Skip to content

feat(auth): flag placeholder & default credentials (PLACEHOLDER_CREDENTIAL)#43

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

feat(auth): flag placeholder & default credentials (PLACEHOLDER_CREDENTIAL)#43
dmchaledev wants to merge 1 commit into
mainfrom
claude/amazing-franklin-sjdz5d

Conversation

@dmchaledev

Copy link
Copy Markdown
Contributor

Summary

Closes a real false-negative on the scanner's core auth checks: a long placeholder or default credential passes the gate today.

NO_AUTH accepts any non-empty apiKey/token as proof that auth is configured, and WEAK_API_KEY only checks length (and exempts JWTs). So a config shipped with an unfilled credential like "your-api-key-here-replace-before-prod" (37 chars, not a JWT) satisfies both and produces zero findings — the gate goes green on a server anyone can authenticate to with a publicly-known value.

Repro (built CLI at current main)

// placeholder.json
{ "transport": { "url": "https://x.example.com", "tls": true,
    "auth": { "type": "apikey", "apiKey": "your-api-key-here-replace-before-prod" } },
  "rateLimit": { "enabled": true } }
$ node dist/cli.js placeholder.json --format=table
Found 0 finding(s): 0 critical, 0 high, 0 medium, 0 low   →  PASSED   # placeholder credential, not flagged

After this change the same config reports a HIGH PLACEHOLDER_CREDENTIAL.

Change

New HIGH PLACEHOLDER_CREDENTIAL rule (src/rules/auth-rules.ts) inspecting transport.auth.apiKey and transport.auth.token for:

  • Unresolved template markers<your-key>, {{API_KEY}}, ${TOKEN}
  • Filler / repeated-character values — e.g. xxxxxxxx, 00000000
  • Known default/weak secretschangeme, password, admin, root, secret, … (matched against the whole normalized value)
  • High-signal placeholder phrasesyour-api-key, replace-me, insert-your-key, placeholder, redacted, … (multi-character substrings only — no bare key/token/test)

Matching is deliberately anchored to keep the false-positive rate near zero:

  • A real random-looking key is not flagged (kZ8f3Qw9Lx2Vt7Rb1Np6Yc4Md0Ha5Ue → clean).
  • A JWT is not flagged — the bundled examples/secure-config.json stays clean and still PASSED.

The matched value is a placeholder/default (not a real secret), so a short slice is safely included in evidence to locate the offending field.

Scope / safety

  • Additive only — no change to existing rules, output schema, or public API. The new RuleId is auto-picked up by the CLI/--rule allowlists and SARIF.
  • Requires a config file, so URL mode is unaffected (it isn't in URL_EVALUABLE_RULES).
  • Complements rather than overlaps WEAK_API_KEY: short placeholders still trip WEAK_API_KEY on length; the gap this closes is long placeholders that pass length.

Tests / verification

  • npx tsc --noEmit ✅ · npm run lint (0 warnings) ✅ · npm test132 passed (was 118) · npm run build
  • Added a PLACEHOLDER_CREDENTIAL suite: the long-placeholder regression (asserts WEAK_API_KEY does not fire on the same value), a parametrized case per detection category, independent apiKey+token flagging, and no-false-positive guards for a random key, a JWT, and an absent credential.
  • CLI smoke-tested: the placeholder config now emits the HIGH finding; examples/secure-config.json remains clean.

Note on backlog overlap

Independent of the open backlog — the three open EXPOSED_SECRETS PRs (#28/#35/#38) concern hardcoded real secrets and their redaction; #26 concerns credential length; #39 concerns the mcpServers stdio schema. None address placeholder/default credentials.

🤖 Generated with Claude Code

https://claude.ai/code/session_013FP2Zbbft758mDMK2Edcbd


Generated by Claude Code

…NTIAL)

A long placeholder or default credential (>= 32 chars, not JWT-shaped)
such as "your-api-key-here-replace-before-prod" satisfied NO_AUTH (a
credential is present) and passed WEAK_API_KEY (length ok), so a config
shipped with an unfilled or default credential went green on the gate.

Add a HIGH PLACEHOLDER_CREDENTIAL rule that inspects transport.auth.apiKey
and transport.auth.token for:
- unresolved template markers (<your-key>, {{API_KEY}}, ${TOKEN})
- filler/repeated-character fillers (xxxxxxxx)
- known default/weak secrets (changeme, password, admin, ...)
- high-signal placeholder phrases (your-api-key, replace-me, ...)

Matching is anchored to the whole normalized value (defaults) or
multi-character high-signal phrases (placeholders) to keep false
positives near zero: real random keys and JWTs are not flagged. Rule
requires a config file, so URL mode is unaffected. Additive only; no
change to existing rules or output schema.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FP2Zbbft758mDMK2Edcbd
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