Skip to content

feat(EXPOSED_SECRETS): detect common real-world credential formats#37

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

feat(EXPOSED_SECRETS): detect common real-world credential formats#37
dmchaledev wants to merge 1 commit into
mainfrom
claude/amazing-franklin-jall53

Conversation

@dmchaledev

Copy link
Copy Markdown
Contributor

Problem

The EXPOSED_SECRETS rule (CRITICAL — the scanner's headline "Potential Secret Exposed" check) only matched a thin set of vendor prefixes: OpenAI sk-, GitHub ghp_, AWS AKIA, plus an inline password= assignment. Several credential formats that routinely appear in real MCP configs slipped through entirely, so a config carrying them produced 0 findings and PASSED.

Verified against main (built CLI) — this config scans clean today:

{
  "transport": { "url": "https://x.example.com", "tls": true,
    "auth": { "type": "bearer", "token": "sk-ant-api03-…" } },   // Anthropic key
  "rateLimit": { "enabled": true },
  "tools": [
    { "name": "db",    "description": "postgres://admin:SuperSecret123@db.internal:5432/app" },
    { "name": "slack", "description": "xoxb-…" },
    { "name": "gcp",   "description": "AIzaSy…" }
  ]
}
$ node dist/cli.js config.json --format=table
Found 0 finding(s)  →  PASSED        # 4 hardcoded secrets, none detected

For a tool sold as a CI/CD secret-detection gate, missing an Anthropic key, a Slack/Google/Stripe token, a PEM private key, or credentials embedded in a connection-string URL is a meaningful false negative.

Changes

Localized to src/rules/runtime-rules.ts + tests — no new dependencies:

  • Add patterns for Anthropic (sk-ant-), OpenAI project keys (sk-proj-), GitHub fine-grained PATs (github_pat_), Google API keys (AIza…), Slack tokens (xox[baprs]-), Stripe live keys ([sr]k_live_), PEM private-key blocks, and credentials embedded in connection-string URLs (scheme://user:pass@host).
  • Fix the AWS pattern — removed the erroneous case-insensitive flag (AKIA IDs are strictly uppercase; /i would flag any lowercase akia… substring).
  • Name the matched credential type in the finding's description and evidence so users know what was found.
  • Redact matched values (short prefix + length) so the scanner never echoes a full secret into logs or uploaded SARIF.

The same config now correctly fails:

CRITICAL | EXPOSED_SECRETS | Potential Secret Exposed in Configuration
# description: "…4 hardcoded secret(s) (Anthropic API key, Credentials in URL, Slack token, Google API key)…"

False-positive guardrails

Patterns are anchored on distinctive prefixes/structures, so:

  • A high-entropy opaque token without a known prefix stays clean.
  • A plain URL without userinfo (https://api.example.com, wss://…) does not match the connection-string pattern.
  • The JWT-style bearer token in examples/secure-config.json stays clean — secure-config.json still PASSES and vulnerable-config.json is unchanged (no new findings).

Tests

+15 cases covering each new credential format, the redaction behavior, the multi-secret summary, and the no-false-positive guards. Full suite: 133 passing (was 118). lint and typecheck clean.

Note: a couple of sample tokens in the tests are assembled from string fragments at runtime, so no full token literal sits in source — otherwise GitHub push protection (rightly) blocks the commit.

🤖 Generated with Claude Code


Generated by Claude Code

The EXPOSED_SECRETS rule (CRITICAL) only matched a thin set of vendor
prefixes (OpenAI `sk-`, GitHub `ghp_`, AWS `AKIA`) plus an inline
`password=` assignment. As a result, a config carrying an Anthropic key,
a Slack/Google/Stripe token, a PEM private key, or a connection string
with embedded credentials (`postgres://user:pass@host`) produced zero
findings and PASSED — a false negative on the tool's headline secret check.

Changes (localized to runtime-rules.ts + tests, no new dependencies):
- Add patterns for Anthropic (`sk-ant-`), OpenAI project keys (`sk-proj-`),
  GitHub fine-grained PATs (`github_pat_`), Google API keys (`AIza…`),
  Slack tokens (`xox[baprs]-`), Stripe live keys (`[sr]k_live_`), PEM
  private-key blocks, and credentials embedded in connection-string URLs.
- Remove the erroneous case-insensitive flag on the AWS pattern (access
  key IDs are strictly uppercase; `/i` flagged any lowercase "akia…").
- Name the matched credential type in the finding's description/evidence.
- Redact matched values (short prefix + length) so the scanner never
  echoes a full secret into logs or uploaded SARIF.

Patterns are anchored on distinctive prefixes/structures, so a
high-entropy opaque token without a known prefix and the JWT-style token
in examples/secure-config.json stay clean (no false positives).

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