|
|
@@ -1,14 +1,42 @@
|
|
|
---
|
|
|
description: Security vulnerability scan with a reviewable remediation patch — OWASP, CWE, CVE, secrets, injection
|
|
|
-argument-hint: <system-dir>
|
|
|
+argument-hint: <system-dir> [--show-secrets]
|
|
|
---
|
|
|
|
|
|
-Run a **security hardening pass** on `legacy/$1`: find vulnerabilities, rank
|
|
|
-them, and produce a reviewable patch for the critical ones.
|
|
|
+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:
|
|
|
@@ -20,7 +48,9 @@ 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."
|
|
|
+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
|
|
|
|
|
|
@@ -29,26 +59,50 @@ Write `analysis/$1/SECURITY_FINDINGS.md`:
|
|
|
- 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 all fixes as a single unified diff to
|
|
|
-`analysis/$1/security_remediation.patch`, with a comment line above each
|
|
|
-hunk citing the finding ID it addresses (`# SEC-001: parameterize the query`).
|
|
|
+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 the patch hunk that
|
|
|
-implements it.
|
|
|
+finding ID → one-line summary of the proposed fix and which patch file
|
|
|
+carries the hunk.
|
|
|
|
|
|
## Verify
|
|
|
|
|
|
-Spawn the **security-auditor** again to **review the patch** against the
|
|
|
-original code:
|
|
|
+Spawn the **security-auditor** again to **review both patches** against
|
|
|
+the original code:
|
|
|
|
|
|
-"Review analysis/$1/security_remediation.patch against legacy/$1. For each
|
|
|
+"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? Return one verdict per
|
|
|
-hunk: RESOLVES / PARTIAL / INTRODUCES-RISK, with a one-line reason."
|
|
|
+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.
|
|
|
@@ -57,8 +111,12 @@ If any hunk is PARTIAL or INTRODUCES-RISK, revise the patch and re-review.
|
|
|
|
|
|
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 if appropriate
|
|
|
- with `git -C legacy/$1 apply ../../analysis/$1/security_remediation.patch`
|
|
|
+- `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`
|