Skip to content

feat(CREDENTIALS_IN_URL): flag credentials embedded in the transport URL#42

Open
dmchaledev wants to merge 1 commit into
mainfrom
claude/amazing-franklin-gx0i1r
Open

feat(CREDENTIALS_IN_URL): flag credentials embedded in the transport URL#42
dmchaledev wants to merge 1 commit into
mainfrom
claude/amazing-franklin-gx0i1r

Conversation

@dmchaledev

Copy link
Copy Markdown
Contributor

Summary

A transport/serverUrl of the form scheme://user:password@host embeds long‑lived credentials directly in the connection string. Today the scanner has no rule for this, so such a config scans completely clean:

$ node dist/cli.js creds-url.json --format=table   # transport.url: https://admin:SuperSecret123@mcp.example.com
Found 0 finding(s): 0 critical, 0 high, 0 medium, 0 low
PASSED

That's a false negative on a real, well‑known credential‑exposure vector (CWE‑522 / CWE‑598): credentials in a URL leak through access/proxy logs, browser history, and Referer headers. TLS does not protect them — the exposure happens at the endpoints, not on the wire — so MISSING_TLS/INSECURE_TRANSPORT don't cover it, and the secret‑scanning patterns (sk-…, ghp_…, AKIA…, password=…) don't match a URL userinfo component either.

This gap is independent of the current backlog — no open/closed issue or PR references URL userinfo / embedded credentials. (The EXPOSED_SECRETS PRs all target API‑key/token/password patterns in string values.)

Change

Add a HIGH‑severity CREDENTIALS_IN_URL rule that parses the transport URL with the WHATWG URL API and fires on any non‑empty username (with or without a password).

$ node dist/cli.js creds-url.json --format=table
HIGH | CREDENTIALS_IN_URL | Credentials Embedded in Transport URL
  • Password is redacted in the evidence (transport.url: https://admin:***@mcp.example.com/mcp) — the scanner never echoes the secret it flags.
  • URL‑evaluable: embedded credentials are visible in the URL string itself, so the rule is added to URL_EVALUABLE_RULES and runs in URL mode too — giving that mode its first genuine (non‑transport‑scheme) security finding.
  • The new RuleId is auto‑included in --rule validation and --help (both derive from the enum), so no CLI wiring changes were needed.
  • Unparseable URLs are ignored (no throw, no finding).

Tests

  • Rule‑level: user:password@, bare user@, wss://, serverUrl fallback, evidence redaction, and the clean/absent/unparseable negatives.
  • Integration: URL‑mode scan flags the finding, a clean endpoint does not, and the serialized report contains no plaintext secret.

Full suite: 128 passed. typecheck, lint (--max-warnings 0), and build all clean.

Docs

README "What It Checks" now mentions credentials embedded in the connection URL.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XgH2BbU7WoCekW6n8QxcNE


Generated by Claude Code

An MCP transport/serverUrl of the form `scheme://user:password@host` embeds
long-lived credentials directly in the connection string. Those credentials
leak through access/proxy logs, browser history, and Referer headers — TLS
does not protect them, because the exposure happens at the endpoints, not on
the wire (CWE-522 / CWE-598). Previously such a config scanned completely
clean (0 findings, PASSED), a false negative on a real credential-exposure
vector that none of the existing rules cover.

Add a HIGH-severity `CREDENTIALS_IN_URL` rule that parses the transport URL
with the WHATWG URL API and fires on any non-empty userinfo component. The
password is redacted in the finding evidence so the scanner never echoes the
secret it flags. Because embedded credentials are visible in the URL string
itself, the rule is URL-evaluable and runs in URL mode too — giving that mode
its first genuine security finding.

- New RuleId.CREDENTIALS_IN_URL, auto-included in `--rule` validation and help.
- Added to URL_EVALUABLE_RULES so it runs against a bare endpoint URL.
- Tests: user:pass and bare user@, wss://, serverUrl fallback, redaction,
  unparseable/clean/absent URLs, and URL-mode integration + no-secret-leak.
- README "What It Checks" notes the new detection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XgH2BbU7WoCekW6n8QxcNE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants