Skip to content

HARDCODED_SECRET flags <> and [] placeholders outside docs/tests paths #3091

Description

@phwizard

plugin-scanner 3.x flags password: "<password>" and a "[redacted ...]" constant as high severity HARDCODED_SECRET when the file sits outside a docs, tests or examples path.

This is the same shape as #2811, which fixed the ${VAR} case. The < and [ placeholder forms still reach the report.

Cause

_looks_like_placeholder_secret in checks/security.py already recognises both forms:

if _looks_like_interpolated_secret(normalized) or normalized.startswith(("<", "[")):
    return True

But in _should_skip_secret_match it is gated behind the surface test, and the early return fires first:

if not _is_example_surface(relative_path):
    return False                                  # non-docs path stops here
if _looks_like_placeholder_secret(candidate):     # never asked
    return True

_looks_like_interpolated_secret was hoisted above that gate, which is why ${VAR} is now clean; startswith(("<", "[")) was left below it.

Confirmed against the installed package:

$ python -c "from codex_plugin_scanner.checks.security import _looks_like_placeholder_secret as p, _is_example_surface as e; ..."
'<password>'                       -> placeholder? True
'[redacted - call ethora-app-...]' -> placeholder? True
src/tools.ts                       -> example surface? False
src/redact.ts                      -> example surface? False

So the value is correctly identified as a placeholder, and the answer is discarded because of where the file lives.

Repro

Any plugin with a TypeScript source file outside docs/tests:

// src/a.ts
const nextCall = { email: "user@example.com", password: "<password>" }
export const REDACTED_APP_TOKEN = "[redacted - call the reveal tool for appToken]"
plugin-scanner scan .
# HARDCODED_SECRET high: Potential secret material was detected in src/a.ts

Why it matters beyond one repo

fail_on_severity: high in the awesome-ai-plugins catalog gate means any project that writes password: "<password>" in an example payload, or ships a redaction placeholder constant, cannot be listed without rewording correct code. The second case is the awkward one: on our server the flagged line is the placeholder belonging to the module whose only job is stripping credentials out of tool results before they reach a model's context, so the check fires on the fix rather than the problem.

Real-world instance: dappros/ethora-mcp-server scores 85/100 with 0 critical, 0 medium after acting on the other findings (pinning every action to a SHA and adding Dependabot, both fair), and is blocked only by these two.

Suggested fix

Hoist the unambiguous bracketed forms next to the interpolated check, keeping the rest of the placeholder heuristics scoped to example surfaces as they are today:

candidate = _extract_secret_candidate(detector, match)
if _looks_like_interpolated_secret(candidate):
    return True
if _normalize_secret_candidate(candidate).startswith(("<", "[")):
    return True

That stays narrow: <...> and [...] are not shapes a real credential takes, and a value that is genuinely secret would not survive _normalize_secret_candidate starting with either. Happy to send this as a PR with a test if the approach suits you.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions