attackmap 0.2.0__tar.gz → 0.3.1__tar.gz

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.
Files changed (97) hide show
  1. {attackmap-0.2.0/src/attackmap.egg-info → attackmap-0.3.1}/PKG-INFO +244 -11
  2. attackmap-0.3.1/README.md +545 -0
  3. {attackmap-0.2.0 → attackmap-0.3.1}/pyproject.toml +1 -1
  4. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/__init__.py +1 -1
  5. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/analyzers.py +32 -9
  6. attackmap-0.3.1/src/attackmap/anomalies.py +385 -0
  7. attackmap-0.3.1/src/attackmap/authz.py +196 -0
  8. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/cli.py +75 -1
  9. attackmap-0.3.1/src/attackmap/crypto.py +188 -0
  10. attackmap-0.3.1/src/attackmap/exploitability.py +275 -0
  11. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/llm_review.py +9 -5
  12. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/merge.py +20 -0
  13. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/models.py +163 -0
  14. attackmap-0.3.1/src/attackmap/progress.py +155 -0
  15. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/report.py +54 -2
  16. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/review_prompts.py +102 -0
  17. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/scanner.py +58 -5
  18. attackmap-0.3.1/src/attackmap/srcpaths.py +83 -0
  19. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/taint.py +181 -2
  20. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/threat_model.py +544 -26
  21. attackmap-0.3.1/src/attackmap/weaknesses.py +188 -0
  22. attackmap-0.3.1/src/attackmap/webhardening.py +142 -0
  23. {attackmap-0.2.0 → attackmap-0.3.1/src/attackmap.egg-info}/PKG-INFO +244 -11
  24. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap.egg-info/SOURCES.txt +19 -1
  25. attackmap-0.3.1/tests/test_anomalies.py +371 -0
  26. attackmap-0.3.1/tests/test_authz.py +241 -0
  27. attackmap-0.3.1/tests/test_crypto.py +256 -0
  28. attackmap-0.3.1/tests/test_exploitability.py +199 -0
  29. attackmap-0.3.1/tests/test_hunt.py +170 -0
  30. attackmap-0.3.1/tests/test_injection_sinks.py +247 -0
  31. attackmap-0.3.1/tests/test_progress.py +97 -0
  32. attackmap-0.3.1/tests/test_srcpaths.py +120 -0
  33. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_taint.py +122 -7
  34. attackmap-0.3.1/tests/test_weaknesses.py +255 -0
  35. attackmap-0.3.1/tests/test_webhardening.py +208 -0
  36. attackmap-0.2.0/README.md +0 -312
  37. {attackmap-0.2.0 → attackmap-0.3.1}/LICENSE +0 -0
  38. {attackmap-0.2.0 → attackmap-0.3.1}/setup.cfg +0 -0
  39. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/analyzer.py +0 -0
  40. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/analyzer_contracts.py +0 -0
  41. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/asset_model.py +0 -0
  42. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/attack_taxonomy.py +0 -0
  43. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/config_scanner.py +0 -0
  44. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/context_pack.py +0 -0
  45. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/control_model.py +0 -0
  46. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/cve.py +0 -0
  47. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/defensive_review.py +0 -0
  48. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/detection_opportunities.py +0 -0
  49. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/diagrams.py +0 -0
  50. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/diff.py +0 -0
  51. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/graph.py +0 -0
  52. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/insights.py +0 -0
  53. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/recon_models.py +0 -0
  54. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/recon_to_analysis.py +0 -0
  55. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/review_eval.py +0 -0
  56. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/review_json.py +0 -0
  57. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/sarif.py +0 -0
  58. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/sbom.py +0 -0
  59. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/sdk/__init__.py +0 -0
  60. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/sdk/contracts.py +0 -0
  61. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/sdk/models.py +0 -0
  62. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/security_overlay.py +0 -0
  63. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/suggest.py +0 -0
  64. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap/topology.py +0 -0
  65. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap.egg-info/dependency_links.txt +0 -0
  66. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap.egg-info/entry_points.txt +0 -0
  67. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap.egg-info/requires.txt +0 -0
  68. {attackmap-0.2.0 → attackmap-0.3.1}/src/attackmap.egg-info/top_level.txt +0 -0
  69. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_analyzer.py +0 -0
  70. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_analyzer_metadata_schema.py +0 -0
  71. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_analyzers.py +0 -0
  72. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_artifact_schemas.py +0 -0
  73. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_config_scanner.py +0 -0
  74. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_context_pack.py +0 -0
  75. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_cve.py +0 -0
  76. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_defensive_review.py +0 -0
  77. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_diagrams.py +0 -0
  78. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_diff.py +0 -0
  79. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_graph.py +0 -0
  80. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_llm_review.py +0 -0
  81. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_merge.py +0 -0
  82. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_provenance.py +0 -0
  83. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_recon_to_analysis.py +0 -0
  84. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_report.py +0 -0
  85. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_review_eval.py +0 -0
  86. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_review_json.py +0 -0
  87. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_review_prompts.py +0 -0
  88. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_sarif.py +0 -0
  89. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_sbom.py +0 -0
  90. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_scanner.py +0 -0
  91. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_security_overlay.py +0 -0
  92. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_shared_contract_imports.py +0 -0
  93. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_signal_v2.py +0 -0
  94. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_suggest.py +0 -0
  95. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_threat_intel.py +0 -0
  96. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_threat_model.py +0 -0
  97. {attackmap-0.2.0 → attackmap-0.3.1}/tests/test_topology.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: attackmap
3
- Version: 0.2.0
3
+ Version: 0.3.1
4
4
  Summary: AI-assisted defensive security analyzer for codebases — scans a repository, models assets and controls, finds cross-cutting weaknesses, and generates an evidence-grounded review with MITRE ATT&CK mappings and detection-engineering hints.
5
5
  Author: AttackMap Contributors
6
6
  Author-email: Matthew Davis <matthewd@matthewd.xyz>
@@ -60,9 +60,11 @@ Dynamic: license-file
60
60
  # AttackMap
61
61
 
62
62
  **AI-assisted defensive security analysis for codebases.** AttackMap reads your
63
- repository, models its assets and defensive controls, finds cross-cutting
64
- weaknesses that single-file scanners miss, and produces an evidence-grounded
65
- security review with MITRE ATT&CK mappings and detection-engineering hints.
63
+ repository, models its assets and defensive controls, traces request-to-sink
64
+ data flow, inventories dependencies and their known CVEs, and produces an
65
+ evidence-grounded security review with MITRE ATT&CK mappings and
66
+ detection-engineering hints — finding the cross-cutting weaknesses that
67
+ single-file scanners miss.
66
68
 
67
69
  Built for AppSec engineers, SOC and detection-engineering teams, and engineering
68
70
  managers who need to triage an unfamiliar codebase.
@@ -71,6 +73,13 @@ managers who need to triage an unfamiliar codebase.
71
73
 
72
74
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
73
75
  [![Python: 3.11+](https://img.shields.io/badge/Python-3.11%2B-blue.svg)](https://www.python.org/)
76
+ [![PyPI](https://img.shields.io/pypi/v/attackmap.svg)](https://pypi.org/project/attackmap/)
77
+
78
+ > **Status: beta (v0.3.1).** Core engine and 14 analyzer plugins are published
79
+ > to PyPI, Homebrew, and GHCR and validated against real-world codebases.
80
+ > AttackMap is heuristic by design — findings are confidence-tiered evidence,
81
+ > not proof. See [Project status](#project-status) for what's solid and what's
82
+ > still maturing.
74
83
 
75
84
  ---
76
85
 
@@ -108,7 +117,7 @@ Read `reports/defensive-review.md` (heuristic) and `reports/defensive-review-llm
108
117
  ```bash
109
118
  pip install attackmap # core only
110
119
  pip install "attackmap[llm]" # add LLM narrative support
111
- pip install "attackmap[all]" # core + LLM + all 13 analyzer plugins
120
+ pip install "attackmap[all]" # core + LLM + all 14 analyzer plugins
112
121
  ```
113
122
 
114
123
  You can also install individual analyzer plugins on demand:
@@ -166,8 +175,10 @@ Every `attackmap analyze` run writes:
166
175
  | `attackmap-paths.md` | Mermaid flowcharts of each attack path — renders inline on GitHub |
167
176
  | `attackmap-topology.md` | Mermaid graph of the service topology, with edge kinds styled per relationship type |
168
177
  | `attackmap-paths.dot` / `attackmap-topology.dot` | Graphviz DOT versions of the two diagrams — feed into `dot -Tsvg` for slide-quality graphics |
178
+ | `attackmap-exploitability.md` | "Most exploitable now" — route→sink paths ranked by fused 0–100 score, each with its factors |
169
179
  | `defensive-review-llm.md` *(with `--llm`)* | Claude-narrated review |
170
180
  | `defensive-review-llm.meta.json` *(with `--llm`)* | Backend, model, token usage |
181
+ | `vulnerability-hypotheses.md` *(with `--hunt`)* | LLM-generated, evidence-cited exploit-chain **hypotheses** to confirm (leads, not detections) |
171
182
 
172
183
  ### GitHub Code Scanning integration
173
184
 
@@ -213,6 +224,151 @@ on unrelated commits, so a finding that persists across scans has the same id
213
224
  in both. The diff has three sections — **New**, **Persisted**, **Resolved** —
214
225
  which drop cleanly into a PR comment.
215
226
 
227
+ ### Data-flow / injection detection
228
+
229
+ A lightweight taint pass (Python + JS/TS) walks the import graph up to two hops
230
+ from each route handler and flags dangerous sinks reachable from an entry point.
231
+ Each sink kind that a route can reach produces a dedicated finding with an
232
+ ATT&CK mapping:
233
+
234
+ | Sink kind | What it catches | Severity |
235
+ |---|---|---|
236
+ | `eval` / `exec` | Request-reachable code execution | HIGH |
237
+ | `subprocess_shell` | OS command execution (`shell=True`, `child_process.exec`) | HIGH |
238
+ | `unsafe_deserialization` | `pickle.loads`, `yaml.load` (no SafeLoader), `marshal`, `node-serialize` | HIGH |
239
+ | `ssti` | Server-side template injection (`render_template_string`, `Template(req…)`) | HIGH |
240
+ | `ssrf` | Request-derived URL into `requests`/`httpx`/`urlopen`/`axios`/`fetch` | MEDIUM |
241
+ | `nosql_injection` | Request object as a Mongo filter, or `$where` | MEDIUM |
242
+ | `sql_execute` | Cursor/session `.execute`/`.query` reachable from a route | (feeds attack paths) |
243
+ | `dynamic_open` | `open()` with request-shaped path | (feeds attack paths) |
244
+
245
+ | `open_redirect` | Request-derived URL into `redirect()`/`res.redirect()` | MEDIUM |
246
+
247
+ Beyond the taint sinks, a per-file pass flags additional undisclosed-vuln
248
+ classes (`scan.code_weaknesses`): **prototype pollution** (`__proto__` writes,
249
+ deep-merge of a request object), **mass assignment** (a whole request body bound
250
+ to a model), **JWT weaknesses** (`alg=none`, signature verification off), **XXE**
251
+ (XML parsers with external entities enabled), **ReDoS** (regexes with
252
+ catastrophic backtracking), **insecure upload** (a file saved under a
253
+ client-controlled name/path), and **GraphQL exposure** (introspection/playground
254
+ left on).
255
+
256
+ Sinks that are only dangerous with attacker-controlled input (SSRF, SSTI, NoSQL,
257
+ open redirect, `open`) are gated on a request-shaped identifier in the call — a constant URL or
258
+ template is not flagged. It's a heuristic (import-edge ≠ call-edge), so findings
259
+ are evidence, not proof; confidence tapers with hop distance. Chains appear in
260
+ `attackmap-report.json` under `scan.taint_chains`.
261
+
262
+ Test and spec files (`tests/`, `__tests__/`, `*.test.*`, `test_*.py`, …) are
263
+ excluded from all the heuristic passes above by default, since dangerous
264
+ patterns in test scaffolding are rarely real exposure. Set
265
+ `ATTACKMAP_INCLUDE_TESTS=1` to scan them too (e.g. for test-quality reviews).
266
+
267
+ ### Web hardening gaps
268
+
269
+ Route- and config-level checks for common web misconfigurations, each an
270
+ ATT&CK-mapped finding:
271
+
272
+ | Kind | Catches | Severity |
273
+ |---|---|---|
274
+ | `cors_wildcard_credentials` | wildcard/reflected CORS origin **with** credentials | HIGH |
275
+ | `csrf_disabled` | CSRF explicitly disabled / exempted | MEDIUM |
276
+ | `insecure_cookie` | `httpOnly:false`, `secure:false`, `SameSite=None` without `Secure` | MEDIUM |
277
+ | `weak_csp` | CSP allowing `'unsafe-inline'` / `'unsafe-eval'` | MEDIUM |
278
+ | `debug_enabled` | debug mode / actuator wildcard exposure shipped on | MEDIUM |
279
+
280
+ These detect *positively-present* misconfigurations rather than hard-to-judge
281
+ absences (a wildcard CORS origin alone is fine — it's the pairing with
282
+ credentials that's flagged). Results appear under `scan.web_hardening_issues`.
283
+
284
+ ### Insecure cryptography & weak randomness
285
+
286
+ A cheap per-file pass flags crypto misuse, each as a finding with an ATT&CK
287
+ mapping:
288
+
289
+ | Kind | Catches | Severity |
290
+ |---|---|---|
291
+ | `weak_password_hash` | MD5/SHA-1 over a password-shaped value | HIGH |
292
+ | `weak_cipher` | DES / 3DES / RC4 / Blowfish | HIGH |
293
+ | `ecb_mode` | ECB block-cipher mode (incl. Java's `Cipher.getInstance("AES")` default) | MEDIUM |
294
+ | `static_iv_salt` | hard-coded IV or salt literal | MEDIUM |
295
+ | `insecure_random` | `Math.random`/`random`/`rand`/`mt_rand` for a token/key/salt/nonce | MEDIUM |
296
+ | `insecure_tls` | `verify=False`, `rejectUnauthorized:false`, `InsecureSkipVerify:true`, deprecated TLS | HIGH |
297
+
298
+ The noisy families (weak hash, insecure RNG) are gated on a security-context
299
+ identifier; cipher/ECB tokens are matched case-sensitively so algorithm names
300
+ aren't confused with prose (e.g. the French word "des"). Results appear under
301
+ `scan.crypto_weaknesses`.
302
+
303
+ ### Broken object-level authorization (BOLA / IDOR)
304
+
305
+ OWASP API Security #1. AttackMap flags a route as a BOLA/IDOR candidate when it
306
+ composes three signals it already has:
307
+
308
+ 1. the route takes a **resource id** in the path (`/users/{id}`,
309
+ `/orders/:orderId`, `/docs/<int:doc_id>`), and
310
+ 2. it **reaches a datastore** — a DB hint in the same file/module, or a taint
311
+ chain from the route to a SQL execute sink, and
312
+ 3. **no ownership/authorization check** is visible near the handler
313
+ (`current_user`, `request.user`, `authorize`, a policy/guard, or a
314
+ `filter_by(user_id=…)`-style scoped query).
315
+
316
+ Write routes (POST/PUT/PATCH/DELETE) are HIGH, reads MEDIUM. Candidates appear
317
+ under `scan.authz_candidates`; the ownership-marker scan is the main
318
+ false-positive reducer, so a well-scoped handler is not flagged. Path-template
319
+ routes today; query-parameter and RPC-method ids are future work.
320
+
321
+ ### Anomaly / outlier detection
322
+
323
+ The closest honest thing to "surface the unknown": instead of matching a
324
+ known-bad signature, AttackMap flags a route that deviates from the norm its own
325
+ siblings establish. Routes are bucketed into resource cohorts by path prefix
326
+ (`/api/users`, `/api/users/{id}` and `/api/users/export` all share `api/users`;
327
+ `api`/version scaffolding is stripped so versioned resources still separate), and
328
+ within each cohort the odd-one-out is reported:
329
+
330
+ | Kind | Catches | Severity |
331
+ |---|---|---|
332
+ | `auth_outlier` | siblings carry an auth/authorization signal near the handler; this route doesn't | HIGH |
333
+ | `validation_outlier` | among a cohort's state-changing handlers, peers validate input and this one shows no validation marker | LOW |
334
+ | `method_outlier` | a lone state-changing method in an otherwise read-only cohort | MEDIUM |
335
+
336
+ Everything is peer-relative and **confidence scales with how consistent the
337
+ cohort is** — a lone deviation among many agreeing siblings is likelier a mistake
338
+ than the same deviation in a split group. Outliers are only flagged when they're a
339
+ strict minority (a genuinely 50/50 surface isn't nagged), the cohort must have
340
+ real route structure (distinct paths with parameters/sub-paths, not repeated
341
+ method-call strings), and per-route signal detection is scoped to each handler's
342
+ own span so a sibling's guard is never miscredited. Results appear under
343
+ `scan.anomalies`, each finding naming the peer group and the deviation. This is
344
+ the scan-level, route-cohort counterpart to the layered engine's
345
+ `asymmetric_protection` insight.
346
+
347
+ ### Exploitability fusion ("Most exploitable now")
348
+
349
+ Every signal AttackMap has about a route→sink path is fused into a single
350
+ **0–100 exploitability score** so the highest-risk *combinations* rise to the
351
+ top — the public, unauthenticated route whose request reaches a SQL sink next to
352
+ a secret is a different animal from an internal, authed route that reaches the
353
+ same sink two hops away. The score is:
354
+
355
+ - **Deterministic** — the same scan always yields the same number; no
356
+ randomness, no clock.
357
+ - **Explainable** — the score is the clamped sum of named factors, and every one
358
+ is shown. Contributing factors: sink danger (SQLi/RCE/deserialization highest),
359
+ exposure (public/internal/unknown), auth at the entry route, reachability
360
+ (fewer hops = higher), and data sensitivity at the sink (a co-located secret or
361
+ datastore), plus insecure-crypto / web-hardening gaps on the path as
362
+ amplifiers.
363
+
364
+ Scores land on the relevant taint findings (`exploitability` + `exploitability_tier`)
365
+ and in a ranked **`attackmap-exploitability.md`** report plus the `exploitability`
366
+ array in `attackmap-report.json`; the console summary leads with the top few. For
367
+ example, `public + no-auth + taint-to-eval (0 hops)` scores 90/100 (CRITICAL).
368
+ (Dependency CVEs are manifest-level, not attributable to a specific source path,
369
+ so they inform the report but aren't folded into a path's score — path-attributed
370
+ CVE fusion is future work.)
371
+
216
372
  ### SBOM inventory
217
373
 
218
374
  Every scan also produces a lightweight SBOM by parsing direct dependencies out
@@ -268,7 +424,10 @@ AttackMap is built as four layers, each grounded in the layer below.
268
424
  databases, external calls, auth signals, secrets, frameworks, and entrypoints.
269
425
  Every signal carries a `file:line` citation, an evidence-text snippet, and a
270
426
  confidence score. Plugins are auto-discovered through the `attackmap.analyzers`
271
- entry-point group.
427
+ entry-point group. Alongside recon, three cross-file passes run in core: a
428
+ **taint / data-flow** walk (request-to-sink reachability across imports), a
429
+ **BOLA/IDOR** authorization check, and an **SBOM** dependency inventory
430
+ (optionally cross-referenced against OSV.dev with `--cve`).
272
431
 
273
432
  **2. Asset and control overlay.** Identifies *what's at risk* (credentials,
274
433
  sessions, PII, payment records, internal secrets — with criticality tiers) and
@@ -285,6 +444,18 @@ trust-boundary violations, and more.
285
444
  from the structured evidence pack. The model is forced to cite real
286
445
  surface/asset/control IDs, so it can't invent findings.
287
446
 
447
+ **5. Vulnerability-hypothesis hunting (`--hunt`).** The honest core of the
448
+ "find the unknown" ask. `attackmap analyze . --hunt` has Claude reason over the
449
+ full evidence pack (surfaces, assets, controls, taint chains, exploitability
450
+ scores, anomalies) as a red-team analyst and propose **ranked, human-verifiable
451
+ exploit-chain hypotheses** — candidate weaknesses a static rule wouldn't catch,
452
+ especially novel cross-signal combinations. Output goes to
453
+ `vulnerability-hypotheses.md` under an unmissable banner: **these are hypotheses
454
+ to confirm, not detections.** The same grounding contract as the review applies
455
+ (every hypothesis cites real evidence IDs), plus honesty guardrails: no CVE
456
+ assignment, no exploit code, confidence-tiered, and each lead lists exactly what
457
+ a human must verify. Uses the same auth/backend resolution as `--llm`.
458
+
288
459
  Layered on top: **MITRE ATT&CK technique mappings** on every insight and
289
460
  **detection opportunities** (Sigma/KQL/Splunk-style hints) for each weakness.
290
461
 
@@ -292,7 +463,7 @@ Layered on top: **MITRE ATT&CK technique mappings** on every insight and
292
463
 
293
464
  ## Supported ecosystems
294
465
 
295
- Thirteen official analyzer plugins, each distributable as a separate package:
466
+ Fourteen official analyzer plugins, each distributable as a separate package:
296
467
 
297
468
  | Plugin | Coverage |
298
469
  |---|---|
@@ -302,13 +473,15 @@ Thirteen official analyzer plugins, each distributable as a separate package:
302
473
  | `attackmap-analyzer-java-spring` | Java/Kotlin Spring Boot, JAX-RS, Ktor; Spring Data; Spring Security; jjwt |
303
474
  | `attackmap-analyzer-dotnet` | ASP.NET Core minimal APIs and attribute routing, EF Core, Identity, JwtBearer |
304
475
  | `attackmap-analyzer-terraform` | AWS, Azure, GCP resources; IAM wildcards; open SGs; secrets |
476
+ | `attackmap-analyzer-iac` | Dockerfile hardening, docker-compose service graphs, GitHub Actions workflows, `.env` templates, shell installers |
305
477
  | `attackmap-analyzer-c` | libmicrohttpd, civetweb, mongoose; libcurl; OpenSSL/libsodium; sqlite3/libpq/mysql |
306
478
  | `attackmap-analyzer-cpp` | Crow, Pistache, Drogon, cpprestsdk; libcurl/cpr; OpenSSL/Botan/libsodium; libpqxx/mongocxx |
307
479
  | `attackmap-analyzer-node-service` | Node.js / TypeScript service ecosystems |
308
480
  | `attackmap-analyzer-atproto` | AT Protocol (Bluesky) services |
309
481
  | `attackmap-analyzer-php-web` / `-php-laminas` / `-omeka-s` | Generic PHP web, Laminas/Zend MVC, Omeka-S |
310
482
 
311
- `pip install "attackmap[all]"` installs every official plugin.
483
+ `pip install "attackmap[all]"` installs every official plugin. Not sure which
484
+ you need? `attackmap suggest ./repo` recommends the right set for a repo's shape.
312
485
 
313
486
  ### Building your own analyzer
314
487
 
@@ -324,16 +497,28 @@ scaffolding, testing, and publishing instructions is in
324
497
  ```bash
325
498
  attackmap analyze <path> # run a review on a repository
326
499
  attackmap analyze <path> --output dir # write outputs to `dir/`
500
+ attackmap analyze <path> --format json # json | markdown | all (default)
327
501
  attackmap analyze <path> --module python --module rust # only these analyzers
502
+ attackmap analyze <path> --cve # cross-reference SBOM against OSV.dev
328
503
  attackmap analyze <path> --llm # add LLM narrative (auto-resolve auth)
329
504
  attackmap analyze <path> --llm --llm-backend cli # force Claude CLI
505
+ attackmap analyze <path> --hunt # LLM vulnerability-hypothesis hunt (leads to confirm)
506
+
507
+ # CI / PR diff gating
508
+ attackmap analyze <path> --baseline prev/attackmap-report.json \
509
+ --diff-output reports/attackmap-diff.md --fail-on-new-high
510
+
511
+ # Plugin discovery
330
512
  attackmap suggest ./repo # recommend plugins for a repo shape
331
513
  attackmap suggest ./repo --install # and pip-install the missing ones
332
514
  attackmap modules # list installed analyzers
333
515
  ```
334
516
 
335
517
  `--module` is repeatable. Missing requested external analyzers can be
336
- auto-installed (when possible) from the `mlaify` GitHub organization.
518
+ auto-installed (when possible) from the `mlaify` GitHub organization. `--cve`
519
+ does network I/O (cached under `~/.attackmap/cache/osv/`, 24h TTL);
520
+ `--fail-on-new-high` requires `--baseline` and exits non-zero when the diff
521
+ introduces a new HIGH finding.
337
522
 
338
523
  ---
339
524
 
@@ -341,13 +526,61 @@ auto-installed (when possible) from the `mlaify` GitHub organization.
341
526
 
342
527
  - **A runtime detector.** AttackMap is static. The detection opportunities it
343
528
  emits are *hints* for your SIEM team — they are not deployable rules.
344
- - **A vulnerability scanner.** AttackMap models architecture, assets, and
345
- controls. It does not match known-CVE patterns.
529
+ - **A replacement for dedicated SCA.** AttackMap does inventory dependencies and
530
+ cross-reference OSV.dev with `--cve`, but tools like Trivy, Grype, and
531
+ Dependabot go deeper on transitive resolution and lockfiles. AttackMap's
532
+ value is folding the CVE signal into an architecture-aware narrative
533
+ ("this public route reaches this vulnerable ORM").
534
+ - **A true taint engine.** The data-flow pass is a heuristic import-graph walk
535
+ (import-edge ≈ call-edge), not sound interprocedural taint analysis. It
536
+ favors precision over recall; findings are evidence, not proof.
346
537
  - **Exhaustive.** AttackMap is heuristic by design. Findings are confidence-tiered
347
538
  with explicit guardrails for stale signals.
348
539
 
349
540
  ---
350
541
 
542
+ ## Project status
543
+
544
+ AttackMap is **beta** (v0.3.1) — published and validated on real codebases, but
545
+ pre-1.0 and heuristic.
546
+
547
+ **Solid today:**
548
+
549
+ - Modular analyzer execution with entry-point discovery; 14 official plugins on PyPI.
550
+ - Framework-aware route extraction (FastAPI/Flask/Express/Spring/axum/chi/…).
551
+ - Asset + control modeling, cross-cutting insight engine, chain-aware threat model.
552
+ - Injection / data-flow detection: SSRF, SSTI, NoSQL, unsafe deserialization,
553
+ eval/exec/shell, SQL, dynamic file open, open redirect — request-container-gated
554
+ for precision.
555
+ - Novel vuln-class detectors: prototype pollution, mass assignment, JWT weakness,
556
+ XXE, ReDoS, insecure upload, GraphQL exposure.
557
+ - BOLA/IDOR authorization detection on path-template routes.
558
+ - Insecure-crypto / weak-randomness and web-hardening (CORS/CSRF/cookies/CSP/debug)
559
+ detection.
560
+ - Anomaly / outlier detection (the odd-one-out among sibling routes) and
561
+ **exploitability fusion** — a deterministic, explainable 0–100 "exploitable now"
562
+ score that ranks route→sink combinations.
563
+ - **`--hunt`**: LLM vulnerability-hypothesis mode — evidence-cited, human-verifiable
564
+ exploit-chain leads (not detections).
565
+ - SBOM inventory (5 ecosystems) + OSV.dev CVE cross-reference (`--cve`).
566
+ - Output: Markdown + JSON + **SARIF 2.1.0** (GitHub Code Scanning) + **Mermaid /
567
+ Graphviz** diagrams; **diff/baseline** mode for PR gating; optional LLM narrative.
568
+ - Live scan progress bar + ETA; test/spec files excluded from heuristic passes.
569
+ - Distribution: `pip install attackmap[all]`, `brew install mlaify/tap/attackmap`,
570
+ `docker pull ghcr.io/mlaify/attackmap`.
571
+
572
+ **Still maturing:**
573
+
574
+ - Taint + BOLA are Python + JS/TS and path-template scoped; query-param / RPC-method
575
+ authorization and more languages are planned.
576
+ - The import-graph taint walk approximates call-edges with import-edges — precision
577
+ over recall; findings are evidence, not proof.
578
+ - CVE lookup resolves a best-effort concrete version, not full lockfile ranges, and
579
+ isn't yet fused into per-path exploitability scores.
580
+ - Anomaly / exploitability reasoning is route-cohort and taint-chain scoped.
581
+
582
+ ---
583
+
351
584
  ## Documentation
352
585
 
353
586
  - [`CHANGELOG.md`](CHANGELOG.md) — release notes