Requirements: Review-Security Integration
Feature: Consolidate security into a unified engine and integrate as Stage 3 of /z:review
Status: APPROVED
Created: 2026-02-15
Author: ZERG Plan (Socratic mode, 3 rounds)
1. Problem Statement
Security logic is scattered across three locations with overlap and gaps:
zerg/security.py — 27 secret patterns, sensitive files, large files, symlink escapes
zerg/security.py:HOOK_PATTERNS — shell injection, code injection, unsafe deserialization (defined but never called)
zerg/commands/review.py:CodeAnalyzer — duplicate hardcoded_secret pattern (weaker version)
Meanwhile, /z:security slash command describes OWASP presets, CVE scanning, injection/XSS analysis, and compliance frameworks — but these exist only as Claude-directed behaviors, not as Python functions callable by the CLI.
Result: zerg review CLI provides shallow security checks. The slash command promises deep security but the programmatic path can't deliver it.
2. Goals
- Consolidate all security logic into a single
zerg/security/ package — zero duplication
- Deepen security scanning with 10 new capability areas
- Integrate security as always-on Stage 3 in
/z:review (both slash command and CLI)
- Reuse —
/z:security and /z:review call the same engine. No parallel implementations
- Document the integration across all touchpoints: command files, docs, website, wiki
3. Non-Goals
- Replacing external security tools (Snyk, Semgrep, Trivy) — ZERG supplements, doesn't replace
- Real-time monitoring or runtime security — this is static analysis only
- Modifying the
/z:rush or /z:worker pipelines (future scope)
4. Functional Requirements
FR-1: Consolidated Security Package
Promote zerg/security.py and zerg/security_rules.py into a zerg/security/ package:
zerg/security/
__init__.py # Public API: run_security_scan(), SecurityResult
scanner.py # Main scanning engine (consolidates all patterns)
patterns.py # All detection patterns (secrets, injection, crypto, etc.)
rules.py # Stack detection, rule fetching, filtering (from security_rules.py)
cve.py # Dependency CVE scanning with API + heuristic fallback
hooks.py # Git hook installation/management (from security.py)
- All existing callers must be updated to import from
zerg.security (package)
- HOOK_PATTERNS security patterns must be incorporated into the scanner, not just defined
- CodeAnalyzer.hardcoded_secret pattern in
review.py must be removed — defer to security engine
run_security_scan() returns a SecurityResult dataclass with structured findings
FR-2: Deep Security Scanning Engine
The consolidated scanner must implement these capability areas:
| # |
Capability |
Description |
Implementation |
| 1 |
Secret detection |
API keys, tokens, credentials, private keys |
Existing 27 patterns + HOOK_PATTERNS |
| 2 |
Injection detection |
Shell injection, code injection (eval/exec), SQL injection patterns |
From HOOK_PATTERNS + new patterns |
| 3 |
Deserialization risks |
Unsafe deserialization, unsafe YAML, insecure data loading |
From HOOK_PATTERNS + new patterns |
| 4 |
Cryptographic misuse |
MD5/SHA1 for passwords, hardcoded IVs/salts, weak algorithms |
New patterns |
| 5 |
Error handling audit |
Bare except, fail-open patterns, stack trace leakage in responses |
New patterns |
| 6 |
Input validation gaps |
Unvalidated user input flowing to dangerous sinks |
New patterns |
| 7 |
Dependency CVE scanning |
Check deps against known vulnerabilities |
External API (osv.dev) + heuristic fallback |
| 8 |
Lockfile integrity |
Verify lockfile exists, hashes present, no unpinned deps |
Heuristic checks |
| 9 |
License compliance |
Detect GPL/AGPL deps that could affect commercial use |
Pattern-based detection |
| 10 |
Git history scanning |
Secrets in past commits (not just current files) |
git log analysis |
| 11 |
Sensitive file detection |
.env, credentials.json, private keys in repo |
Existing (from security.py) |
| 12 |
File permission checks |
World-writable files, overly permissive configs |
New checks |
| 13 |
Environment variable leakage |
Logging/printing env vars containing secrets |
New patterns |
| 14 |
Dockerfile security |
Running as root, no USER directive, privileged mode |
Leverages existing .claude/rules/security/containers/ |
| 15 |
Symlink escape detection |
Path traversal via symlinks |
Existing (from security.py) |
FR-3: SecurityResult Dataclass
@dataclass
class SecurityFinding:
category: str # e.g., "secret", "injection", "crypto"
severity: str # "critical", "high", "medium", "low", "info"
file: str
line: int
message: str
cwe: str | None # e.g., "CWE-798"
remediation: str # How to fix
pattern_name: str # Which pattern matched
@dataclass
class SecurityResult:
findings: list[SecurityFinding]
categories_scanned: list[str]
files_scanned: int
scan_duration_seconds: float
passed: bool # True if no critical/high findings
summary: dict[str, int] # severity -> count
FR-4: Review Integration — Stage 3
Slash command (review.md):
- Review becomes 3-stage: Spec -> Quality -> Security
- Stage 3 invokes the same logic as
/z:security
- Security findings appear in the review report
- Always-on by default
CLI (review.py):
ReviewCommand.run() calls zerg.security.run_security_scan()
ReviewResult gains security_passed: bool and security_result: SecurityResult
overall_passed requires all 3 stages to pass
- Rich table output adds row:
Stage 3 (Security): check/cross
- Security findings displayed by severity below the table
FR-5: --no-security Flag
- Available on both slash command and CLI
- Default: security ON
- When used: prints warning
"WARNING: Security scan skipped. Use with caution."
- Review output shows
Stage 3 (Security): SKIPPED in table
FR-6: CVE Scanning with Fallback
- Try external API first: Query osv.dev API with dependency list
- Fallback to heuristics: If offline or API fails, use pattern-based checks:
- Unpinned versions (
>=, *, no version specifier)
- Missing lockfiles (requirements.txt without .lock, package.json without lockfile)
- Known-bad version ranges from hardcoded database
- Supported ecosystems: Python (pip), Node.js (npm), Rust (cargo), Go (go.mod)
FR-7: Shared Engine — No Duplication
/z:security slash command and /z:review Stage 3 use the same run_security_scan()
security_rules_cmd.py CLI uses the same package for rule management
review.py:CodeAnalyzer removes its hardcoded_secret pattern
- Single source of truth:
zerg/security/patterns.py
5. Non-Functional Requirements
NFR-1: Performance
- Full security scan of 50 files completes in < 5 seconds (excluding CVE API calls)
- CVE API calls have 5-second timeout with graceful fallback
NFR-2: Extensibility
- New patterns can be added to
patterns.py without modifying scanner logic
- Pattern registry pattern: each category registers its patterns declaratively
NFR-3: Context Engineering Compatibility
- Package structure enables task-scoped context (workers load only needed submodules)
- Follows ZERG command splitting philosophy (if review.md grows > 300 lines, split to core/details)
NFR-4: Test Coverage
- Unit tests for each capability area in
tests/unit/test_security_engine.py
- Integration tests for review + security pipeline in
tests/integration/
- Existing
test_review_cmd.py updated to cover Stage 3
- Existing
test_security.py migrated to new package structure
6. Acceptance Criteria
7. Files to Create
| File |
Purpose |
zerg/security/__init__.py |
Public API surface |
zerg/security/scanner.py |
Main scanning engine |
zerg/security/patterns.py |
All detection patterns |
zerg/security/rules.py |
Migrated from zerg/security_rules.py |
zerg/security/cve.py |
CVE scanning with fallback |
zerg/security/hooks.py |
Git hook management (migrated) |
tests/unit/test_security_engine.py |
New consolidated tests |
tests/integration/test_review_security.py |
Integration tests |
docs/wiki/Security-Philosophy.md |
New wiki page |
8. Files to Modify
| File |
Change |
zerg/commands/review.py |
Add Stage 3, import security engine, extend ReviewResult, remove hardcoded_secret from CodeAnalyzer |
zerg/commands/security_rules_cmd.py |
Update imports to zerg.security.rules |
zerg/commands/__init__.py |
Update imports if needed |
zerg/cli.py |
No change expected (review and security-rules already registered) |
zerg/data/commands/review.md |
Add Stage 3 security, --no-security flag, 3-stage output |
zerg/data/commands/security.md |
Reference shared engine, note review integration |
docs/commands-quick.md |
Update review entry (3-stage), add --no-security flag |
docs/commands-deep.md |
Update review section (3-stage diagram), update security section |
docs/index.html |
Update review description, add security philosophy narrative |
tests/unit/test_review_cmd.py |
Add Stage 3 tests, update ReviewResult assertions |
tests/unit/test_security.py |
Migrate to new package imports |
9. Files to Delete
| File |
Reason |
zerg/security.py |
Migrated to zerg/security/ package |
zerg/security_rules.py |
Migrated to zerg/security/rules.py |
10. Migration Plan
- Create
zerg/security/ package with all modules
- Migrate
security.py functions to scanner.py, patterns.py, hooks.py
- Migrate
security_rules.py to rules.py
- Update all callers (
review.py, security_rules_cmd.py, any others)
- Add new capabilities to
scanner.py + patterns.py
- Create
cve.py with API + fallback
- Integrate into
review.py as Stage 3
- Update slash commands (
review.md, security.md)
- Update docs and website
- Delete old files
- Run full test suite
11. Documentation Impact Analysis
| Document |
Section |
Change |
zerg/data/commands/review.md |
Modes/Output/Help |
Add Stage 3, --no-security flag |
zerg/data/commands/security.md |
Capabilities |
Reference shared engine |
docs/commands-quick.md |
/zerg:review row |
Add --no-security flag |
docs/commands-deep.md |
/zerg:review section |
New 3-stage diagram, security stage details |
docs/commands-deep.md |
/zerg:security section |
Note shared engine with review |
docs/index.html |
Command table + hero/features |
Update review desc, add security narrative |
docs/wiki/Security-Philosophy.md |
New page |
Security-as-core-value philosophy |
CHANGELOG.md |
[Unreleased] |
Feature entry |
12. Risk Assessment
| Risk |
Probability |
Impact |
Mitigation |
| Import breakage from package migration |
Medium |
High |
Grep all imports before migration, update atomically |
| CVE API rate limiting |
Low |
Low |
Graceful fallback to heuristics |
| False positives from new patterns |
Medium |
Medium |
Start with high-confidence patterns, tune iteratively |
| Performance regression from deep scan |
Low |
Medium |
Benchmark 50-file scan, set 5s budget |
| Scope creep from 15 capabilities |
Medium |
High |
Implement in priority order, each independently testable |
13. Open Questions (RESOLVED)
- osv.dev vs pip-audit: osv.dev API first, then shell out to
pip-audit/npm audit as secondary source. Both, layered.
- Git history depth: Configurable. Default: last 100 commits. Document the default clearly in help text and docs.
- License database: Library integration (not hardcoded allowlist). Use a proper license detection library.
- Severity thresholds:
--no-security is never blocked, but critical findings trigger prominent red warnings prompting the user to reconsider. The scan still skips — the user has final say.
Generated by /zerg:plan --socratic (3 rounds)
1---2name: 1545-requirements-a8e9f3813description: Requirements: Review-Security Integration4---5# Requirements: Review-Security Integration67**Feature**: Consolidate security into a unified engine and integrate as Stage 3 of `/z:review`8**Status**: APPROVED9**Created**: 2026-02-1510**Author**: ZERG Plan (Socratic mode, 3 rounds)1112---1314## 1. Problem Statement1516Security logic is scattered across three locations with overlap and gaps:17- `zerg/security.py` — 27 secret patterns, sensitive files, large files, symlink escapes18- `zerg/security.py:HOOK_PATTERNS` — shell injection, code injection, unsafe deserialization (defined but **never called**)19- `zerg/commands/review.py:CodeAnalyzer` — duplicate hardcoded_secret pattern (weaker version)2021Meanwhile, `/z:security` slash command *describes* OWASP presets, CVE scanning, injection/XSS analysis, and compliance frameworks — but these exist only as Claude-directed behaviors, not as Python functions callable by the CLI.2223Result: `zerg review` CLI provides shallow security checks. The slash command promises deep security but the programmatic path can't deliver it.2425## 2. Goals26271. **Consolidate** all security logic into a single `zerg/security/` package — zero duplication282. **Deepen** security scanning with 10 new capability areas293. **Integrate** security as always-on Stage 3 in `/z:review` (both slash command and CLI)304. **Reuse** — `/z:security` and `/z:review` call the same engine. No parallel implementations315. **Document** the integration across all touchpoints: command files, docs, website, wiki3233## 3. Non-Goals3435- Replacing external security tools (Snyk, Semgrep, Trivy) — ZERG supplements, doesn't replace36- Real-time monitoring or runtime security — this is static analysis only37- Modifying the `/z:rush` or `/z:worker` pipelines (future scope)3839## 4. Functional Requirements4041### FR-1: Consolidated Security Package4243Promote `zerg/security.py` and `zerg/security_rules.py` into a `zerg/security/` package:4445```46zerg/security/47 __init__.py # Public API: run_security_scan(), SecurityResult48 scanner.py # Main scanning engine (consolidates all patterns)49 patterns.py # All detection patterns (secrets, injection, crypto, etc.)50 rules.py # Stack detection, rule fetching, filtering (from security_rules.py)51 cve.py # Dependency CVE scanning with API + heuristic fallback52 hooks.py # Git hook installation/management (from security.py)53```5455- **All existing callers** must be updated to import from `zerg.security` (package)56- **HOOK_PATTERNS** security patterns must be incorporated into the scanner, not just defined57- **CodeAnalyzer.hardcoded_secret** pattern in `review.py` must be removed — defer to security engine58- `run_security_scan()` returns a `SecurityResult` dataclass with structured findings5960### FR-2: Deep Security Scanning Engine6162The consolidated scanner must implement these capability areas:6364| # | Capability | Description | Implementation |65|---|-----------|-------------|----------------|66| 1 | Secret detection | API keys, tokens, credentials, private keys | Existing 27 patterns + HOOK_PATTERNS |67| 2 | Injection detection | Shell injection, code injection (eval/exec), SQL injection patterns | From HOOK_PATTERNS + new patterns |68| 3 | Deserialization risks | Unsafe deserialization, unsafe YAML, insecure data loading | From HOOK_PATTERNS + new patterns |69| 4 | Cryptographic misuse | MD5/SHA1 for passwords, hardcoded IVs/salts, weak algorithms | New patterns |70| 5 | Error handling audit | Bare except, fail-open patterns, stack trace leakage in responses | New patterns |71| 6 | Input validation gaps | Unvalidated user input flowing to dangerous sinks | New patterns |72| 7 | Dependency CVE scanning | Check deps against known vulnerabilities | External API (osv.dev) + heuristic fallback |73| 8 | Lockfile integrity | Verify lockfile exists, hashes present, no unpinned deps | Heuristic checks |74| 9 | License compliance | Detect GPL/AGPL deps that could affect commercial use | Pattern-based detection |75| 10 | Git history scanning | Secrets in past commits (not just current files) | `git log` analysis |76| 11 | Sensitive file detection | .env, credentials.json, private keys in repo | Existing (from security.py) |77| 12 | File permission checks | World-writable files, overly permissive configs | New checks |78| 13 | Environment variable leakage | Logging/printing env vars containing secrets | New patterns |79| 14 | Dockerfile security | Running as root, no USER directive, privileged mode | Leverages existing `.claude/rules/security/containers/` |80| 15 | Symlink escape detection | Path traversal via symlinks | Existing (from security.py) |8182### FR-3: SecurityResult Dataclass8384```python85@dataclass86class SecurityFinding:87 category: str # e.g., "secret", "injection", "crypto"88 severity: str # "critical", "high", "medium", "low", "info"89 file: str90 line: int91 message: str92 cwe: str | None # e.g., "CWE-798"93 remediation: str # How to fix94 pattern_name: str # Which pattern matched9596@dataclass97class SecurityResult:98 findings: list[SecurityFinding]99 categories_scanned: list[str]100 files_scanned: int101 scan_duration_seconds: float102 passed: bool # True if no critical/high findings103 summary: dict[str, int] # severity -> count104```105106### FR-4: Review Integration — Stage 3107108**Slash command** (`review.md`):109- Review becomes 3-stage: Spec -> Quality -> Security110- Stage 3 invokes the same logic as `/z:security`111- Security findings appear in the review report112- Always-on by default113114**CLI** (`review.py`):115- `ReviewCommand.run()` calls `zerg.security.run_security_scan()`116- `ReviewResult` gains `security_passed: bool` and `security_result: SecurityResult`117- `overall_passed` requires all 3 stages to pass118- Rich table output adds row: `Stage 3 (Security): check/cross`119- Security findings displayed by severity below the table120121### FR-5: --no-security Flag122123- Available on both slash command and CLI124- Default: security ON125- When used: prints warning `"WARNING: Security scan skipped. Use with caution."`126- Review output shows `Stage 3 (Security): SKIPPED` in table127128### FR-6: CVE Scanning with Fallback1291301. **Try external API first**: Query osv.dev API with dependency list1312. **Fallback to heuristics**: If offline or API fails, use pattern-based checks:132 - Unpinned versions (`>=`, `*`, no version specifier)133 - Missing lockfiles (requirements.txt without .lock, package.json without lockfile)134 - Known-bad version ranges from hardcoded database1353. **Supported ecosystems**: Python (pip), Node.js (npm), Rust (cargo), Go (go.mod)136137### FR-7: Shared Engine — No Duplication138139- `/z:security` slash command and `/z:review` Stage 3 use the same `run_security_scan()`140- `security_rules_cmd.py` CLI uses the same package for rule management141- `review.py:CodeAnalyzer` removes its `hardcoded_secret` pattern142- Single source of truth: `zerg/security/patterns.py`143144## 5. Non-Functional Requirements145146### NFR-1: Performance147- Full security scan of 50 files completes in < 5 seconds (excluding CVE API calls)148- CVE API calls have 5-second timeout with graceful fallback149150### NFR-2: Extensibility151- New patterns can be added to `patterns.py` without modifying scanner logic152- Pattern registry pattern: each category registers its patterns declaratively153154### NFR-3: Context Engineering Compatibility155- Package structure enables task-scoped context (workers load only needed submodules)156- Follows ZERG command splitting philosophy (if review.md grows > 300 lines, split to core/details)157158### NFR-4: Test Coverage159- Unit tests for each capability area in `tests/unit/test_security_engine.py`160- Integration tests for review + security pipeline in `tests/integration/`161- Existing `test_review_cmd.py` updated to cover Stage 3162- Existing `test_security.py` migrated to new package structure163164## 6. Acceptance Criteria165166- [ ] `zerg review` CLI output shows 3-stage table (Spec, Quality, Security)167- [ ] `zerg review --no-security` skips Stage 3 with warning168- [ ] `/z:review` slash command describes 3-stage process with security169- [ ] `/z:security` and `/z:review` both call `zerg.security.run_security_scan()`170- [ ] All 15 capability areas have at least one detection pattern171- [ ] CVE scanning attempts API, falls back to heuristics172- [ ] No duplicate security patterns exist across codebase173- [ ] `CodeAnalyzer` in review.py no longer checks for secrets174- [ ] All existing tests pass after migration175- [ ] New tests cover consolidated security engine176177## 7. Files to Create178179| File | Purpose |180|------|---------|181| `zerg/security/__init__.py` | Public API surface |182| `zerg/security/scanner.py` | Main scanning engine |183| `zerg/security/patterns.py` | All detection patterns |184| `zerg/security/rules.py` | Migrated from `zerg/security_rules.py` |185| `zerg/security/cve.py` | CVE scanning with fallback |186| `zerg/security/hooks.py` | Git hook management (migrated) |187| `tests/unit/test_security_engine.py` | New consolidated tests |188| `tests/integration/test_review_security.py` | Integration tests |189| `docs/wiki/Security-Philosophy.md` | New wiki page |190191## 8. Files to Modify192193| File | Change |194|------|--------|195| `zerg/commands/review.py` | Add Stage 3, import security engine, extend ReviewResult, remove hardcoded_secret from CodeAnalyzer |196| `zerg/commands/security_rules_cmd.py` | Update imports to `zerg.security.rules` |197| `zerg/commands/__init__.py` | Update imports if needed |198| `zerg/cli.py` | No change expected (review and security-rules already registered) |199| `zerg/data/commands/review.md` | Add Stage 3 security, --no-security flag, 3-stage output |200| `zerg/data/commands/security.md` | Reference shared engine, note review integration |201| `docs/commands-quick.md` | Update review entry (3-stage), add --no-security flag |202| `docs/commands-deep.md` | Update review section (3-stage diagram), update security section |203| `docs/index.html` | Update review description, add security philosophy narrative |204| `tests/unit/test_review_cmd.py` | Add Stage 3 tests, update ReviewResult assertions |205| `tests/unit/test_security.py` | Migrate to new package imports |206207## 9. Files to Delete208209| File | Reason |210|------|--------|211| `zerg/security.py` | Migrated to `zerg/security/` package |212| `zerg/security_rules.py` | Migrated to `zerg/security/rules.py` |213214## 10. Migration Plan2152161. Create `zerg/security/` package with all modules2172. Migrate `security.py` functions to `scanner.py`, `patterns.py`, `hooks.py`2183. Migrate `security_rules.py` to `rules.py`2194. Update all callers (`review.py`, `security_rules_cmd.py`, any others)2205. Add new capabilities to `scanner.py` + `patterns.py`2216. Create `cve.py` with API + fallback2227. Integrate into `review.py` as Stage 32238. Update slash commands (`review.md`, `security.md`)2249. Update docs and website22510. Delete old files22611. Run full test suite227228## 11. Documentation Impact Analysis229230| Document | Section | Change |231|----------|---------|--------|232| `zerg/data/commands/review.md` | Modes/Output/Help | Add Stage 3, --no-security flag |233| `zerg/data/commands/security.md` | Capabilities | Reference shared engine |234| `docs/commands-quick.md` | /zerg:review row | Add --no-security flag |235| `docs/commands-deep.md` | /zerg:review section | New 3-stage diagram, security stage details |236| `docs/commands-deep.md` | /zerg:security section | Note shared engine with review |237| `docs/index.html` | Command table + hero/features | Update review desc, add security narrative |238| `docs/wiki/Security-Philosophy.md` | New page | Security-as-core-value philosophy |239| `CHANGELOG.md` | [Unreleased] | Feature entry |240241## 12. Risk Assessment242243| Risk | Probability | Impact | Mitigation |244|------|-------------|--------|------------|245| Import breakage from package migration | Medium | High | Grep all imports before migration, update atomically |246| CVE API rate limiting | Low | Low | Graceful fallback to heuristics |247| False positives from new patterns | Medium | Medium | Start with high-confidence patterns, tune iteratively |248| Performance regression from deep scan | Low | Medium | Benchmark 50-file scan, set 5s budget |249| Scope creep from 15 capabilities | Medium | High | Implement in priority order, each independently testable |250251## 13. Open Questions (RESOLVED)2522531. **osv.dev vs pip-audit**: osv.dev API first, then shell out to `pip-audit`/`npm audit` as secondary source. Both, layered.2542. **Git history depth**: Configurable. Default: last 100 commits. Document the default clearly in help text and docs.2553. **License database**: Library integration (not hardcoded allowlist). Use a proper license detection library.2564. **Severity thresholds**: `--no-security` is never blocked, but critical findings trigger prominent red warnings prompting the user to reconsider. The scan still skips — the user has final say.257258---259260*Generated by /zerg:plan --socratic (3 rounds)*