feat(security-guidance): secret detection slice (#398, child of #390)#404
Merged
Conversation
First shippable slice of the security code-review plugin: detect hardcoded
credentials in write_file / patch / skill_manage content.
- New Hermes-side module plugins/security-guidance/secrets.py (kept out of
patterns.py, which is byte-for-byte the Anthropic fork):
* regex rules for well-known formats — AWS access key, AWS secret,
GitHub token + fine-grained PAT, Slack token + webhook, Google API
key, Stripe live key, npm token, PEM private key, JWT, generic
api-key/secret assignments.
* conservative Shannon-entropy backstop: a high-entropy value assigned
to a secret-named key, fired only when no known-format rule matched
(no duplicate warnings).
* placeholder/example exclusion (example/redacted/your-/xxxx/<...>/...)
to keep the false-positive rate low.
- Wired into _scan_args so findings flow through the existing warn-mode
(transform_tool_result) and block-mode (pre_tool_call, env
SECURITY_GUIDANCE_BLOCK) paths with no special handling.
Out of scope for this slice (tracked in parent #390): injection-pattern
detectors, pre-commit diff-review mode, static-analyzer integration.
Tests: tests/plugins/test_security_guidance_secrets.py — 22 tests
(AWS/SSH-PEM/Slack/GitHub/Google/Stripe/npm/JWT/generic detection,
entropy backstop, false-positive sanity, warn+block hook integration).
Token fixtures assembled from parts so secret scanners don't match the
test file. Full plugin suite: 49 passed.
Contributor
🔎 Lint report:
|
| Rule | Count |
|---|---|
unresolved-attribute |
2 |
invalid-argument-type |
1 |
unresolved-import |
1 |
First entries
tests/plugins/test_security_guidance_secrets.py:55: [unresolved-attribute] unresolved-attribute: Attribute `exec_module` is not defined on `None` in union `Loader | None`
tests/plugins/test_security_guidance_secrets.py:51: [invalid-argument-type] invalid-argument-type: Argument to function `module_from_spec` is incorrect: Expected `ModuleSpec`, found `ModuleSpec | None`
tests/plugins/test_security_guidance_secrets.py:21: [unresolved-import] unresolved-import: Cannot resolve imported module `pytest`
tests/plugins/test_security_guidance_secrets.py:55: [unresolved-attribute] unresolved-attribute: Attribute `loader` is not defined on `None` in union `ModuleSpec | None`
✅ Fixed issues: none
Unchanged: 5942 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
…sion for prefix rules (#398) - Split placeholder exclusion: fixed-prefix rules (AKIA/ghp_/etc) now use EXAMPLE-only exclusion so a real key containing 'xxxx'/'00000000' as a substring is never silently dropped (fail-open fix, review nit #1). Assignment-style rule keeps the broad placeholder set. - Docstring notes the conservative entropy threshold won't catch low-entropy passphrases (nit #3); Stripe live-only comment (nit #2); _MAX_SCAN_BYTES cross-ref to __init__.py (nit #4). - Add regression test: prefix key with '00000000' substring still detected.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #398
Advances #390 (parent — first slice).
What
First shippable slice of the security code-review plugin: detect hardcoded credentials in
write_file/patch/skill_managecontent, surfacing a warning (or blocking, in block mode) before the model moves on.Files
plugins/security-guidance/secrets.py(new, Hermes-side) — kept OUT ofpatterns.py, which is byte-for-byte the Anthropic fork (provenance preserved) and has aRuleId-sync assert.example/redacted/your-/xxxx/<...>/…) for a low false-positive rate.__init__.py—from . import secrets; one line in_scan_argsso findings flow through the existing warn-mode (transform_tool_result) and block-mode (pre_tool_call) paths.Out of scope (tracked in parent #390)
Injection-pattern detectors (SQL/command/path/SSRF), pre-commit diff-review mode, static-analyzer integration.
Tests
tests/plugins/test_security_guidance_secrets.py— 22 tests: AWS / SSH-PEM / Slack / GitHub / Google / Stripe / npm / JWT / generic detection, entropy backstop (+ low-entropy & known-format suppression), false-positive sanity (benign code, placeholders, examples, oversized input), and warn+block hook integration. Token fixtures are assembled from parts so neither GitGuardian nor the repo's secret scanners match the test file. Full plugin suite: 49 passed.Success criteria (#398)
patterns-adjacent modulewrite_file/patch/skill_managescan pathSECURITY_GUIDANCE_BLOCK