vanara 0.1.0 → 0.2.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 +140 -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 +168 -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 +112 -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 +156 -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 +185 -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 +168 -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 +163 -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 +177 -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 +163 -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 +146 -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,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,146 @@
|
|
|
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.
|
|
@@ -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`).
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Example: Vulnerability Scan Report
|
|
2
|
+
|
|
3
|
+
A worked example of the report shape this agent produces. Note the structure: a tight summary, a short
|
|
4
|
+
*fix now* list, then everything else ranked below it. The raw scan had 47 findings; triage reduced the
|
|
5
|
+
release-blocking set to 3.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Summary
|
|
10
|
+
|
|
11
|
+
- **Scope:** npm dependencies (lockfile), source secret scan, Dockerfile base image.
|
|
12
|
+
- **Findings:** 1 critical, 2 high, 6 medium, 38 low/info (47 raw -> 9 actionable after triage).
|
|
13
|
+
- **Most urgent:** rotate the AWS key committed in `config/legacy.env` — assume compromised.
|
|
14
|
+
|
|
15
|
+
## Fix now (release-blocking)
|
|
16
|
+
|
|
17
|
+
| Item | Severity | Fix | Breaking? | Reachability |
|
|
18
|
+
|---|---|---|---|---|
|
|
19
|
+
| AWS access key in `config/legacy.env` | critical | rotate in IAM, move to env var | n/a | Live credential, public history |
|
|
20
|
+
| `lodash@4.17.15` (CVE-2020-8203) | high | -> `4.17.21` | no | Reachable via `util/merge.js` |
|
|
21
|
+
| `axios@0.21.0` (SSRF, CVE-2021-3749) | high | -> `0.21.4` | no | Used in outbound webhook client |
|
|
22
|
+
|
|
23
|
+
## Plan (schedule, not blocking)
|
|
24
|
+
|
|
25
|
+
- **`next@12 -> 14` (3 medium CVEs):** breaking major. Clears 3 advisories but requires app-router
|
|
26
|
+
migration review. Estimate: 1 sprint. Group as one coordinated upgrade.
|
|
27
|
+
- **`debug=true` in `config/prod.json`:** medium. Leaks stack traces to clients; set `false`.
|
|
28
|
+
- **6 transitive medium CVEs in dev-only deps:** real but build-time only; bump opportunistically.
|
|
29
|
+
|
|
30
|
+
## Exposed secrets
|
|
31
|
+
|
|
32
|
+
| Secret | Location | Action |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| AWS access key `AKIA…` | `config/legacy.env:4` | **Rotate** in IAM (revoke old), replace with `AWS_ACCESS_KEY_ID` env var, add pre-commit secret hook |
|
|
35
|
+
| Slack webhook URL | `scripts/notify.sh:12` | Rotate webhook in Slack, move to secret manager |
|
|
36
|
+
|
|
37
|
+
Removal from the latest commit is **not** sufficient — both are still valid at the provider.
|
|
38
|
+
|
|
39
|
+
## Config / container risks
|
|
40
|
+
|
|
41
|
+
- **Base image `node:18.0-alpine`:** carries 4 OS-package CVEs. Bump to current `node:18-alpine` patch.
|
|
42
|
+
- **Container runs as root:** add a non-root `USER` to the Dockerfile.
|
|
43
|
+
|
|
44
|
+
## Accepted / suppressed (with reason)
|
|
45
|
+
|
|
46
|
+
- **CVE-2025-XXXX in `fast-xml@3.1.0` (CVSS 9.8):** vulnerable `parseAttrs` path requires
|
|
47
|
+
`allowAttributes:true`; app uses defaults. Downgraded critical -> medium, scheduled.
|
|
48
|
+
- **`AKIAEXAMPLE…` in `docs/setup.md`:** documentation placeholder, not a live key. Suppressed.
|
|
49
|
+
- **CVE in `jest@…`:** dev/test-only dependency, not in production bundle. Backlog.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Remediation and Severity
|
|
2
|
+
|
|
3
|
+
Once a finding is triaged, the deliverable is a *fix the reader can act on*. This reference defines the
|
|
4
|
+
severity scale, the dependency-fix strategy, and the secret-rotation playbook.
|
|
5
|
+
|
|
6
|
+
## Severity scale
|
|
7
|
+
|
|
8
|
+
Use a single normalized scale across all scan families so the report is comparable:
|
|
9
|
+
|
|
10
|
+
| Severity | Meaning | Default action |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `critical` | Reachable RCE, auth bypass, or active secret leak | Block release; fix now |
|
|
13
|
+
| `high` | Serious impact, exploitable with moderate effort | Fix before release |
|
|
14
|
+
| `medium` | Real but constrained (limited reach or impact) | Schedule next sprint |
|
|
15
|
+
| `low` | Minor / hardening | Backlog |
|
|
16
|
+
| `info` | Awareness only | No action required |
|
|
17
|
+
|
|
18
|
+
Final severity = scanner severity **adjusted by reachability and impact** (see
|
|
19
|
+
[triage-and-false-positives](triage-and-false-positives.md)). Always show your adjustment reasoning.
|
|
20
|
+
|
|
21
|
+
## Dependency remediation strategy
|
|
22
|
+
|
|
23
|
+
For every vulnerable dependency, state the fix version and whether it's breaking:
|
|
24
|
+
|
|
25
|
+
1. **Prefer the minimal bump that clears the CVE.** If `1.2.3 -> 1.2.4` fixes it, recommend that, not
|
|
26
|
+
the latest 3.x.
|
|
27
|
+
2. **Label breaking vs. non-breaking** by semver distance and changelog. Crossing a major is breaking
|
|
28
|
+
until proven otherwise.
|
|
29
|
+
3. **Transitive deps:** if you don't own the dependency directly, fix via the parent bump, or a
|
|
30
|
+
lockfile override / resolution (`overrides` in npm, `resolutions` in yarn/pnpm) — and flag overrides
|
|
31
|
+
as a temporary measure, not a permanent pin.
|
|
32
|
+
4. **Group breaking upgrades separately** under *plan* with a migration-risk note. Never bundle a risky
|
|
33
|
+
major bump into a "quick fix" list.
|
|
34
|
+
5. **No fix available?** Document the mitigation (disable the feature, add input validation, network
|
|
35
|
+
isolation) and mark for monitoring.
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
Fix-now bucket -> non-breaking bumps that clear critical/high, reachable
|
|
39
|
+
Plan bucket -> breaking upgrades, lower-severity, or coordinated changes
|
|
40
|
+
Accept/monitor -> no fix yet, or risk-accepted with justification
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Secret remediation — rotation, not removal
|
|
44
|
+
|
|
45
|
+
A committed secret is compromised the moment it lands in a shared repo. The fix is always:
|
|
46
|
+
|
|
47
|
+
1. **Rotate first.** Issue a new credential at the provider and revoke the old one. Until this is done,
|
|
48
|
+
the secret is live regardless of repo state.
|
|
49
|
+
2. **Remove from code.** Replace with an env var or secret-manager reference.
|
|
50
|
+
3. **Purge from history** if required (history rewrite or, more often, treat as exposed and rely on
|
|
51
|
+
rotation — rewriting shared history is disruptive and incomplete if the repo was cloned/forked).
|
|
52
|
+
4. **Add prevention.** A pre-commit secret hook and a `.gitignore` entry so it doesn't recur.
|
|
53
|
+
|
|
54
|
+
> "Deleted the key in the latest commit" is **not** remediation. The credential is still valid at the
|
|
55
|
+
> provider and still present in every prior commit, clone, and CI cache.
|
|
56
|
+
|
|
57
|
+
## Writing the remediation line
|
|
58
|
+
|
|
59
|
+
Each finding's recommendation should be copy-pasteable and unambiguous:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
lodash 4.17.15 -> 4.17.21 | high | non-breaking | prototype-pollution CVE-2020-8203, reachable in util/merge.js
|
|
63
|
+
AWS key in config/old.env | critical | rotate | revoke in IAM, replace with env var, add pre-commit hook
|
|
64
|
+
debug=true in prod config | medium | config | set debug=false; leaks stack traces to clients
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Tie remediation effort to severity so the reader can plan: a *fix now* of ten non-breaking bumps is an
|
|
68
|
+
afternoon; one breaking major in *plan* may be a sprint. Make that tradeoff visible.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Scan Types and Tools
|
|
2
|
+
|
|
3
|
+
Vulnerability scanning is not one activity — it is a family of complementary techniques, each with a
|
|
4
|
+
different blind spot. A credible scan combines several. Use this reference to pick the right family for
|
|
5
|
+
the target and to understand what each one *cannot* see.
|
|
6
|
+
|
|
7
|
+
## SCA — Software Composition Analysis (dependency scanning)
|
|
8
|
+
|
|
9
|
+
Matches your resolved dependency versions against known-vulnerability databases (CVE/NVD, GitHub
|
|
10
|
+
Advisory, OSV).
|
|
11
|
+
|
|
12
|
+
- **Inputs:** lockfiles (`package-lock.json`, `pnpm-lock.yaml`, `poetry.lock`, `Cargo.lock`, `go.sum`).
|
|
13
|
+
Always read the **lockfile**, not the manifest range — `^1.2.0` tells you nothing about what shipped.
|
|
14
|
+
- **Strengths:** high-precision for *known* CVEs; cheap; covers transitive deps.
|
|
15
|
+
- **Blind spots:** zero-days, logic bugs, anything not yet in an advisory DB. Version-only matching can
|
|
16
|
+
over-report (advisory may need a specific feature flag).
|
|
17
|
+
- **Triage hook:** flag direct vs. transitive — a transitive CVE may be fixable only by bumping the
|
|
18
|
+
parent, or pinning via an override/resolution.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Inventory before judging — never trust the manifest range alone
|
|
22
|
+
node -e "const l=require('./package-lock.json');console.log(Object.keys(l.packages||{}).length,'resolved packages')"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Secret scanning
|
|
26
|
+
|
|
27
|
+
Finds credentials committed to the repo: API keys, tokens, private keys, connection strings,
|
|
28
|
+
high-entropy blobs.
|
|
29
|
+
|
|
30
|
+
- **Inputs:** working tree by default; git history when explicitly requested.
|
|
31
|
+
- **Detection:** known-format regexes (e.g. `AKIA…` AWS keys, `ghp_…` GitHub tokens, `-----BEGIN ...
|
|
32
|
+
PRIVATE KEY-----`) plus entropy heuristics.
|
|
33
|
+
- **Blind spots:** secrets in untracked files, encrypted blobs, or rotated-but-still-referenced values.
|
|
34
|
+
- **Critical rule:** a found secret is assumed compromised. Removal ≠ remediation. See
|
|
35
|
+
[remediation-and-severity](remediation-and-severity.md) for the rotation playbook.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Cheap first pass for common key formats (illustrative — a real scan uses a tool)
|
|
39
|
+
grep -rERn 'AKIA[0-9A-Z]{16}|ghp_[A-Za-z0-9]{36}|-----BEGIN [A-Z ]*PRIVATE KEY-----' . \
|
|
40
|
+
--include='*.*' || echo "no obvious key-format matches"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## SAST — Static Application Security Testing
|
|
44
|
+
|
|
45
|
+
Analyzes source/AST for vulnerable patterns: injection sinks, unsafe deserialization, path traversal,
|
|
46
|
+
hardcoded crypto, tainted-data flows.
|
|
47
|
+
|
|
48
|
+
- **Strengths:** finds bugs in *your* code, not just dependencies; runs without deploying.
|
|
49
|
+
- **Blind spots:** high false-positive rate; struggles with dynamic dispatch and framework magic;
|
|
50
|
+
cannot judge runtime config.
|
|
51
|
+
- **Triage hook:** SAST output needs the heaviest false-positive filtering. Confirm the sink is
|
|
52
|
+
reachable with attacker-controlled input before alarming.
|
|
53
|
+
|
|
54
|
+
## DAST — Dynamic Application Security Testing
|
|
55
|
+
|
|
56
|
+
Probes a *running* application from the outside: injection, auth handling, misconfigured headers, TLS.
|
|
57
|
+
|
|
58
|
+
- **Strengths:** finds runtime/config issues SAST can't see; low false positives for what it confirms.
|
|
59
|
+
- **Blind spots:** only covers exercised endpoints; needs a deployed target; can be destructive.
|
|
60
|
+
- **Boundary:** this agent does **not** perform live DAST/exploitation — that is a pen-test activity.
|
|
61
|
+
Note when DAST is warranted and hand off.
|
|
62
|
+
|
|
63
|
+
## Container & IaC scanning
|
|
64
|
+
|
|
65
|
+
When a `Dockerfile`, image, or infra-as-code (Terraform, Kubernetes manifests) is present:
|
|
66
|
+
|
|
67
|
+
- **Base-image CVEs:** OS packages in the image carry their own advisories; a clean app on a stale base
|
|
68
|
+
image is still vulnerable.
|
|
69
|
+
- **Image hygiene:** running as root, secrets baked into layers, unpinned `latest` tags.
|
|
70
|
+
- **IaC misconfig:** public S3 buckets, `0.0.0.0/0` security groups, disabled encryption.
|
|
71
|
+
|
|
72
|
+
## Choosing per target
|
|
73
|
+
|
|
74
|
+
| Target present | Run | Primary risk caught |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| Lockfile | SCA | Known CVEs in deps |
|
|
77
|
+
| Any source | Secret scan + SAST | Leaked creds, injection sinks |
|
|
78
|
+
| Dockerfile / image | Container scan | Base-image CVEs, root, baked secrets |
|
|
79
|
+
| Terraform / k8s | IaC scan | Public exposure, weak crypto config |
|
|
80
|
+
| Deployed URL | DAST (hand off) | Runtime/config exploits |
|
|
81
|
+
|
|
82
|
+
No single family is sufficient. Combine, then triage everything through
|
|
83
|
+
[triage-and-false-positives](triage-and-false-positives.md).
|