vanara 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/bin/vanara.js +66 -2
- package/catalog/agents/api-designer/AGENT.md +156 -0
- package/catalog/agents/api-designer/examples/openapi-snippet.yaml +130 -0
- package/catalog/agents/api-designer/examples/review-notes.md +61 -0
- package/catalog/agents/api-designer/references/contract-and-openapi.md +82 -0
- package/catalog/agents/api-designer/references/design-checklist.md +68 -0
- package/catalog/agents/api-designer/references/versioning-and-evolution.md +63 -0
- package/catalog/agents/api-designer/scripts/lint-openapi.mjs +180 -0
- package/catalog/agents/code-reviewer/AGENT.md +184 -0
- package/catalog/agents/code-reviewer/examples/pr-comment-template.md +48 -0
- package/catalog/agents/code-reviewer/examples/sample-review-output.md +38 -0
- package/catalog/agents/code-reviewer/references/review-checklist.md +46 -0
- package/catalog/agents/code-reviewer/references/security-review.md +62 -0
- package/catalog/agents/code-reviewer/references/severity-rubric.md +63 -0
- package/catalog/agents/code-reviewer/scripts/review-guard.mjs +102 -0
- package/catalog/agents/debugger/AGENT.md +128 -0
- package/catalog/agents/debugger/examples/postmortem-template.md +59 -0
- package/catalog/agents/debugger/examples/repro-template.md +50 -0
- package/catalog/agents/debugger/references/bisection.md +63 -0
- package/catalog/agents/debugger/references/debugging-method.md +57 -0
- package/catalog/agents/debugger/references/observability.md +61 -0
- package/catalog/agents/debugger/scripts/parse-stacktrace.mjs +109 -0
- package/catalog/agents/pr-summarizer/AGENT.md +172 -0
- package/catalog/agents/pr-summarizer/examples/sample-pr-summary.md +46 -0
- package/catalog/agents/pr-summarizer/examples/weak-vs-strong-summary.md +68 -0
- package/catalog/agents/pr-summarizer/references/identifying-risk.md +68 -0
- package/catalog/agents/pr-summarizer/references/reading-the-diff.md +68 -0
- package/catalog/agents/pr-summarizer/references/test-plan-and-missing-tests.md +64 -0
- package/catalog/agents/pr-summarizer/references/writing-the-summary.md +63 -0
- package/catalog/agents/pr-summarizer/scripts/diff-risk.mjs +111 -0
- package/catalog/agents/refactoring-specialist/AGENT.md +201 -0
- package/catalog/agents/refactoring-specialist/examples/before-after.md +91 -0
- package/catalog/agents/refactoring-specialist/examples/refactor-plan.md +97 -0
- package/catalog/agents/refactoring-specialist/references/large-scale-refactor.md +50 -0
- package/catalog/agents/refactoring-specialist/references/safe-workflow.md +75 -0
- package/catalog/agents/refactoring-specialist/references/smell-catalog.md +76 -0
- package/catalog/agents/refactoring-specialist/scripts/detect-smells.mjs +150 -0
- package/catalog/agents/security-auditor/AGENT.md +184 -0
- package/catalog/agents/security-auditor/examples/audit-report.md +68 -0
- package/catalog/agents/security-auditor/examples/finding-template.md +31 -0
- package/catalog/agents/security-auditor/references/audit-workflow.md +116 -0
- package/catalog/agents/security-auditor/references/severity-and-reporting.md +56 -0
- package/catalog/agents/security-auditor/references/vuln-classes.md +129 -0
- package/catalog/agents/security-auditor/scripts/scan-secrets.mjs +86 -0
- package/catalog/agents/technical-writer/AGENT.md +179 -0
- package/catalog/agents/technical-writer/examples/how-to-example.md +76 -0
- package/catalog/agents/technical-writer/examples/reference-example.md +75 -0
- package/catalog/agents/technical-writer/references/clarity-and-style.md +52 -0
- package/catalog/agents/technical-writer/references/diataxis-and-doc-types.md +61 -0
- package/catalog/agents/technical-writer/references/structure-and-maintenance.md +59 -0
- package/catalog/agents/technical-writer/scripts/readability.mjs +103 -0
- package/catalog/agents/test-author/AGENT.md +193 -0
- package/catalog/agents/test-author/examples/test-plan.md +54 -0
- package/catalog/agents/test-author/examples/unit-test-example.ts +55 -0
- package/catalog/agents/test-author/references/aaa-and-naming.md +75 -0
- package/catalog/agents/test-author/references/mocking-and-fixtures.md +94 -0
- package/catalog/agents/test-author/references/test-types-and-pyramid.md +60 -0
- package/catalog/agents/test-author/scripts/check-coverage.mjs +145 -0
- package/catalog/agents/threat-modeler/AGENT.md +179 -0
- package/catalog/agents/threat-modeler/examples/dfd-example.md +55 -0
- package/catalog/agents/threat-modeler/examples/threat-model.md +81 -0
- package/catalog/agents/threat-modeler/references/dfd-and-trust-boundaries.md +76 -0
- package/catalog/agents/threat-modeler/references/mitigation-catalog.md +77 -0
- package/catalog/agents/threat-modeler/references/stride-method.md +68 -0
- package/catalog/agents/threat-modeler/scripts/stride-checklist.mjs +183 -0
- package/catalog/agents/vuln-scanner/AGENT.md +162 -0
- package/catalog/agents/vuln-scanner/examples/finding-template.md +57 -0
- package/catalog/agents/vuln-scanner/examples/scan-report.md +49 -0
- package/catalog/agents/vuln-scanner/references/remediation-and-severity.md +68 -0
- package/catalog/agents/vuln-scanner/references/scan-types-and-tools.md +83 -0
- package/catalog/agents/vuln-scanner/references/triage-and-false-positives.md +73 -0
- package/catalog/agents/vuln-scanner/scripts/parse-scan-results.mjs +133 -0
- package/catalog/packs/code-review-pack/PACK.md +100 -0
- package/catalog/packs/code-review-pack/examples/pr-flow-example.md +50 -0
- package/catalog/packs/code-review-pack/references/rollout-guide.md +40 -0
- package/catalog/packs/security-pack/PACK.md +128 -0
- package/catalog/packs/security-pack/examples/owasp-vuln-triage-and-fix.md +66 -0
- package/catalog/packs/security-pack/examples/threat-model-then-audit.md +77 -0
- package/catalog/packs/security-pack/references/choosing-the-right-tool.md +37 -0
- package/catalog/packs/security-pack/references/threat-model-to-remediation.md +69 -0
- package/catalog/packs/security-pack/references/workflow.md +56 -0
- package/catalog/skills/api-pagination/SKILL.md +83 -0
- package/catalog/skills/api-pagination/examples/keyset-queries.sql +38 -0
- package/catalog/skills/api-pagination/examples/response-shapes.md +51 -0
- package/catalog/skills/api-pagination/references/consuming-pages.md +39 -0
- package/catalog/skills/api-pagination/references/counting-and-totals.md +41 -0
- package/catalog/skills/api-pagination/references/cursor-encoding.md +34 -0
- package/catalog/skills/api-pagination/scripts/check-cursor.mjs +51 -0
- package/catalog/skills/caching-strategies/SKILL.md +180 -0
- package/catalog/skills/caching-strategies/examples/http-cache-headers.md +82 -0
- package/catalog/skills/caching-strategies/examples/redis-cache-aside.js +110 -0
- package/catalog/skills/caching-strategies/references/cache-patterns.md +93 -0
- package/catalog/skills/caching-strategies/references/eviction-and-ttl.md +67 -0
- package/catalog/skills/caching-strategies/references/invalidation-and-stampede.md +99 -0
- package/catalog/skills/caching-strategies/scripts/ttl-jitter.mjs +99 -0
- package/catalog/skills/conventional-commits/SKILL.md +135 -0
- package/catalog/skills/conventional-commits/examples/commit-examples.md +60 -0
- package/catalog/skills/conventional-commits/examples/commitlint.config.js +31 -0
- package/catalog/skills/conventional-commits/references/breaking-changes-semver.md +50 -0
- package/catalog/skills/conventional-commits/references/scoping-commits.md +42 -0
- package/catalog/skills/conventional-commits/references/spec.md +78 -0
- package/catalog/skills/conventional-commits/scripts/lint-commit.mjs +97 -0
- package/catalog/skills/database-migrations/SKILL.md +137 -0
- package/catalog/skills/database-migrations/examples/add-column-safe.sql +34 -0
- package/catalog/skills/database-migrations/examples/migration-config.example.json +27 -0
- package/catalog/skills/database-migrations/references/expand-contract.md +74 -0
- package/catalog/skills/database-migrations/references/rollback-and-safety.md +71 -0
- package/catalog/skills/database-migrations/references/zero-downtime-changes.md +84 -0
- package/catalog/skills/database-migrations/scripts/check-migration-reversible.mjs +139 -0
- package/catalog/skills/error-handling-patterns/SKILL.md +136 -0
- package/catalog/skills/error-handling-patterns/examples/express-error-middleware.js +93 -0
- package/catalog/skills/error-handling-patterns/examples/result-pattern.ts +81 -0
- package/catalog/skills/error-handling-patterns/references/error-taxonomy.md +91 -0
- package/catalog/skills/error-handling-patterns/references/language-patterns.md +102 -0
- package/catalog/skills/error-handling-patterns/references/retry-and-backoff.md +76 -0
- package/catalog/skills/error-handling-patterns/scripts/lint-empty-catch.mjs +113 -0
- package/catalog/skills/git-collaboration-workflows/SKILL.md +104 -0
- package/catalog/skills/git-collaboration-workflows/examples/branch-protection.md +48 -0
- package/catalog/skills/git-collaboration-workflows/examples/pr-review-playbook.md +48 -0
- package/catalog/skills/git-collaboration-workflows/references/branching-models.md +52 -0
- package/catalog/skills/git-collaboration-workflows/references/history-hygiene.md +44 -0
- package/catalog/skills/git-collaboration-workflows/scripts/check-branch-hygiene.mjs +62 -0
- package/catalog/skills/owasp-top10/SKILL.md +112 -0
- package/catalog/skills/owasp-top10/examples/sql-injection-fix.md +33 -0
- package/catalog/skills/owasp-top10/examples/xss-fix.md +27 -0
- package/catalog/skills/owasp-top10/references/access-control.md +36 -0
- package/catalog/skills/owasp-top10/references/crypto-failures.md +29 -0
- package/catalog/skills/owasp-top10/references/injection.md +39 -0
- package/catalog/skills/owasp-top10/references/ssrf-and-design.md +35 -0
- package/catalog/skills/owasp-top10/scripts/scan-injection.mjs +73 -0
- package/catalog/skills/prompt-engineering/SKILL.md +100 -0
- package/catalog/skills/prompt-engineering/examples/classification-prompt.md +29 -0
- package/catalog/skills/prompt-engineering/examples/extraction-prompt.md +25 -0
- package/catalog/skills/prompt-engineering/references/prompt-injection.md +34 -0
- package/catalog/skills/prompt-engineering/references/structured-output.md +34 -0
- package/catalog/skills/prompt-engineering/references/techniques.md +33 -0
- package/catalog/skills/prompt-engineering/scripts/validate-output.mjs +71 -0
- package/catalog/skills/readme-writing/SKILL.md +176 -0
- package/catalog/skills/readme-writing/examples/README.template.md +73 -0
- package/catalog/skills/readme-writing/examples/good-readme-example.md +95 -0
- package/catalog/skills/readme-writing/references/anatomy.md +107 -0
- package/catalog/skills/readme-writing/references/maintenance.md +68 -0
- package/catalog/skills/readme-writing/references/writing-style.md +79 -0
- package/catalog/skills/readme-writing/scripts/lint-readme.mjs +117 -0
- package/catalog/skills/refactoring-patterns/SKILL.md +178 -0
- package/catalog/skills/refactoring-patterns/examples/extract-function.before-after.js +57 -0
- package/catalog/skills/refactoring-patterns/examples/replace-conditional-with-polymorphism.before-after.ts +63 -0
- package/catalog/skills/refactoring-patterns/references/code-smells.md +92 -0
- package/catalog/skills/refactoring-patterns/references/refactoring-catalog.md +78 -0
- package/catalog/skills/refactoring-patterns/references/safe-workflow.md +74 -0
- package/catalog/skills/refactoring-patterns/scripts/detect-smells.mjs +137 -0
- package/catalog/skills/rest-api-design/SKILL.md +147 -0
- package/catalog/skills/rest-api-design/examples/error-envelope.json +26 -0
- package/catalog/skills/rest-api-design/examples/orders-api.openapi.yaml +106 -0
- package/catalog/skills/rest-api-design/references/error-handling.md +43 -0
- package/catalog/skills/rest-api-design/references/pagination.md +41 -0
- package/catalog/skills/rest-api-design/references/status-codes.md +32 -0
- package/catalog/skills/rest-api-design/references/versioning.md +31 -0
- package/catalog/skills/rest-api-design/scripts/check-envelope.mjs +62 -0
- package/catalog/skills/secrets-management/SKILL.md +134 -0
- package/catalog/skills/secrets-management/examples/env-example.md +41 -0
- package/catalog/skills/secrets-management/examples/rotation-runbook.md +50 -0
- package/catalog/skills/secrets-management/references/leak-response.md +47 -0
- package/catalog/skills/secrets-management/references/rotation.md +46 -0
- package/catalog/skills/secrets-management/references/secret-managers.md +52 -0
- package/catalog/skills/secrets-management/scripts/detect-hardcoded.mjs +96 -0
- package/catalog/skills/secure-auth/SKILL.md +135 -0
- package/catalog/skills/secure-auth/examples/auth-flow.md +60 -0
- package/catalog/skills/secure-auth/examples/jwt-verify.ts +89 -0
- package/catalog/skills/secure-auth/references/auth-attacks.md +76 -0
- package/catalog/skills/secure-auth/references/oauth2-oidc.md +65 -0
- package/catalog/skills/secure-auth/references/password-hashing.md +70 -0
- package/catalog/skills/secure-auth/references/sessions-vs-jwt.md +69 -0
- package/catalog/skills/secure-auth/scripts/check-password-policy.mjs +114 -0
- package/catalog/skills/sql-index-tuning/SKILL.md +171 -0
- package/catalog/skills/sql-index-tuning/examples/explain-walkthrough.sql +91 -0
- package/catalog/skills/sql-index-tuning/examples/index-ddl.sql +67 -0
- package/catalog/skills/sql-index-tuning/references/btree-internals.md +58 -0
- package/catalog/skills/sql-index-tuning/references/composite-and-covering.md +60 -0
- package/catalog/skills/sql-index-tuning/references/reading-explain.md +54 -0
- package/catalog/skills/sql-index-tuning/references/selectivity-and-cardinality.md +62 -0
- package/catalog/skills/sql-index-tuning/scripts/suggest-index.mjs +213 -0
- package/catalog/skills/test-plan-design/SKILL.md +154 -0
- package/catalog/skills/test-plan-design/examples/test-case-template.md +45 -0
- package/catalog/skills/test-plan-design/examples/test-plan.md +57 -0
- package/catalog/skills/test-plan-design/references/case-design.md +79 -0
- package/catalog/skills/test-plan-design/references/risk-prioritization.md +58 -0
- package/catalog/skills/test-plan-design/references/test-pyramid.md +58 -0
- package/catalog/skills/test-plan-design/scripts/coverage-gaps.mjs +109 -0
- package/free-tier.json +15 -0
- package/package.json +15 -4
- package/premium-index.json +1 -0
- package/src/config.js +31 -1
- package/src/license.js +143 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Data-Flow Diagrams and Trust Boundaries
|
|
2
|
+
|
|
3
|
+
A threat model is only as good as the diagram it sits on. The data-flow diagram (DFD) is the map; trust
|
|
4
|
+
boundaries are where the dangerous neighborhoods are. Build the diagram first, then hunt threats along
|
|
5
|
+
the boundaries.
|
|
6
|
+
|
|
7
|
+
## The four element types
|
|
8
|
+
|
|
9
|
+
Every DFD is built from exactly four kinds of element. Keep them distinct — the element type determines
|
|
10
|
+
which STRIDE categories apply (see `stride-method.md`).
|
|
11
|
+
|
|
12
|
+
| Element | What it is | Notation here |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| **External entity** | An actor outside your control: a user, a browser, a third-party API | `(E1) Browser` |
|
|
15
|
+
| **Process** | Code that transforms data: a service, a Lambda, a function | `(P2) Auth Service` |
|
|
16
|
+
| **Data store** | Where data rests: a DB, cache, queue, bucket, file | `(DS3) User DB` |
|
|
17
|
+
| **Data flow** | Data in motion between two elements | `──1: HTTPS POST──►` |
|
|
18
|
+
|
|
19
|
+
Number every element and every flow. Threat IDs reference these numbers, which is what makes the model
|
|
20
|
+
auditable: anyone can check that flow 4 has been considered.
|
|
21
|
+
|
|
22
|
+
## What a trust boundary is
|
|
23
|
+
|
|
24
|
+
A trust boundary is any line where the level of trust changes — where data or control passes from a
|
|
25
|
+
less-trusted zone into a more-trusted one. Threats concentrate here because this is where an attacker on
|
|
26
|
+
the outside tries to influence the inside.
|
|
27
|
+
|
|
28
|
+
Draw a boundary at:
|
|
29
|
+
|
|
30
|
+
- **Network edges** — Internet → DMZ → internal network.
|
|
31
|
+
- **Privilege changes** — unauthenticated → authenticated; user → admin; user-space → kernel.
|
|
32
|
+
- **Ownership changes** — your service → a third-party API; first-party → vendor SDK.
|
|
33
|
+
- **Process/host edges** — browser → server; container → host; tenant A → tenant B in multi-tenancy.
|
|
34
|
+
- **Data sensitivity changes** — public data → PII/PCI/PHI store.
|
|
35
|
+
|
|
36
|
+
The classic mistake is drawing too few boundaries. A monolith still has a boundary between the
|
|
37
|
+
unauthenticated request handler and the authenticated business logic.
|
|
38
|
+
|
|
39
|
+
## Text notation
|
|
40
|
+
|
|
41
|
+
Render the DFD as text so it lives in version control next to the design and diffs cleanly. The
|
|
42
|
+
convention used across this package:
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
TRUST BOUNDARY: <less trusted> ││ <more trusted>
|
|
46
|
+
|
|
47
|
+
(E1) Entity ──N: flow label──►││──► (Pn) Process ──M: flow──►││──► (DSn) Store
|
|
48
|
+
Legend: (E)=external entity (P)=process (DS)=data store
|
|
49
|
+
N: numbered data flow ││ = trust boundary crossing
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- `││` marks each point where a flow crosses a boundary. A flow with no `││` stays inside one trust zone.
|
|
53
|
+
- Keep labels verb-or-protocol oriented (`HTTPS POST /login`, `SQL query`, `publish to queue`) so the
|
|
54
|
+
reader knows what crosses.
|
|
55
|
+
|
|
56
|
+
## Reading threats off the diagram
|
|
57
|
+
|
|
58
|
+
Once boundaries are marked, the highest-value work is mechanical:
|
|
59
|
+
|
|
60
|
+
1. **List every flow that crosses a `││`.** These are your priority targets.
|
|
61
|
+
2. For each crossing flow, the **destination process** is where untrusted input lands — apply Tampering,
|
|
62
|
+
Information disclosure, DoS, and Elevation of privilege there.
|
|
63
|
+
3. For each **data store**, ask what happens if the flow writing to it is malicious (Tampering) or the
|
|
64
|
+
store leaks (Information disclosure).
|
|
65
|
+
4. For each **external entity**, ask how it's authenticated (Spoofing) and whether its actions are
|
|
66
|
+
logged (Repudiation).
|
|
67
|
+
|
|
68
|
+
## Common diagram mistakes
|
|
69
|
+
|
|
70
|
+
- **Missing the return flow.** Responses cross boundaries too and can leak data (Information disclosure).
|
|
71
|
+
- **Collapsing distinct stores.** "The database" might be a user table, a session cache, and an audit log
|
|
72
|
+
with very different sensitivity — model them separately.
|
|
73
|
+
- **Hiding third parties.** A payment processor or auth provider is an external entity behind a trust
|
|
74
|
+
boundary; its compromise or outage is in scope.
|
|
75
|
+
- **No boundary inside the server.** Authenticated vs. unauthenticated handlers, or user vs. admin paths,
|
|
76
|
+
are boundaries even on one host.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Mitigation Catalog
|
|
2
|
+
|
|
3
|
+
Reusable, concrete mitigations indexed by STRIDE category. Use these as a starting point — then make each
|
|
4
|
+
one *specific* to the threat it addresses (name the endpoint, the field, the store). A mitigation that
|
|
5
|
+
could be copy-pasted into any model unchanged is too vague to verify.
|
|
6
|
+
|
|
7
|
+
Every mitigation should be **testable**: you should be able to write a test or a check that proves it is
|
|
8
|
+
present and working.
|
|
9
|
+
|
|
10
|
+
## Spoofing → strengthen authentication
|
|
11
|
+
|
|
12
|
+
| Control | Notes |
|
|
13
|
+
|---|---|
|
|
14
|
+
| Strong authentication (OIDC/OAuth2, WebAuthn) | Avoid rolling your own; use established protocols |
|
|
15
|
+
| MFA on sensitive accounts and actions | Step-up auth for high-value operations (transfers, role changes) |
|
|
16
|
+
| Mutual TLS for service-to-service | Each service proves its identity, not just the client |
|
|
17
|
+
| Short-lived, signed tokens (JWT with `exp`, audience, issuer checks) | Validate signature, expiry, `aud`, `iss` server-side every request |
|
|
18
|
+
| Anti-automation on login (rate limit, lockout, CAPTCHA/proof-of-work) | Defends credential stuffing and brute force |
|
|
19
|
+
|
|
20
|
+
## Tampering → protect integrity
|
|
21
|
+
|
|
22
|
+
| Control | Notes |
|
|
23
|
+
|---|---|
|
|
24
|
+
| TLS for all data in transit | Prevents on-path modification |
|
|
25
|
+
| Server-side input validation against an allow-list/schema | Validate at the trust boundary, before use; never trust client checks |
|
|
26
|
+
| Parameterized queries / prepared statements | Eliminates SQL injection tampering |
|
|
27
|
+
| HMAC or digital signatures on critical messages | Detects modification of webhooks, tokens, inter-service messages |
|
|
28
|
+
| Integrity checks on stored data (checksums, append-only stores) | Detect or prevent at-rest modification |
|
|
29
|
+
| Subresource Integrity (SRI) on third-party scripts | Detects tampered CDN assets |
|
|
30
|
+
|
|
31
|
+
## Repudiation → ensure accountability
|
|
32
|
+
|
|
33
|
+
| Control | Notes |
|
|
34
|
+
|---|---|
|
|
35
|
+
| Tamper-evident audit log of security-relevant actions | Append-only or signed; actor, action, timestamp, before/after |
|
|
36
|
+
| Logs stored outside the actor's control | An admin should not be able to edit logs of their own actions |
|
|
37
|
+
| Synchronized, trusted timestamps | NTP; record server time, not client-claimed time |
|
|
38
|
+
| Correlation/request IDs across services | Reconstruct an action end-to-end |
|
|
39
|
+
|
|
40
|
+
## Information disclosure → enforce confidentiality
|
|
41
|
+
|
|
42
|
+
| Control | Notes |
|
|
43
|
+
|---|---|
|
|
44
|
+
| Encryption at rest for sensitive stores | DB/disk/bucket encryption; manage keys in a KMS |
|
|
45
|
+
| TLS in transit (see Tampering) | Confidentiality + integrity together |
|
|
46
|
+
| Least-privilege data access; field-level authz | Return only what the caller is entitled to |
|
|
47
|
+
| Generic error messages externally; detail in server logs only | Don't leak stack traces, SQL, or existence (404 vs 403) |
|
|
48
|
+
| Scrub secrets/PII from logs and telemetry | Redact tokens, card numbers, emails before logging |
|
|
49
|
+
| Avoid IDOR | Check resource *ownership*, not just authentication |
|
|
50
|
+
|
|
51
|
+
## Denial of service → preserve availability
|
|
52
|
+
|
|
53
|
+
| Control | Notes |
|
|
54
|
+
|---|---|
|
|
55
|
+
| Rate limiting and quotas per client/key | Return `429` + `Retry-After`; defend per-tenant |
|
|
56
|
+
| Timeouts and circuit breakers on outbound calls | Stop a slow dependency from exhausting your threads |
|
|
57
|
+
| Input size and complexity limits | Cap payload size, page size, query depth, regex complexity (ReDoS) |
|
|
58
|
+
| Resource pooling and back-pressure | Bounded queues; shed load instead of collapsing |
|
|
59
|
+
| CDN/WAF and autoscaling for public surfaces | Absorb volumetric floods upstream |
|
|
60
|
+
|
|
61
|
+
## Elevation of privilege → enforce authorization
|
|
62
|
+
|
|
63
|
+
| Control | Notes |
|
|
64
|
+
|---|---|
|
|
65
|
+
| Centralized, server-side authorization on every action | Deny by default; never rely on hidden UI or client checks |
|
|
66
|
+
| Principle of least privilege for processes and tokens | Minimal DB grants, scoped tokens, no ambient admin |
|
|
67
|
+
| Sandboxing / isolation of untrusted input handling | Separate parsing/deserialization from privileged logic |
|
|
68
|
+
| Avoid unsafe deserialization, template injection, path traversal | Allow-list types/paths; canonicalize before checks |
|
|
69
|
+
| Re-check authz after any state or role change | Don't cache a stale privilege decision across a privilege change |
|
|
70
|
+
|
|
71
|
+
## Choosing among controls
|
|
72
|
+
|
|
73
|
+
- Prefer **eliminating** a threat (remove the feature/flow) over mitigating it.
|
|
74
|
+
- Prefer a **single well-placed control at the trust boundary** over many scattered patches.
|
|
75
|
+
- Layer controls so the failure of one (a bypassed WAF, a leaked token) is not total (defense in depth).
|
|
76
|
+
- For any threat you choose **not** to mitigate, record it as an accepted/transferred risk with a named
|
|
77
|
+
owner and rationale — see `AGENT.md` output format.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# The STRIDE Method
|
|
2
|
+
|
|
3
|
+
STRIDE is a threat-classification model created at Microsoft. Each letter names a category of threat
|
|
4
|
+
defined by the security property it violates. Walking every element of a system against all six
|
|
5
|
+
categories gives you systematic coverage instead of relying on whatever attacks you happen to think of.
|
|
6
|
+
|
|
7
|
+
## The six categories
|
|
8
|
+
|
|
9
|
+
| Category | Property violated | The attacker's goal | Example |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| **Spoofing** | Authentication | Pretend to be someone/something else | Forged JWT, stolen session, impersonated service identity |
|
|
12
|
+
| **Tampering** | Integrity | Modify data or code | Altered request body, poisoned cache, modified DB row |
|
|
13
|
+
| **Repudiation** | Non-repudiation | Deny having done something | No audit trail for a refund; logs are editable |
|
|
14
|
+
| **Information disclosure** | Confidentiality | Read data they shouldn't | PII in logs, verbose errors, IDOR exposing other users' records |
|
|
15
|
+
| **Denial of service** | Availability | Make the system unavailable | Connection flood, expensive query amplification, lock exhaustion |
|
|
16
|
+
| **Elevation of privilege** | Authorization | Gain rights they shouldn't have | Missing server-side authz check, path traversal, sandbox escape |
|
|
17
|
+
|
|
18
|
+
## Element-type → applicable categories
|
|
19
|
+
|
|
20
|
+
Not every category applies to every element type. Use this mapping so you don't waste effort (and don't
|
|
21
|
+
miss the relevant ones):
|
|
22
|
+
|
|
23
|
+
| Element type | S | T | R | I | D | E |
|
|
24
|
+
|---|:-:|:-:|:-:|:-:|:-:|:-:|
|
|
25
|
+
| External entity (user, third party) | ● | | ● | | | |
|
|
26
|
+
| Process (service, function) | ● | ● | ● | ● | ● | ● |
|
|
27
|
+
| Data store (DB, cache, queue, files) | | ● | ● | ● | ● | |
|
|
28
|
+
| Data flow (network call, IPC) | | ● | | ● | ● | |
|
|
29
|
+
|
|
30
|
+
A *process* is the most exposed element — all six categories apply. A *data store* can't be "spoofed"
|
|
31
|
+
(it has no identity to forge) but can be tampered with, leak data, be DoS'd, and may need to defend
|
|
32
|
+
against repudiation if it holds audit records.
|
|
33
|
+
|
|
34
|
+
## Per-element question checklist
|
|
35
|
+
|
|
36
|
+
For each element on the diagram, ask the questions for its applicable categories:
|
|
37
|
+
|
|
38
|
+
**Spoofing**
|
|
39
|
+
- How is this entity/process authenticated? Can the credential be stolen, replayed, or forged?
|
|
40
|
+
- Is mutual authentication needed for service-to-service calls?
|
|
41
|
+
|
|
42
|
+
**Tampering**
|
|
43
|
+
- Can a request, message, or stored record be modified in transit or at rest?
|
|
44
|
+
- Is integrity protected (TLS, signatures, HMAC, checksums)?
|
|
45
|
+
|
|
46
|
+
**Repudiation**
|
|
47
|
+
- Is there a tamper-evident audit log of security-relevant actions?
|
|
48
|
+
- Can a user or admin alter or delete the evidence of their own actions?
|
|
49
|
+
|
|
50
|
+
**Information disclosure**
|
|
51
|
+
- What sensitive data does this element hold or transmit? Who can read it?
|
|
52
|
+
- Do errors, logs, headers, or timing leak information? Is data encrypted at rest and in transit?
|
|
53
|
+
|
|
54
|
+
**Denial of service**
|
|
55
|
+
- What resource (CPU, memory, connections, locks, quota) can an attacker exhaust?
|
|
56
|
+
- Are there rate limits, timeouts, quotas, and back-pressure?
|
|
57
|
+
|
|
58
|
+
**Elevation of privilege**
|
|
59
|
+
- Is every action authorized server-side, checking *ownership* not just authentication (IDOR)?
|
|
60
|
+
- Can input cross a trust boundary into a more privileged context (injection, deserialization, traversal)?
|
|
61
|
+
|
|
62
|
+
## How STRIDE relates to DREAD and risk rating
|
|
63
|
+
|
|
64
|
+
STRIDE *finds and classifies* threats; it does not rate them. Pair it with a rating scheme — this package
|
|
65
|
+
uses a lightweight Likelihood × Impact score (see `AGENT.md` → Risk rating). DREAD (Damage,
|
|
66
|
+
Reproducibility, Exploitability, Affected users, Discoverability) is an alternative; it is more granular
|
|
67
|
+
but harder to apply consistently. For most design-time models, Likelihood × Impact is enough and more
|
|
68
|
+
repeatable across reviewers.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Runnable check: validates that a threat-model document covers all six STRIDE
|
|
3
|
+
// categories for every element it names. Accepts either JSON or a markdown
|
|
4
|
+
// threat table, so you can lint a model before review.
|
|
5
|
+
//
|
|
6
|
+
// STRIDE = Spoofing, Tampering, Repudiation, Information disclosure,
|
|
7
|
+
// Denial of service, Elevation of privilege.
|
|
8
|
+
//
|
|
9
|
+
// Usage:
|
|
10
|
+
// node stride-checklist.mjs model.json # check a JSON model file
|
|
11
|
+
// node stride-checklist.mjs model.md # check a markdown threat table
|
|
12
|
+
// cat model.md | node stride-checklist.mjs # check from stdin
|
|
13
|
+
// node stride-checklist.mjs --selftest # run built-in test cases
|
|
14
|
+
//
|
|
15
|
+
// JSON shape (either accepted):
|
|
16
|
+
// { "elements": [ { "name": "Auth", "categories": ["S","T","R","I","D","E"] } ] }
|
|
17
|
+
// [ { "name": "Auth", "categories": ["Spoofing", "Tampering", ...] } ]
|
|
18
|
+
//
|
|
19
|
+
// Markdown: any table with an "Element" column and a "STRIDE" column; rows are
|
|
20
|
+
// grouped by element and the STRIDE cells are unioned per element.
|
|
21
|
+
|
|
22
|
+
import { readFileSync } from 'node:fs';
|
|
23
|
+
|
|
24
|
+
const STRIDE = ['S', 'T', 'R', 'I', 'D', 'E'];
|
|
25
|
+
const STRIDE_NAME = {
|
|
26
|
+
S: 'Spoofing', T: 'Tampering', R: 'Repudiation',
|
|
27
|
+
I: 'Information disclosure', D: 'Denial of service', E: 'Elevation of privilege',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Normalize a category token (letter or full word) to a single STRIDE letter, or null.
|
|
31
|
+
export function toLetter(token) {
|
|
32
|
+
if (typeof token !== 'string') return null;
|
|
33
|
+
const t = token.trim().toUpperCase();
|
|
34
|
+
if (STRIDE.includes(t)) return t;
|
|
35
|
+
const word = token.trim().toLowerCase();
|
|
36
|
+
if (word.startsWith('spoof')) return 'S';
|
|
37
|
+
if (word.startsWith('tamper')) return 'T';
|
|
38
|
+
if (word.startsWith('repudiat')) return 'R';
|
|
39
|
+
if (word.startsWith('info')) return 'I';
|
|
40
|
+
if (word.startsWith('denial') || word === 'dos') return 'D';
|
|
41
|
+
if (word.startsWith('elevat') || word.includes('privilege')) return 'E';
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Build a map of element name -> Set of covered STRIDE letters.
|
|
46
|
+
function buildCoverage(elements) {
|
|
47
|
+
const map = new Map();
|
|
48
|
+
for (const el of elements) {
|
|
49
|
+
const name = (el && el.name ? String(el.name) : '').trim();
|
|
50
|
+
if (!name) continue;
|
|
51
|
+
if (!map.has(name)) map.set(name, new Set());
|
|
52
|
+
const set = map.get(name);
|
|
53
|
+
for (const c of el.categories || []) {
|
|
54
|
+
const letter = toLetter(c);
|
|
55
|
+
if (letter) set.add(letter);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return map;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Parse a JSON threat model into an elements array.
|
|
62
|
+
function parseJson(text) {
|
|
63
|
+
const obj = JSON.parse(text);
|
|
64
|
+
const arr = Array.isArray(obj) ? obj : obj.elements;
|
|
65
|
+
if (!Array.isArray(arr)) throw new Error('expected an array or { elements: [...] }');
|
|
66
|
+
return arr;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Parse a markdown threat table into an elements array.
|
|
70
|
+
function parseMarkdown(text) {
|
|
71
|
+
const lines = text.split('\n').filter((l) => l.trim().startsWith('|'));
|
|
72
|
+
if (lines.length < 2) throw new Error('no markdown table found');
|
|
73
|
+
const cells = (line) => line.split('|').slice(1, -1).map((c) => c.trim());
|
|
74
|
+
const header = cells(lines[0]).map((h) => h.toLowerCase());
|
|
75
|
+
const elIdx = header.findIndex((h) => h.includes('element'));
|
|
76
|
+
const strideIdx = header.findIndex((h) => h.includes('stride') || h === 'category');
|
|
77
|
+
if (elIdx === -1 || strideIdx === -1) {
|
|
78
|
+
throw new Error('table needs an "Element" column and a "STRIDE" column');
|
|
79
|
+
}
|
|
80
|
+
const out = [];
|
|
81
|
+
for (const line of lines.slice(1)) {
|
|
82
|
+
const row = cells(line);
|
|
83
|
+
if (row.every((c) => /^[-:]*$/.test(c))) continue; // separator row
|
|
84
|
+
if (row.length <= Math.max(elIdx, strideIdx)) continue;
|
|
85
|
+
out.push({ name: row[elIdx], categories: [row[strideIdx]] });
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function parse(text) {
|
|
91
|
+
const trimmed = text.trim();
|
|
92
|
+
if (trimmed.startsWith('{') || trimmed.startsWith('[')) return parseJson(trimmed);
|
|
93
|
+
return parseMarkdown(trimmed);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Returns { ok, elements: [{ name, missing: [letters] }] }
|
|
97
|
+
export function checkCoverage(elements) {
|
|
98
|
+
const coverage = buildCoverage(elements);
|
|
99
|
+
const report = [];
|
|
100
|
+
for (const [name, covered] of coverage) {
|
|
101
|
+
const missing = STRIDE.filter((c) => !covered.has(c));
|
|
102
|
+
report.push({ name, missing });
|
|
103
|
+
}
|
|
104
|
+
const ok = report.length > 0 && report.every((r) => r.missing.length === 0);
|
|
105
|
+
return { ok, elements: report };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function render(label, result) {
|
|
109
|
+
if (result.elements.length === 0) {
|
|
110
|
+
console.error(`✗ ${label}: no elements found in document`);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
for (const { name, missing } of result.elements) {
|
|
114
|
+
if (missing.length === 0) {
|
|
115
|
+
console.log(`✓ ${name}: all six STRIDE categories covered`);
|
|
116
|
+
} else {
|
|
117
|
+
const names = missing.map((m) => `${m} (${STRIDE_NAME[m]})`).join(', ');
|
|
118
|
+
console.error(`✗ ${name}: missing ${names}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
console.log(result.ok ? `✓ ${label}: complete` : `✗ ${label}: incomplete`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function checkText(label, text) {
|
|
125
|
+
let elements;
|
|
126
|
+
try { elements = parse(text); }
|
|
127
|
+
catch (e) { console.error(`✗ ${label}: ${e.message}`); return false; }
|
|
128
|
+
const result = checkCoverage(elements);
|
|
129
|
+
render(label, result);
|
|
130
|
+
return result.ok;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function selftest() {
|
|
134
|
+
const all = ['S', 'T', 'R', 'I', 'D', 'E'];
|
|
135
|
+
const complete = { elements: [
|
|
136
|
+
{ name: 'Auth Service', categories: all },
|
|
137
|
+
{ name: 'Order API', categories: ['Spoofing', 'Tampering', 'Repudiation',
|
|
138
|
+
'Information disclosure', 'Denial of service', 'Elevation of privilege'] },
|
|
139
|
+
] };
|
|
140
|
+
const incomplete = { elements: [
|
|
141
|
+
{ name: 'Auth Service', categories: ['S', 'T', 'R', 'I', 'D', 'E'] },
|
|
142
|
+
{ name: 'Order API', categories: ['S', 'T'] }, // missing R, I, D, E
|
|
143
|
+
] };
|
|
144
|
+
const completeMd = [
|
|
145
|
+
'| ID | Element | STRIDE | Threat |',
|
|
146
|
+
'|----|-------------|--------|--------|',
|
|
147
|
+
'| T1 | Auth | S | spoof |',
|
|
148
|
+
'| T2 | Auth | T | tamper |',
|
|
149
|
+
'| T3 | Auth | R | repud |',
|
|
150
|
+
'| T4 | Auth | I | leak |',
|
|
151
|
+
'| T5 | Auth | D | flood |',
|
|
152
|
+
'| T6 | Auth | E | escal |',
|
|
153
|
+
].join('\n');
|
|
154
|
+
|
|
155
|
+
const cases = [
|
|
156
|
+
['complete_json', complete, true],
|
|
157
|
+
['incomplete_json', incomplete, false],
|
|
158
|
+
['complete_markdown', completeMd, true],
|
|
159
|
+
];
|
|
160
|
+
let allExpected = true;
|
|
161
|
+
for (const [name, input, shouldPass] of cases) {
|
|
162
|
+
const elements = typeof input === 'string' ? parseMarkdown(input) : input.elements;
|
|
163
|
+
const { ok } = checkCoverage(elements);
|
|
164
|
+
const correct = ok === shouldPass;
|
|
165
|
+
allExpected &&= correct;
|
|
166
|
+
console.log(`${correct ? '✓' : '✗'} selftest ${name}: ${ok ? 'complete' : 'incomplete'} (expected ${shouldPass ? 'complete' : 'incomplete'})`);
|
|
167
|
+
}
|
|
168
|
+
process.exit(allExpected ? 0 : 1);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const arg = process.argv[2];
|
|
172
|
+
if (arg === '--selftest') {
|
|
173
|
+
selftest();
|
|
174
|
+
} else if (arg) {
|
|
175
|
+
let text;
|
|
176
|
+
try { text = readFileSync(arg, 'utf8'); }
|
|
177
|
+
catch (e) { console.error(`✗ cannot read ${arg}: ${e.message}`); process.exit(1); }
|
|
178
|
+
process.exit(checkText(arg, text) ? 0 : 1);
|
|
179
|
+
} else {
|
|
180
|
+
let buf = '';
|
|
181
|
+
process.stdin.on('data', (c) => (buf += c));
|
|
182
|
+
process.stdin.on('end', () => process.exit(checkText('stdin', buf) ? 0 : 1));
|
|
183
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vuln-scanner
|
|
3
|
+
description: Use when scanning a project's dependencies, source, config, and container images for known vulnerabilities (CVEs), risky versions, and exposed secrets — then triaging findings and proposing safe, prioritized remediations. Invoke before releases, on dependency bumps, or for periodic supply-chain hygiene.
|
|
4
|
+
tools: Read, Grep, Glob, Bash
|
|
5
|
+
model: claude-haiku-4-5
|
|
6
|
+
type: agent
|
|
7
|
+
version: 2.0.0
|
|
8
|
+
updated: 2026-06-29
|
|
9
|
+
---
|
|
10
|
+
# Vulnerability Scanner
|
|
11
|
+
|
|
12
|
+
You are an application-security scanning agent. Your job is to keep the software supply chain clean:
|
|
13
|
+
known-bad dependencies, leaked secrets, and risky configuration are caught and **triaged** before they
|
|
14
|
+
ship. A scan that dumps 400 raw findings is not security work — it is noise. Your value is in turning
|
|
15
|
+
raw scanner output into a short, ranked, actionable list a developer can act on today.
|
|
16
|
+
|
|
17
|
+
You operate read-only by default. You read lockfiles, source, and config; you run scanners in
|
|
18
|
+
report-only mode; you never auto-apply upgrades or rewrite history without explicit instruction. You
|
|
19
|
+
propose changes — a human approves them.
|
|
20
|
+
|
|
21
|
+
## Role and mindset
|
|
22
|
+
|
|
23
|
+
- **Signal over volume.** The deliverable is a triaged report, not a tool dump. Every finding you
|
|
24
|
+
surface must carry a severity, an exploitability judgment, and a concrete next step.
|
|
25
|
+
- **Reachability matters.** A critical CVE in a code path the app never calls is lower real-world risk
|
|
26
|
+
than a medium CVE on an internet-facing entrypoint. Say so.
|
|
27
|
+
- **Fix-forward.** Each vulnerable dependency gets a fix version and a breaking-vs-non-breaking label,
|
|
28
|
+
so the reader knows whether it's a one-line bump or a migration.
|
|
29
|
+
- **Secrets are incidents.** A committed secret is assumed compromised. Removal is not remediation;
|
|
30
|
+
rotation is.
|
|
31
|
+
|
|
32
|
+
## Scan workflow
|
|
33
|
+
|
|
34
|
+
Work through these phases in order. Skipping triage (phase 5) is the most common failure — do not.
|
|
35
|
+
|
|
36
|
+
1. **Scope and inventory.** Identify the stack(s) from manifests and lockfiles. Map direct vs.
|
|
37
|
+
transitive dependencies. Note what is in scope (app code, deps, containers, IaC) and what is not.
|
|
38
|
+
2. **Dependency / SCA scan.** Resolve installed versions from lockfiles and match against known CVEs.
|
|
39
|
+
Flag outdated, unmaintained (no release in a long window), or vulnerable-pinned packages.
|
|
40
|
+
3. **Secret scan.** Search the working tree (and, when asked, history) for high-entropy strings, known
|
|
41
|
+
key formats, tokens, and connection strings. Distinguish live secrets from test fixtures and
|
|
42
|
+
placeholders.
|
|
43
|
+
4. **Config / SAST / container scan.** Check risky config defaults (debug on, permissive CORS, disabled
|
|
44
|
+
TLS verification), obvious source-level sinks, and base-image CVEs when a Dockerfile is present.
|
|
45
|
+
5. **Triage.** Deduplicate, suppress confirmed false positives with a recorded reason, assess
|
|
46
|
+
reachability/exploitability, and assign a final severity. This is where raw output becomes a report.
|
|
47
|
+
6. **Prioritize and report.** Group into *fix now* (critical/high, reachable, non-breaking), *plan*
|
|
48
|
+
(breaking upgrades, lower severity), and *accept/monitor* (with justification).
|
|
49
|
+
7. **Self-check.** Before returning, verify the output against the self-check list below.
|
|
50
|
+
|
|
51
|
+
The heavy detail for each scan family lives in [scan-types-and-tools](references/scan-types-and-tools.md);
|
|
52
|
+
the triage rules live in [triage-and-false-positives](references/triage-and-false-positives.md).
|
|
53
|
+
|
|
54
|
+
## Triage rules
|
|
55
|
+
|
|
56
|
+
Triage is the core skill. A finding moves from *raw* to *reported* only after you answer four questions:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
1. Is it real? -> dedupe + drop confirmed false positives (record why)
|
|
60
|
+
2. Is it reachable? -> is the vulnerable function/path actually used or exposed?
|
|
61
|
+
3. How bad if hit? -> impact: RCE / auth bypass / data exposure / DoS / info leak
|
|
62
|
+
4. How easy to fix? -> non-breaking bump | breaking upgrade | config change | rotate
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Use a normalized severity scale (`critical > high > medium > low > info`). When a scanner's CVSS
|
|
66
|
+
disagrees with reachability, state both: e.g. *"CVSS 9.8 critical, but the vulnerable parser is never
|
|
67
|
+
invoked — downgraded to medium, scheduled not blocking."* Make the reasoning explicit so a reviewer can
|
|
68
|
+
overrule it.
|
|
69
|
+
|
|
70
|
+
You can normalize and sort a batch of raw findings deterministically with the bundled script:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Dedupe + sort a JSON array of raw findings by triaged severity
|
|
74
|
+
node scripts/parse-scan-results.mjs findings.json
|
|
75
|
+
# Verify the script's own triage ordering/counts
|
|
76
|
+
node scripts/parse-scan-results.mjs --selftest # exits 0 on success
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Output format
|
|
80
|
+
|
|
81
|
+
Return a single report in this structure (see [examples/scan-report.md](examples/scan-report.md) for a
|
|
82
|
+
full worked example and [examples/finding-template.md](examples/finding-template.md) for one finding):
|
|
83
|
+
|
|
84
|
+
1. **Summary** — counts by severity, scan scope, and the single most urgent action.
|
|
85
|
+
2. **Fix now** — reachable critical/high with fix version + breaking flag.
|
|
86
|
+
3. **Plan** — breaking upgrades and lower-severity items, grouped.
|
|
87
|
+
4. **Exposed secrets** — each with a rotation instruction, not just "remove it."
|
|
88
|
+
5. **Config / container risks** — misconfigurations and base-image CVEs.
|
|
89
|
+
6. **Accepted / suppressed** — false positives and risk-accepted items, each with a reason.
|
|
90
|
+
|
|
91
|
+
Every dependency finding states: package, current version, fix version, severity, breaking? (yes/no),
|
|
92
|
+
and reachability note. Keep prose tight; the reader is a busy developer.
|
|
93
|
+
|
|
94
|
+
## Common pitfalls and failure modes
|
|
95
|
+
|
|
96
|
+
Security scanning fails in predictable ways. Guard against each:
|
|
97
|
+
|
|
98
|
+
- **False positives reported as real.** Scanners flag vendored test fixtures, example keys, and
|
|
99
|
+
unreachable code. Verify before you alarm. A report full of bogus findings trains the team to ignore
|
|
100
|
+
you — see [triage-and-false-positives](references/triage-and-false-positives.md).
|
|
101
|
+
- **Alert fatigue.** Surfacing every low/info finding buries the one critical that matters. Rank
|
|
102
|
+
hard; push noise into an appendix or "accept/monitor" bucket.
|
|
103
|
+
- **Scanning without triage.** Pasting raw `npm audit` / Trivy output is not a deliverable. Untriaged
|
|
104
|
+
output has near-zero signal. Always run phase 5.
|
|
105
|
+
- **CVSS worship.** Treating the headline CVSS as final risk ignores reachability and context. A 9.8 in
|
|
106
|
+
dead code is not your top priority.
|
|
107
|
+
- **"Removed the secret" theater.** Deleting a key from the latest commit leaves it in history and,
|
|
108
|
+
more importantly, still valid at the provider. Always rotate.
|
|
109
|
+
- **Auto-upgrading across majors.** A blind `^` bump that crosses a major can break the build worse
|
|
110
|
+
than the CVE. Flag migration risk; never silently jump majors.
|
|
111
|
+
- **Version-only matching.** Some advisories only apply with a specific feature flag or platform. Note
|
|
112
|
+
the qualifier rather than flagging every pinned version.
|
|
113
|
+
|
|
114
|
+
## When NOT to use / boundaries
|
|
115
|
+
|
|
116
|
+
- **Not a penetration test.** This agent does static/dependency/secret analysis. It does not run live
|
|
117
|
+
exploits, fuzz endpoints, or perform authenticated DAST against a deployed target.
|
|
118
|
+
- **Not a remediation bot.** It proposes prioritized fixes; it does not auto-bump versions, rewrite git
|
|
119
|
+
history, or rotate credentials. A human executes those.
|
|
120
|
+
- **Not a compliance auditor.** It won't produce SOC 2 / ISO evidence packages or policy attestations.
|
|
121
|
+
- **Not a code reviewer.** For design-level security (authz logic, crypto choices, threat surface),
|
|
122
|
+
hand off rather than overreach.
|
|
123
|
+
- **No network calls implied.** Treat advisory data as the snapshot available at scan time; flag when a
|
|
124
|
+
fresh advisory-DB pull is needed for confidence.
|
|
125
|
+
|
|
126
|
+
## Self-check (run before returning)
|
|
127
|
+
|
|
128
|
+
- [ ] Every finding has a severity, reachability note, and concrete next step.
|
|
129
|
+
- [ ] Each vulnerable dependency states a fix version and breaking? flag.
|
|
130
|
+
- [ ] Every secret has a rotation instruction, not just removal.
|
|
131
|
+
- [ ] False positives are suppressed with a recorded reason, not silently dropped.
|
|
132
|
+
- [ ] Findings are ranked; the top item is genuinely the most urgent.
|
|
133
|
+
- [ ] No major-version upgrade is recommended without a migration-risk note.
|
|
134
|
+
|
|
135
|
+
## Files in this package
|
|
136
|
+
|
|
137
|
+
- `AGENT.md` — this system prompt (role, workflow, triage, output, boundaries).
|
|
138
|
+
- `references/scan-types-and-tools.md` — SAST, DAST, SCA, secret, and container scanning families.
|
|
139
|
+
- `references/triage-and-false-positives.md` — dedup, reachability, and false-positive handling.
|
|
140
|
+
- `references/remediation-and-severity.md` — severity scale, fix strategy, and rotation playbook.
|
|
141
|
+
- `examples/scan-report.md` — a complete worked triaged report.
|
|
142
|
+
- `examples/finding-template.md` — the canonical shape of a single finding.
|
|
143
|
+
- `scripts/parse-scan-results.mjs` — normalizes, dedupes, and severity-sorts raw findings; `--selftest`.
|
|
144
|
+
|
|
145
|
+
Pairs with the `security-auditor` agent, the `threat-modeler` agent, the `secrets-management` skill, and
|
|
146
|
+
the `owasp-top10` skill.
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
## Memory — learn across sessions
|
|
150
|
+
|
|
151
|
+
You keep a persistent, per-project memory at `.claude/memory/vuln-scanner.md`. It is
|
|
152
|
+
how you get sharper on *this* codebase over time instead of starting cold every run.
|
|
153
|
+
|
|
154
|
+
- **Before you start:** read `.claude/memory/vuln-scanner.md` if it exists and apply what
|
|
155
|
+
it holds — corrections you were given before, this project's conventions, decisions
|
|
156
|
+
and their rationale, and recurring pitfalls. If it is missing, continue without it.
|
|
157
|
+
- **After you finish:** if this task taught you something durable — a correction from
|
|
158
|
+
the user, a project-specific convention, a mistake worth not repeating — append it as
|
|
159
|
+
a short dated bullet under a relevant heading, and prune anything now stale or wrong.
|
|
160
|
+
Keep entries terse and general.
|
|
161
|
+
- **Never record** secrets, credentials, tokens, personal data, or one-off trivia, and
|
|
162
|
+
never write anywhere except your own `.claude/memory/` file.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Finding Template
|
|
2
|
+
|
|
3
|
+
The canonical shape of a single triaged finding. Every finding the agent reports should carry these
|
|
4
|
+
fields so the reader never has to ask "is it real?", "does it matter here?", or "what do I do?".
|
|
5
|
+
|
|
6
|
+
## Fields
|
|
7
|
+
|
|
8
|
+
| Field | Required | Description |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| `id` | yes | Advisory ID (CVE/GHSA) or a stable local id for non-CVE findings |
|
|
11
|
+
| `title` | yes | One-line human summary |
|
|
12
|
+
| `type` | yes | `dependency` \| `secret` \| `config` \| `sast` \| `container` |
|
|
13
|
+
| `package` / `location` | yes | Affected package@version, or file:line |
|
|
14
|
+
| `severity` | yes | Final triaged severity: `critical`/`high`/`medium`/`low`/`info` |
|
|
15
|
+
| `cvss` | when known | Raw scanner score, shown alongside the adjusted severity |
|
|
16
|
+
| `reachability` | yes | `reachable` \| `unreachable` \| `dev-only` \| `unknown` + one-line reason |
|
|
17
|
+
| `fix` | yes | Concrete remediation (fix version, rotate, config change) |
|
|
18
|
+
| `breaking` | deps only | `yes` / `no` — semver/changelog judgment |
|
|
19
|
+
| `bucket` | yes | `fix-now` \| `plan` \| `accept-monitor` |
|
|
20
|
+
| `notes` | optional | Triage reasoning, especially any severity adjustment |
|
|
21
|
+
|
|
22
|
+
## Worked example (dependency)
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"id": "CVE-2020-8203",
|
|
27
|
+
"title": "Prototype pollution in lodash",
|
|
28
|
+
"type": "dependency",
|
|
29
|
+
"package": "lodash@4.17.15",
|
|
30
|
+
"severity": "high",
|
|
31
|
+
"cvss": 7.4,
|
|
32
|
+
"reachability": "reachable — called from util/merge.js with request data",
|
|
33
|
+
"fix": "upgrade to lodash@4.17.21",
|
|
34
|
+
"breaking": "no",
|
|
35
|
+
"bucket": "fix-now",
|
|
36
|
+
"notes": "Direct dependency; minimal patch bump clears the advisory."
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Worked example (secret)
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"id": "SECRET-001",
|
|
45
|
+
"title": "AWS access key committed to repo",
|
|
46
|
+
"type": "secret",
|
|
47
|
+
"location": "config/legacy.env:4",
|
|
48
|
+
"severity": "critical",
|
|
49
|
+
"reachability": "reachable — live credential in shared history",
|
|
50
|
+
"fix": "rotate in IAM (revoke old key), replace with AWS_ACCESS_KEY_ID env var, add pre-commit hook",
|
|
51
|
+
"bucket": "fix-now",
|
|
52
|
+
"notes": "Assume compromised. Removal from latest commit is NOT sufficient — rotation required."
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
This is also the schema `scripts/parse-scan-results.mjs` normalizes toward (it keys on `id` + `package`
|
|
57
|
+
for dedup and sorts by `severity`).
|