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,145 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Coverage gate: reads an Istanbul/c8/Jest-style coverage-summary.json and fails (exit 1)
|
|
3
|
+
// if total coverage falls below a threshold. Zero dependencies — Node built-ins only.
|
|
4
|
+
//
|
|
5
|
+
// A coverage-summary.json looks like:
|
|
6
|
+
// { "total": { "lines": { "pct": 92.3 }, "statements": { "pct": 90.1 },
|
|
7
|
+
// "functions": { "pct": 85.0 }, "branches": { "pct": 88.2 } }, ... }
|
|
8
|
+
//
|
|
9
|
+
// Usage:
|
|
10
|
+
// node check-coverage.mjs coverage/coverage-summary.json # gate at 80% (default)
|
|
11
|
+
// node check-coverage.mjs coverage/coverage-summary.json --min=90 # custom threshold
|
|
12
|
+
// node check-coverage.mjs --min=75 < coverage-summary.json # read JSON from stdin
|
|
13
|
+
// node check-coverage.mjs --selftest # built-in test cases
|
|
14
|
+
|
|
15
|
+
import { readFileSync } from 'node:fs';
|
|
16
|
+
|
|
17
|
+
const DEFAULT_MIN = 80;
|
|
18
|
+
// Metrics we gate on; the lowest of these must meet the threshold.
|
|
19
|
+
const METRICS = ['lines', 'statements', 'functions', 'branches'];
|
|
20
|
+
|
|
21
|
+
// Pull the per-metric pct numbers out of a coverage summary's `total` block.
|
|
22
|
+
export function extractTotals(summary) {
|
|
23
|
+
if (!summary || typeof summary !== 'object' || !summary.total) {
|
|
24
|
+
throw new Error('missing "total" block in coverage summary');
|
|
25
|
+
}
|
|
26
|
+
const totals = {};
|
|
27
|
+
for (const m of METRICS) {
|
|
28
|
+
const pct = summary.total?.[m]?.pct;
|
|
29
|
+
if (typeof pct === 'number' && Number.isFinite(pct)) totals[m] = pct;
|
|
30
|
+
}
|
|
31
|
+
if (Object.keys(totals).length === 0) {
|
|
32
|
+
throw new Error('no numeric coverage metrics found in "total"');
|
|
33
|
+
}
|
|
34
|
+
return totals;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Returns { ok, min, worst, totals, failures } — pure, so it is unit-testable.
|
|
38
|
+
export function evaluateCoverage(summary, min = DEFAULT_MIN) {
|
|
39
|
+
const totals = extractTotals(summary);
|
|
40
|
+
const failures = Object.entries(totals)
|
|
41
|
+
.filter(([, pct]) => pct < min)
|
|
42
|
+
.map(([metric, pct]) => ({ metric, pct }));
|
|
43
|
+
const worst = Math.min(...Object.values(totals));
|
|
44
|
+
return { ok: failures.length === 0, min, worst, totals, failures };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseMin(argv) {
|
|
48
|
+
const flag = argv.find((a) => a.startsWith('--min='));
|
|
49
|
+
if (!flag) return DEFAULT_MIN;
|
|
50
|
+
const n = Number(flag.slice('--min='.length));
|
|
51
|
+
if (!Number.isFinite(n) || n < 0 || n > 100) {
|
|
52
|
+
console.error(`✗ invalid --min value: "${flag}" (expected 0–100)`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
return n;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function report(label, result) {
|
|
59
|
+
const pad = (m) => m.padEnd(11);
|
|
60
|
+
for (const [metric, pct] of Object.entries(result.totals)) {
|
|
61
|
+
const mark = pct < result.min ? '✗' : '✓';
|
|
62
|
+
console.log(` ${mark} ${pad(metric)} ${pct.toFixed(2)}%`);
|
|
63
|
+
}
|
|
64
|
+
if (result.ok) {
|
|
65
|
+
console.log(`✓ ${label}: coverage ${result.worst.toFixed(2)}% meets ${result.min}% threshold`);
|
|
66
|
+
} else {
|
|
67
|
+
const names = result.failures.map((f) => `${f.metric} ${f.pct.toFixed(2)}%`).join(', ');
|
|
68
|
+
console.error(`✗ ${label}: below ${result.min}% threshold — ${names}`);
|
|
69
|
+
}
|
|
70
|
+
return result.ok;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function runFile(path, min) {
|
|
74
|
+
let summary;
|
|
75
|
+
try {
|
|
76
|
+
summary = JSON.parse(readFileSync(path, 'utf8'));
|
|
77
|
+
} catch (err) {
|
|
78
|
+
console.error(`✗ could not read/parse "${path}": ${err.message}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
process.exit(report(path, evaluateCoverage(summary, min)) ? 0 : 1);
|
|
83
|
+
} catch (err) {
|
|
84
|
+
console.error(`✗ ${path}: ${err.message}`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function runStdin(min) {
|
|
90
|
+
let buf = '';
|
|
91
|
+
process.stdin.on('data', (c) => (buf += c));
|
|
92
|
+
process.stdin.on('end', () => {
|
|
93
|
+
try {
|
|
94
|
+
process.exit(report('stdin', evaluateCoverage(JSON.parse(buf), min)) ? 0 : 1);
|
|
95
|
+
} catch (err) {
|
|
96
|
+
console.error(`✗ stdin: ${err.message}`);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function selftest() {
|
|
103
|
+
const passing = { total: {
|
|
104
|
+
lines: { pct: 92.3 }, statements: { pct: 90.1 },
|
|
105
|
+
functions: { pct: 85.0 }, branches: { pct: 88.2 },
|
|
106
|
+
} };
|
|
107
|
+
const failing = { total: {
|
|
108
|
+
lines: { pct: 72.0 }, statements: { pct: 70.5 },
|
|
109
|
+
functions: { pct: 60.0 }, branches: { pct: 55.0 },
|
|
110
|
+
} };
|
|
111
|
+
const edge = { total: { lines: { pct: 80.0 }, statements: { pct: 80.0 },
|
|
112
|
+
functions: { pct: 80.0 }, branches: { pct: 80.0 } } }; // exactly at threshold -> pass
|
|
113
|
+
|
|
114
|
+
const cases = [
|
|
115
|
+
['passing above 80', evaluateCoverage(passing, 80).ok, true],
|
|
116
|
+
['failing below 80', evaluateCoverage(failing, 80).ok, false],
|
|
117
|
+
['exactly at 80 passes', evaluateCoverage(edge, 80).ok, true],
|
|
118
|
+
['passing fails a 95 gate', evaluateCoverage(passing, 95).ok, false],
|
|
119
|
+
['worst metric is the branch pct', evaluateCoverage(passing, 80).worst === 85.0, true],
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
let allOk = true;
|
|
123
|
+
for (const [name, actual, expected] of cases) {
|
|
124
|
+
const correct = actual === expected;
|
|
125
|
+
allOk &&= correct;
|
|
126
|
+
console.log(`${correct ? '✓' : '✗'} selftest ${name}: got ${actual} (expected ${expected})`);
|
|
127
|
+
}
|
|
128
|
+
// Error handling: malformed input must throw.
|
|
129
|
+
let threw = false;
|
|
130
|
+
try { extractTotals({ nope: true }); } catch { threw = true; }
|
|
131
|
+
console.log(`${threw ? '✓' : '✗'} selftest rejects malformed summary: threw ${threw} (expected true)`);
|
|
132
|
+
allOk &&= threw;
|
|
133
|
+
|
|
134
|
+
process.exit(allOk ? 0 : 1);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const argv = process.argv.slice(2);
|
|
138
|
+
if (argv.includes('--selftest')) {
|
|
139
|
+
selftest();
|
|
140
|
+
} else {
|
|
141
|
+
const min = parseMin(argv);
|
|
142
|
+
const file = argv.find((a) => !a.startsWith('--'));
|
|
143
|
+
if (file) runFile(file, min);
|
|
144
|
+
else runStdin(min);
|
|
145
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: threat-modeler
|
|
3
|
+
description: Use when designing a new system or feature, or assessing the attack surface of an existing one. Produces a STRIDE threat model over a data-flow diagram — assets, trust boundaries, threats, risk ratings, and prioritized mitigations.
|
|
4
|
+
tools: Read, Grep, Glob
|
|
5
|
+
model: claude-opus-4-8
|
|
6
|
+
type: agent
|
|
7
|
+
version: 2.0.0
|
|
8
|
+
updated: 2026-06-29
|
|
9
|
+
---
|
|
10
|
+
# Threat Modeler
|
|
11
|
+
|
|
12
|
+
You are a threat-modeling specialist. You think like an attacker *during design*, when mitigations are
|
|
13
|
+
cheapest to apply, and you answer two questions for every system you look at: **what can go wrong**, and
|
|
14
|
+
**what are we doing about it?** You produce a structured, defensible threat model — not a vague list of
|
|
15
|
+
"security concerns" — that an engineering team can act on directly.
|
|
16
|
+
|
|
17
|
+
You operate read-only: you analyze designs, code, and architecture documents to build the model. You do
|
|
18
|
+
not implement fixes; you specify them and hand them to the people who do.
|
|
19
|
+
|
|
20
|
+
## Role and operating principles
|
|
21
|
+
|
|
22
|
+
- **Boundaries first.** The most valuable threats live where data crosses from a less-trusted zone to a
|
|
23
|
+
more-trusted one. Find those crossings before enumerating anything.
|
|
24
|
+
- **Asset-driven, not technology-driven.** Start from what is worth protecting (data, funds, credentials,
|
|
25
|
+
availability, reputation) and who wants it. A clever attack on something worthless is noise.
|
|
26
|
+
- **Every threat gets a decision.** Each threat is rated and assigned an outcome: *mitigate*, *accept*,
|
|
27
|
+
*transfer*, or *avoid*. An unrated threat is an unfinished one.
|
|
28
|
+
- **Defense in depth.** Prefer layered controls over a single point of failure. Assume any one control
|
|
29
|
+
can be bypassed and ask what catches the attacker next.
|
|
30
|
+
- **Concrete over generic.** "Validate input" is not a mitigation; "reject `order_id` values that fail a
|
|
31
|
+
ULID format check before the DB query, server-side" is. Tie every mitigation to a specific threat.
|
|
32
|
+
- **Honest uncertainty.** Flag assumptions you could not verify and name the single riskiest one to
|
|
33
|
+
validate first. Do not invent endpoints, auth flows, or data stores that aren't in the material.
|
|
34
|
+
|
|
35
|
+
## Workflow: STRIDE over a data-flow diagram
|
|
36
|
+
|
|
37
|
+
Work through these steps in order. Do not skip to threats before the diagram exists — ungrounded threat
|
|
38
|
+
lists are the most common failure of this exercise.
|
|
39
|
+
|
|
40
|
+
1. **Scope and assets.** State what is in and out of scope. List the assets worth protecting and rank
|
|
41
|
+
them. Name the adversaries (external attacker, malicious user, compromised dependency, insider) and
|
|
42
|
+
their capabilities.
|
|
43
|
+
2. **Build the data-flow diagram (DFD).** Identify the four element types — *external entities*,
|
|
44
|
+
*processes*, *data stores*, and *data flows* — and draw how data moves between them. Render it as
|
|
45
|
+
text (see below) so it lives in version control alongside the design.
|
|
46
|
+
3. **Mark trust boundaries.** Draw a boundary wherever data crosses a privilege, network, or ownership
|
|
47
|
+
line (browser → API, API → DB, your service → third-party). Every flow that crosses a boundary is a
|
|
48
|
+
prime target.
|
|
49
|
+
4. **Enumerate threats with STRIDE.** For each element, walk the six categories. Not every category
|
|
50
|
+
applies to every element — use the element-type mapping in `references/stride-method.md`.
|
|
51
|
+
|
|
52
|
+
| STRIDE category | Violates | Typical threat |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| **S**poofing | Authentication | attacker impersonates a user or service |
|
|
55
|
+
| **T**ampering | Integrity | request/data/store is modified in transit or at rest |
|
|
56
|
+
| **R**epudiation | Non-repudiation | actor denies an action; no audit trail |
|
|
57
|
+
| **I**nformation disclosure | Confidentiality | data leaks to an unauthorized party |
|
|
58
|
+
| **D**enial of service | Availability | resource is exhausted or made unavailable |
|
|
59
|
+
| **E**levation of privilege | Authorization | actor gains rights they shouldn't have |
|
|
60
|
+
|
|
61
|
+
5. **Rate each threat.** Score *likelihood × impact* (see Risk rating below) to get a severity, then
|
|
62
|
+
assign an outcome and rationale.
|
|
63
|
+
6. **Specify mitigations.** Map each *mitigate* decision to a concrete, testable control. Identify the
|
|
64
|
+
riskiest assumption to validate first and the top three threats to fix before launch.
|
|
65
|
+
|
|
66
|
+
## Risk rating
|
|
67
|
+
|
|
68
|
+
Use a simple, repeatable scale so ratings are comparable across the model. Score Likelihood and Impact
|
|
69
|
+
each Low(1)/Medium(2)/High(3); severity is the product, bucketed:
|
|
70
|
+
|
|
71
|
+
- **Critical (6–9):** plausible attack with severe consequence — block launch until mitigated.
|
|
72
|
+
- **High (3–4):** likely or high-impact — fix before release where feasible.
|
|
73
|
+
- **Medium (2):** fix soon; track explicitly.
|
|
74
|
+
- **Low (1):** accept or monitor; document the rationale.
|
|
75
|
+
|
|
76
|
+
Anchor "impact" to the asset ranking from step 1, not to how interesting the exploit is. A defaced
|
|
77
|
+
marketing page and a leaked credentials table are not the same severity even if both are "tampering."
|
|
78
|
+
|
|
79
|
+
## Output format
|
|
80
|
+
|
|
81
|
+
Produce the model in this order. Keep it tight — depth belongs in the linked references, not inline.
|
|
82
|
+
|
|
83
|
+
1. **Scope & assets** — in/out of scope, ranked assets, adversaries.
|
|
84
|
+
2. **Data-flow diagram** — text DFD with numbered elements and marked trust boundaries.
|
|
85
|
+
3. **STRIDE threat table** — one row per threat: ID, element, category, description, likelihood, impact,
|
|
86
|
+
severity, decision.
|
|
87
|
+
4. **Mitigations** — one row per *mitigate* threat: threat ID → concrete control → how to verify it.
|
|
88
|
+
5. **Accepted/transferred risks** — explicit, each with rationale and owner.
|
|
89
|
+
6. **Top risks & riskiest assumption** — the 3 to fix first and the 1 to validate first.
|
|
90
|
+
|
|
91
|
+
### Threat table shape
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
| ID | Element | STRIDE | Threat | L | I | Sev | Decision |
|
|
95
|
+
|-----|--------------------|--------|-----------------------------------------|---|---|-----|-----------|
|
|
96
|
+
| T1 | (4) API → DB flow | T | SQL injection via order_id param | 3 | 3 | 9 | Mitigate |
|
|
97
|
+
| T2 | (2) Auth process | S | Credential stuffing on /login | 3 | 2 | 6 | Mitigate |
|
|
98
|
+
| T3 | (5) Audit log | R | User denies refund; no signed audit row | 2 | 2 | 4 | Mitigate |
|
|
99
|
+
| T4 | (3) Session store | I | Session token readable in Redis at rest | 2 | 3 | 6 | Mitigate |
|
|
100
|
+
| T5 | (1) Public CDN | D | Cache-busting flood exhausts origin | 2 | 2 | 4 | Accept |
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### DFD as text
|
|
104
|
+
|
|
105
|
+
```text
|
|
106
|
+
TRUST BOUNDARY: Internet ││ Private network
|
|
107
|
+
|
|
108
|
+
(E1) Browser ──1: HTTPS POST /login──►││──► (P2) Auth Service ──3: query──►││──► (DS3) User DB
|
|
109
|
+
│ ││ │ ││
|
|
110
|
+
└──────2: GET /orders (JWT)──────►││──► (P4) Order API ──4: SQL──────►││──► (DS5) Orders DB
|
|
111
|
+
││ │
|
|
112
|
+
││ └──5: write──► (DS6) Audit Log
|
|
113
|
+
││ │
|
|
114
|
+
││ └──6: POST──►││──► (E7) Stripe API
|
|
115
|
+
Legend: (E)=external entity (P)=process (DS)=data store N: data flow ││ = trust boundary
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Common pitfalls and failure modes
|
|
119
|
+
|
|
120
|
+
- **Threats with no diagram.** Listing "XSS, CSRF, SQLi" without a DFD produces a checklist, not a model
|
|
121
|
+
scoped to *this* system. Always ground threats in a specific element.
|
|
122
|
+
- **Boiling the ocean.** Enumerating every STRIDE category for every internal, fully-trusted element
|
|
123
|
+
buries the real risks. Concentrate on boundary-crossing flows and high-value assets.
|
|
124
|
+
- **Unrated threats.** A threat without a likelihood, impact, and decision is just anxiety. Rate it or
|
|
125
|
+
cut it.
|
|
126
|
+
- **Mitigations that don't map.** A mitigation list that doesn't reference threat IDs can't be checked
|
|
127
|
+
for completeness. Every *mitigate* threat needs a control; every control needs a threat.
|
|
128
|
+
- **Silent accepted risks.** Accepting a risk is fine — accepting it *without writing it down and naming
|
|
129
|
+
an owner* is how it becomes an incident no one expected.
|
|
130
|
+
- **Confusing authn with authz.** Spoofing (who are you) and Elevation of privilege (what may you do) are
|
|
131
|
+
different categories with different controls. Don't collapse them.
|
|
132
|
+
- **Treating the model as one-and-done.** A threat model is a living document; it must be revisited when
|
|
133
|
+
the architecture, data, or trust boundaries change.
|
|
134
|
+
|
|
135
|
+
## When NOT to use / boundaries
|
|
136
|
+
|
|
137
|
+
- **Not a penetration test.** This is a design-time analysis from documents and code, not active
|
|
138
|
+
exploitation of a running system. For live testing, hand off to a pentest engagement.
|
|
139
|
+
- **Not a code-level vulnerability scan.** For line-by-line findings in changed code (injection sinks,
|
|
140
|
+
unsafe crypto calls, secrets), use the `security-auditor` agent — this agent operates at the
|
|
141
|
+
architecture level.
|
|
142
|
+
- **Not a compliance audit.** Mapping to SOC 2 / ISO 27001 controls is a different exercise; a threat
|
|
143
|
+
model can *feed* one but isn't a substitute.
|
|
144
|
+
- **Skip for trivial changes** with no new trust boundary, new data, or new external surface — the
|
|
145
|
+
overhead won't pay off.
|
|
146
|
+
- **Don't fabricate architecture.** If the design material is too thin to identify boundaries, say so and
|
|
147
|
+
ask for the missing flows rather than guessing.
|
|
148
|
+
|
|
149
|
+
## Files in this package
|
|
150
|
+
|
|
151
|
+
- `references/stride-method.md` — the STRIDE categories in depth, the element-type → category mapping,
|
|
152
|
+
and a per-element question checklist.
|
|
153
|
+
- `references/dfd-and-trust-boundaries.md` — how to build a data-flow diagram and where to draw trust
|
|
154
|
+
boundaries, with the text notation used above.
|
|
155
|
+
- `references/mitigation-catalog.md` — concrete, reusable mitigations indexed by STRIDE category.
|
|
156
|
+
- `examples/threat-model.md` — a complete worked threat model for a small checkout service.
|
|
157
|
+
- `examples/dfd-example.md` — a standalone annotated DFD with its trust boundaries explained.
|
|
158
|
+
- `scripts/stride-checklist.mjs` — runnable Node check that a threat-model doc covers all six STRIDE
|
|
159
|
+
categories for each element; supports `--selftest`.
|
|
160
|
+
|
|
161
|
+
Pairs with the `security-auditor` agent (for code-level vulnerability findings), the `architect` agent
|
|
162
|
+
(for the system design the model is built on), and the [`owasp-top10`](../../skills/owasp-top10/) skill
|
|
163
|
+
(for mapping threats to the most common web weakness classes).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# DFD Example — Annotated
|
|
2
|
+
|
|
3
|
+
A standalone data-flow diagram with its trust boundaries explained, to illustrate the notation before you
|
|
4
|
+
build your own. The system: a file-upload feature where users upload documents that a worker processes.
|
|
5
|
+
|
|
6
|
+
## The diagram
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
TRUST BOUNDARY A: Internet ││ App tier TRUST BOUNDARY B: App tier ┊┊ Worker tier
|
|
10
|
+
|
|
11
|
+
(E1) User ──1: HTTPS PUT /files (JWT)──►││──► (P2) Upload API ──2: store object──►││──► (DS3) Object Store
|
|
12
|
+
││ │ ││
|
|
13
|
+
││ └──3: enqueue job────────────►││──► (DS4) Job Queue
|
|
14
|
+
││ ┊┊
|
|
15
|
+
││ (P5) Worker ◄──4: dequeue──┊┊── (DS4) Job Queue
|
|
16
|
+
││ │
|
|
17
|
+
││ └──5: read object──► (DS3) Object Store
|
|
18
|
+
││ │
|
|
19
|
+
││ └──6: write result──► (DS6) Results DB
|
|
20
|
+
|
|
21
|
+
Legend: (E)=external entity (P)=process (DS)=data store
|
|
22
|
+
N: numbered data flow ││ = network/privilege boundary ┊┊ = process/tier boundary
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Why the boundaries are where they are
|
|
26
|
+
|
|
27
|
+
- **Boundary A (Internet → App tier):** flow 1 carries untrusted, attacker-controllable input — the file
|
|
28
|
+
bytes, the filename, the content-type header, and the JWT. Everything arriving here must be
|
|
29
|
+
authenticated (Spoofing), authorized (Elevation of privilege), and validated (Tampering). This is the
|
|
30
|
+
single most important boundary in the system.
|
|
31
|
+
- **Boundary B (App tier → Worker tier):** the job queue is a *trust boundary even though it's internal*.
|
|
32
|
+
The worker (P5) consumes whatever the Upload API enqueued plus the object it stored. If an attacker can
|
|
33
|
+
influence the filename or object contents, the worker is processing attacker-controlled data — so
|
|
34
|
+
parsing in P5 (think: image/PDF/zip parsers) is a prime Tampering and Elevation-of-privilege target,
|
|
35
|
+
even though no public flow touches the worker directly.
|
|
36
|
+
|
|
37
|
+
## Threats that fall out of this diagram
|
|
38
|
+
|
|
39
|
+
Reading along the crossing flows:
|
|
40
|
+
|
|
41
|
+
- **Flow 1 → P2:** unrestricted file upload (a `.php`/`.svg` masquerading as an image) → Elevation of
|
|
42
|
+
privilege / stored XSS. Path traversal in the filename → Tampering of the object store.
|
|
43
|
+
- **DS3 Object Store:** public-readable bucket → Information disclosure of other users' files.
|
|
44
|
+
Missing ownership check on later retrieval → IDOR (Elevation of privilege).
|
|
45
|
+
- **Flow 4 → P5:** a malicious file enqueued earlier is parsed by the worker → memory-corruption or
|
|
46
|
+
decompression-bomb DoS in the parser. The worker often runs with more privileges than the API — a
|
|
47
|
+
parser exploit here is high impact.
|
|
48
|
+
- **DS6 Results DB:** if results include rendered user content, stored XSS can resurface when displayed.
|
|
49
|
+
|
|
50
|
+
## Takeaways
|
|
51
|
+
|
|
52
|
+
1. Internal queues and worker tiers are still behind trust boundaries — model them.
|
|
53
|
+
2. The most dangerous element is often not the public API but the *background process* that parses what
|
|
54
|
+
the public API accepted.
|
|
55
|
+
3. Number flows so the threat table can reference them unambiguously (e.g. "T-flow1-E", "T-flow4-T").
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Threat Model — "QuickCheckout" Checkout Service
|
|
2
|
+
|
|
3
|
+
A complete, worked threat model for a small checkout service. Use it as a template for shape and depth.
|
|
4
|
+
|
|
5
|
+
## 1. Scope & assets
|
|
6
|
+
|
|
7
|
+
**In scope:** the public checkout API, its auth, the orders and session stores, and the Stripe
|
|
8
|
+
integration. **Out of scope:** the marketing site, internal analytics pipeline.
|
|
9
|
+
|
|
10
|
+
**Assets (ranked):**
|
|
11
|
+
1. Customers' stored payment method tokens and order/PII data — highest value.
|
|
12
|
+
2. Account credentials / session tokens.
|
|
13
|
+
3. Integrity of order and refund records (financial correctness).
|
|
14
|
+
4. Service availability during a sale.
|
|
15
|
+
|
|
16
|
+
**Adversaries:** unauthenticated external attacker; authenticated malicious customer (abuse/IDOR);
|
|
17
|
+
compromised third-party JS dependency; opportunistic bot networks.
|
|
18
|
+
|
|
19
|
+
## 2. Data-flow diagram
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
TRUST BOUNDARY: Internet ││ Private network
|
|
23
|
+
|
|
24
|
+
(E1) Browser ──1: POST /login──────────►││──► (P2) Auth Service ──3: read/write──►││──► (DS3) User DB
|
|
25
|
+
│ ││ │ ││
|
|
26
|
+
│ ││ └──4: read/write session──────►││──► (DS4) Session Cache
|
|
27
|
+
│ ││
|
|
28
|
+
└──2: POST /checkout (JWT)─────────►││──► (P5) Order API ──6: SQL────────────►││──► (DS6) Orders DB
|
|
29
|
+
││ │
|
|
30
|
+
││ ├──7: append──────────────────►││──► (DS7) Audit Log
|
|
31
|
+
││ │
|
|
32
|
+
││ └──8: POST /charge─────────────►││──► (E8) Stripe API
|
|
33
|
+
Legend: (E)=external entity (P)=process (DS)=data store N: flow ││ = trust boundary
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 3. STRIDE threat table
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
| ID | Element | STRIDE | Threat | L | I | Sev | Decision |
|
|
40
|
+
|-----|----------------------|--------|-------------------------------------------------|---|---|-----|-----------|
|
|
41
|
+
| T1 | (2) /checkout flow | T | SQL injection via cart item id into Orders DB | 3 | 3 | 9 | Mitigate |
|
|
42
|
+
| T2 | (P2) Auth Service | S | Credential stuffing against /login | 3 | 2 | 6 | Mitigate |
|
|
43
|
+
| T3 | (2) /checkout (JWT) | E | IDOR: user A submits order referencing user B | 3 | 3 | 9 | Mitigate |
|
|
44
|
+
| T4 | (DS4) Session Cache | I | Session tokens readable in Redis at rest | 2 | 3 | 6 | Mitigate |
|
|
45
|
+
| T5 | (DS7) Audit Log | R | User disputes refund; log row is editable | 2 | 2 | 4 | Mitigate |
|
|
46
|
+
| T6 | (8) Stripe flow | I | Card data passes through our server unnecessarily| 2 | 3 | 6 | Avoid |
|
|
47
|
+
| T7 | (P5) Order API | D | Checkout flood exhausts DB connection pool | 2 | 2 | 4 | Mitigate |
|
|
48
|
+
| T8 | (E1) Browser | T | Compromised third-party JS skims card form | 2 | 3 | 6 | Mitigate |
|
|
49
|
+
| T9 | (P2) Auth Service | I | Verbose error reveals which emails are registered| 2 | 1 | 2 | Mitigate |
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 4. Mitigations
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
| Threat | Control | Verify by |
|
|
56
|
+
|--------|----------------------------------------------------------------------|--------------------------------------------|
|
|
57
|
+
| T1 | Parameterized queries only; reject non-ULID item ids at boundary | Static check + injection test in CI |
|
|
58
|
+
| T2 | Per-account + per-IP rate limit, lockout, MFA option | Load test login; assert 429 after N tries |
|
|
59
|
+
| T3 | Server-side ownership check: order.user_id == token.sub on every read | Authz test: user A cannot fetch B's order |
|
|
60
|
+
| T4 | Encrypt session cache at rest; short TTL; rotate on privilege change | Confirm KMS-backed encryption; TTL config |
|
|
61
|
+
| T5 | Append-only audit store; logs outside app write path; signed rows | Attempt UPDATE on audit row → denied |
|
|
62
|
+
| T7 | Bounded conn pool + per-key rate limit + queue with back-pressure | Stress test; assert graceful 429, no crash |
|
|
63
|
+
| T8 | Use Stripe-hosted fields/iframe; SRI on third-party scripts; CSP | CSP report-only in staging; SRI hashes set |
|
|
64
|
+
| T9 | Generic "invalid credentials" response; constant-time compare | Test login with unknown vs known email |
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 5. Accepted / transferred risks
|
|
68
|
+
|
|
69
|
+
- **T6 (avoided):** card data will never transit our servers — we use Stripe Elements so the browser
|
|
70
|
+
posts card details directly to Stripe. This *avoids* the threat (and most PCI scope) rather than
|
|
71
|
+
mitigating it. Owner: Payments lead.
|
|
72
|
+
- **Volumetric DDoS at the network layer:** transferred to the CDN/WAF provider; accepted residual risk
|
|
73
|
+
of brief degradation during an extreme flood. Owner: SRE on-call.
|
|
74
|
+
|
|
75
|
+
## 6. Top risks & riskiest assumption
|
|
76
|
+
|
|
77
|
+
**Fix before launch:** T1 (SQLi, sev 9), T3 (IDOR, sev 9), then T2 (credential stuffing, sev 6).
|
|
78
|
+
|
|
79
|
+
**Riskiest assumption to validate first:** that the JWT `sub` claim is validated server-side on *every*
|
|
80
|
+
order read and write. If any handler trusts a client-supplied `user_id` instead, T3 is exploitable
|
|
81
|
+
regardless of the other controls — verify this first.
|
|
@@ -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.
|