mirror of
https://github.com/anthropics/claude-plugins-official.git
synced 2026-06-14 14:46:03 -03:00
A red-team pass found four ways credential values still reached shareable artifacts after the initial redaction: - the remediation patch: a diff removing a hardcoded secret carries the raw value on its '-' lines by construction. harden now splits output: non-credential hunks in the shareable security_remediation.patch, credential hunks in a gitignored security_remediation.local.patch with comment-only placeholders in the shareable file - the other four agents had no secret-handling rules. legacy-analyst (hardcoded-config evidence in tech-debt findings), business-rules-extractor (credentials recorded as rule parameters), test-engineer (legacy literals becoming committed test fixtures), and architecture-critic (quoted code in notes files) now all mask values and cite file:line; assess's tech-debt prompt and ASSESSMENT.md masking now cover every section, not just Security Findings - non-git projects: a .gitignore protects nothing under SVN/Mercurial. Both commands now refuse --show-secrets without git and write the quarantine file to ~/.modernize/<system>/ outside the project tree - the patch-apply instruction was wrong in both documented layouts (symlinked legacy/ broke relative paths). Patches are now written with project-root-relative paths and applied from the project root Also: --show-secrets is now position-independent in both commands, and the README documents the full model.
123 lines
5.6 KiB
Markdown
123 lines
5.6 KiB
Markdown
---
|
||
description: Security vulnerability scan with a reviewable remediation patch — OWASP, CWE, CVE, secrets, injection
|
||
argument-hint: <system-dir> [--show-secrets]
|
||
---
|
||
|
||
Run a **security hardening pass** on the legacy system: find
|
||
vulnerabilities, rank them, and produce a reviewable patch for the
|
||
critical ones. Parse arguments flag-independently: the system dir
|
||
(referred to as `$1` below) is the first non-flag token in `$ARGUMENTS`;
|
||
`--show-secrets` may appear anywhere.
|
||
|
||
This command never edits `legacy/` — it writes findings and a proposed patch
|
||
to `analysis/$1/`. The user reviews and applies (or not).
|
||
|
||
## Step 0 — Secrets quarantine setup
|
||
|
||
Findings files get shared, committed, and pasted into decks — discovered
|
||
credential values must never land in them. Before any scanning:
|
||
|
||
1. Ensure `analysis/.gitignore` exists and contains the lines
|
||
`SECRETS.local.md` and `*.local.patch`. Create the file or append the
|
||
missing lines.
|
||
2. If the project is a git repo, verify with
|
||
`git check-ignore -q analysis/$1/SECRETS.local.md` — if that exits
|
||
non-zero, fix the ignore rule before proceeding. Do not write any
|
||
findings until this check passes.
|
||
3. **If there is no git repo** (check for `.svn`/`.hg`/`CVS` too — a
|
||
`.gitignore` protects nothing under another VCS): refuse
|
||
`--show-secrets`, and write `SECRETS.local.md` and any `.local.patch`
|
||
file to `~/.modernize/$1/` instead of the project tree, telling the
|
||
user where they went and why.
|
||
|
||
All secret values in every shareable artifact this command produces are
|
||
**masked** (`AKIA****`, `password=****`) and cited by `file:line`. Raw
|
||
values may appear in exactly two places, both gitignored: the
|
||
`*.local.patch` remediation hunks (unavoidably — see Remediate) and, only
|
||
with `--show-secrets`, `SECRETS.local.md`. Never in SECURITY_FINDINGS.md
|
||
or patch commentary.
|
||
|
||
## Scan
|
||
|
||
Spawn the **security-auditor** subagent:
|
||
|
||
"Adversarially audit legacy/$1 for security vulnerabilities. Cover what's
|
||
relevant to the stack: injection (SQL/NoSQL/OS command/template), broken
|
||
auth, sensitive data exposure, access control gaps, insecure deserialization,
|
||
hardcoded secrets, vulnerable dependency versions, missing input validation,
|
||
path traversal. For each finding return: CWE ID, severity
|
||
(Critical/High/Med/Low), file:line, one-sentence exploit scenario, and
|
||
recommended fix. Run any available SAST tooling (npm audit, pip-audit,
|
||
OWASP dependency-check) and include its raw output. Mask every discovered
|
||
credential value per your secret-handling rules — file:line plus a 2–4
|
||
character masked preview, never the value itself."
|
||
|
||
## Triage
|
||
|
||
Write `analysis/$1/SECURITY_FINDINGS.md`:
|
||
- Summary scorecard (count by severity, top CWE categories)
|
||
- Findings table sorted by severity
|
||
- Dependency CVE table (package, installed version, CVE, fixed version)
|
||
|
||
If any hardcoded credentials were found, also write
|
||
`analysis/$1/SECRETS.local.md` (the gitignored quarantine file from Step 0):
|
||
one row per credential — masked preview, `file:line`, credential type, what
|
||
it appears to grant access to, production/test guess, and a rotation
|
||
recommendation. With `--show-secrets`, append the raw value column here —
|
||
this file only. SECURITY_FINDINGS.md gets a one-line pointer:
|
||
"N hardcoded credentials found — inventory in SECRETS.local.md (gitignored;
|
||
not for sharing)."
|
||
|
||
## Remediate
|
||
|
||
For each **Critical** and **High** finding, draft a minimal, targeted fix.
|
||
Do **not** edit `legacy/` — write fixes as unified diffs with **paths
|
||
relative to the project root** (`legacy/$1/...`), applied from the project
|
||
root, with a comment line above each hunk citing the finding ID it
|
||
addresses (`# SEC-001: parameterize the query`).
|
||
|
||
**Credential findings split into two files.** A diff that removes a
|
||
hardcoded secret necessarily contains the raw value on its `-` and
|
||
context lines — that cannot go in the shareable patch:
|
||
|
||
- `analysis/$1/security_remediation.patch` (shareable) — every
|
||
non-credential hunk, plus for each credential finding a comment-only
|
||
placeholder: `# SEC-NNN: credential remediation — hunk in
|
||
security_remediation.local.patch (gitignored; not for sharing)`.
|
||
- `analysis/$1/security_remediation.local.patch` (gitignored in Step 0) —
|
||
the real, applyable hunks for credential findings only.
|
||
|
||
Add a **Remediation Log** section to SECURITY_FINDINGS.md mapping each
|
||
finding ID → one-line summary of the proposed fix and which patch file
|
||
carries the hunk.
|
||
|
||
## Verify
|
||
|
||
Spawn the **security-auditor** again to **review both patches** against
|
||
the original code:
|
||
|
||
"Review analysis/$1/security_remediation.patch and
|
||
analysis/$1/security_remediation.local.patch against legacy/$1. For each
|
||
hunk: does it fully remediate the cited finding? Does it introduce new
|
||
vulnerabilities or change behavior beyond the fix? Confirm no raw
|
||
credential values appear anywhere in the shareable patch. Return one
|
||
verdict per hunk: RESOLVES / PARTIAL / INTRODUCES-RISK, with a one-line
|
||
reason."
|
||
|
||
Add a **Patch Review** section to SECURITY_FINDINGS.md with the verdicts.
|
||
If any hunk is PARTIAL or INTRODUCES-RISK, revise the patch and re-review.
|
||
|
||
## Present
|
||
|
||
Tell the user the artifacts are ready:
|
||
- `analysis/$1/SECURITY_FINDINGS.md` — findings, remediation log, patch review
|
||
- `analysis/$1/security_remediation.patch` — review, then apply **from the
|
||
project root**: `git apply analysis/$1/security_remediation.patch`
|
||
(if `legacy/$1` is a symlink, use `git apply --unsafe-paths` or apply
|
||
with `patch -p0` from the project root)
|
||
- `analysis/$1/security_remediation.local.patch` — the credential fixes;
|
||
apply the same way, and rotate the affected credentials regardless
|
||
- Re-run `/modernize-harden $1` after applying to confirm resolution
|
||
|
||
Suggest: `glow -p analysis/$1/SECURITY_FINDINGS.md`
|