attackmap 0.1.1__tar.gz → 0.3.0__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 (105) hide show
  1. attackmap-0.3.0/PKG-INFO +604 -0
  2. attackmap-0.3.0/README.md +545 -0
  3. {attackmap-0.1.1 → attackmap-0.3.0}/pyproject.toml +2 -1
  4. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/__init__.py +1 -1
  5. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/analyzer.py +51 -6
  6. attackmap-0.3.0/src/attackmap/analyzer_contracts.py +190 -0
  7. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/analyzers.py +183 -18
  8. attackmap-0.3.0/src/attackmap/anomalies.py +385 -0
  9. attackmap-0.3.0/src/attackmap/authz.py +196 -0
  10. attackmap-0.3.0/src/attackmap/cli.py +412 -0
  11. attackmap-0.3.0/src/attackmap/config_scanner.py +291 -0
  12. attackmap-0.3.0/src/attackmap/crypto.py +188 -0
  13. attackmap-0.3.0/src/attackmap/cve.py +436 -0
  14. attackmap-0.3.0/src/attackmap/diagrams.py +224 -0
  15. attackmap-0.3.0/src/attackmap/diff.py +179 -0
  16. attackmap-0.3.0/src/attackmap/exploitability.py +275 -0
  17. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/llm_review.py +34 -7
  18. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/merge.py +39 -0
  19. attackmap-0.3.0/src/attackmap/models.py +661 -0
  20. attackmap-0.3.0/src/attackmap/progress.py +155 -0
  21. attackmap-0.3.0/src/attackmap/report.py +161 -0
  22. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/review_eval.py +70 -16
  23. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/review_prompts.py +102 -0
  24. attackmap-0.3.0/src/attackmap/sarif.py +231 -0
  25. attackmap-0.3.0/src/attackmap/sbom.py +384 -0
  26. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/scanner.py +336 -16
  27. attackmap-0.3.0/src/attackmap/srcpaths.py +83 -0
  28. attackmap-0.3.0/src/attackmap/suggest.py +386 -0
  29. attackmap-0.3.0/src/attackmap/taint.py +491 -0
  30. attackmap-0.3.0/src/attackmap/threat_model.py +1882 -0
  31. attackmap-0.3.0/src/attackmap/topology.py +316 -0
  32. attackmap-0.3.0/src/attackmap/weaknesses.py +188 -0
  33. attackmap-0.3.0/src/attackmap/webhardening.py +142 -0
  34. attackmap-0.3.0/src/attackmap.egg-info/PKG-INFO +604 -0
  35. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap.egg-info/SOURCES.txt +39 -1
  36. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap.egg-info/requires.txt +1 -0
  37. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_analyzer.py +101 -0
  38. attackmap-0.3.0/tests/test_analyzer_metadata_schema.py +194 -0
  39. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_analyzers.py +127 -10
  40. attackmap-0.3.0/tests/test_anomalies.py +371 -0
  41. attackmap-0.3.0/tests/test_authz.py +241 -0
  42. attackmap-0.3.0/tests/test_config_scanner.py +265 -0
  43. attackmap-0.3.0/tests/test_crypto.py +256 -0
  44. attackmap-0.3.0/tests/test_cve.py +403 -0
  45. attackmap-0.3.0/tests/test_diagrams.py +256 -0
  46. attackmap-0.3.0/tests/test_diff.py +368 -0
  47. attackmap-0.3.0/tests/test_exploitability.py +199 -0
  48. attackmap-0.3.0/tests/test_hunt.py +170 -0
  49. attackmap-0.3.0/tests/test_injection_sinks.py +247 -0
  50. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_llm_review.py +38 -0
  51. attackmap-0.3.0/tests/test_progress.py +97 -0
  52. attackmap-0.3.0/tests/test_provenance.py +208 -0
  53. attackmap-0.3.0/tests/test_review_eval.py +165 -0
  54. attackmap-0.3.0/tests/test_sarif.py +219 -0
  55. attackmap-0.3.0/tests/test_sbom.py +250 -0
  56. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_scanner.py +378 -0
  57. attackmap-0.3.0/tests/test_srcpaths.py +120 -0
  58. attackmap-0.3.0/tests/test_suggest.py +259 -0
  59. attackmap-0.3.0/tests/test_taint.py +247 -0
  60. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_threat_model.py +374 -2
  61. attackmap-0.3.0/tests/test_topology.py +220 -0
  62. attackmap-0.3.0/tests/test_weaknesses.py +255 -0
  63. attackmap-0.3.0/tests/test_webhardening.py +208 -0
  64. attackmap-0.1.1/PKG-INFO +0 -264
  65. attackmap-0.1.1/README.md +0 -206
  66. attackmap-0.1.1/src/attackmap/analyzer_contracts.py +0 -104
  67. attackmap-0.1.1/src/attackmap/cli.py +0 -185
  68. attackmap-0.1.1/src/attackmap/models.py +0 -352
  69. attackmap-0.1.1/src/attackmap/report.py +0 -74
  70. attackmap-0.1.1/src/attackmap/threat_model.py +0 -986
  71. attackmap-0.1.1/src/attackmap.egg-info/PKG-INFO +0 -264
  72. attackmap-0.1.1/tests/test_review_eval.py +0 -68
  73. {attackmap-0.1.1 → attackmap-0.3.0}/LICENSE +0 -0
  74. {attackmap-0.1.1 → attackmap-0.3.0}/setup.cfg +0 -0
  75. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/asset_model.py +0 -0
  76. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/attack_taxonomy.py +0 -0
  77. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/context_pack.py +0 -0
  78. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/control_model.py +0 -0
  79. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/defensive_review.py +0 -0
  80. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/detection_opportunities.py +0 -0
  81. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/graph.py +0 -0
  82. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/insights.py +0 -0
  83. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/recon_models.py +0 -0
  84. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/recon_to_analysis.py +0 -0
  85. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/review_json.py +0 -0
  86. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/sdk/__init__.py +0 -0
  87. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/sdk/contracts.py +0 -0
  88. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/sdk/models.py +0 -0
  89. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap/security_overlay.py +0 -0
  90. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap.egg-info/dependency_links.txt +0 -0
  91. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap.egg-info/entry_points.txt +0 -0
  92. {attackmap-0.1.1 → attackmap-0.3.0}/src/attackmap.egg-info/top_level.txt +0 -0
  93. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_artifact_schemas.py +0 -0
  94. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_context_pack.py +0 -0
  95. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_defensive_review.py +0 -0
  96. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_graph.py +0 -0
  97. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_merge.py +0 -0
  98. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_recon_to_analysis.py +0 -0
  99. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_report.py +0 -0
  100. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_review_json.py +0 -0
  101. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_review_prompts.py +0 -0
  102. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_security_overlay.py +0 -0
  103. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_shared_contract_imports.py +0 -0
  104. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_signal_v2.py +0 -0
  105. {attackmap-0.1.1 → attackmap-0.3.0}/tests/test_threat_intel.py +0 -0
@@ -0,0 +1,604 @@
1
+ Metadata-Version: 2.4
2
+ Name: attackmap
3
+ Version: 0.3.0
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
+ Author: AttackMap Contributors
6
+ Author-email: Matthew Davis <matthewd@matthewd.xyz>
7
+ Maintainer-email: Matthew Davis <matthewd@matthewd.xyz>
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/mlaify/AttackMap
10
+ Project-URL: Documentation, https://github.com/mlaify/AttackMap/wiki
11
+ Project-URL: Repository, https://github.com/mlaify/AttackMap
12
+ Project-URL: Issues, https://github.com/mlaify/AttackMap/issues
13
+ Project-URL: Changelog, https://github.com/mlaify/AttackMap/blob/main/CHANGELOG.md
14
+ Keywords: security,static-analysis,appsec,defensive-security,threat-modeling,attack-surface,mitre-attack,detection-engineering,code-review,llm,claude
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Environment :: Console
17
+ Classifier: Intended Audience :: Developers
18
+ Classifier: Intended Audience :: Information Technology
19
+ Classifier: Intended Audience :: System Administrators
20
+ Classifier: License :: OSI Approved :: MIT License
21
+ Classifier: Operating System :: OS Independent
22
+ Classifier: Programming Language :: Python :: 3
23
+ Classifier: Programming Language :: Python :: 3.11
24
+ Classifier: Programming Language :: Python :: 3.12
25
+ Classifier: Programming Language :: Python :: 3.13
26
+ Classifier: Programming Language :: Python :: 3 :: Only
27
+ Classifier: Topic :: Security
28
+ Classifier: Topic :: Software Development :: Quality Assurance
29
+ Classifier: Topic :: Software Development :: Testing
30
+ Classifier: Typing :: Typed
31
+ Requires-Python: >=3.11
32
+ Description-Content-Type: text/markdown
33
+ License-File: LICENSE
34
+ Requires-Dist: typer>=0.12.3
35
+ Requires-Dist: pydantic>=2.7.0
36
+ Requires-Dist: networkx>=3.3
37
+ Provides-Extra: llm
38
+ Requires-Dist: anthropic>=0.40.0; extra == "llm"
39
+ Provides-Extra: all
40
+ Requires-Dist: attackmap[llm]; extra == "all"
41
+ Requires-Dist: attackmap-analyzer-python>=0.1.0; extra == "all"
42
+ Requires-Dist: attackmap-analyzer-rust>=0.1.0; extra == "all"
43
+ Requires-Dist: attackmap-analyzer-go>=0.1.0; extra == "all"
44
+ Requires-Dist: attackmap-analyzer-java-spring>=0.1.0; extra == "all"
45
+ Requires-Dist: attackmap-analyzer-dotnet>=0.1.0; extra == "all"
46
+ Requires-Dist: attackmap-analyzer-terraform>=0.1.0; extra == "all"
47
+ Requires-Dist: attackmap-analyzer-c>=0.1.0; extra == "all"
48
+ Requires-Dist: attackmap-analyzer-cpp>=0.1.0; extra == "all"
49
+ Requires-Dist: attackmap-analyzer-node-service>=0.2.0; extra == "all"
50
+ Requires-Dist: attackmap-analyzer-atproto>=0.1.0; extra == "all"
51
+ Requires-Dist: attackmap-analyzer-php-web>=0.1.0; extra == "all"
52
+ Requires-Dist: attackmap-analyzer-php-laminas>=0.1.0; extra == "all"
53
+ Requires-Dist: attackmap-analyzer-omeka-s>=0.1.0; extra == "all"
54
+ Requires-Dist: attackmap-analyzer-iac>=0.1.0; extra == "all"
55
+ Provides-Extra: dev
56
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
57
+ Requires-Dist: build>=1.2.0; extra == "dev"
58
+ Dynamic: license-file
59
+
60
+ # AttackMap
61
+
62
+ **AI-assisted defensive security analysis for codebases.** AttackMap reads your
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.
68
+
69
+ Built for AppSec engineers, SOC and detection-engineering teams, and engineering
70
+ managers who need to triage an unfamiliar codebase.
71
+
72
+ > Story over checklist. Asset-aware. Control-absence-aware. Evidence-grounded.
73
+
74
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
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.0).** 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.
83
+
84
+ ---
85
+
86
+ ## Quickstart
87
+
88
+ Install with all bundled analyzers:
89
+
90
+ ```bash
91
+ pip install "attackmap[all]"
92
+ ```
93
+
94
+ Run a review on a repository:
95
+
96
+ ```bash
97
+ attackmap analyze /path/to/repo --output reports
98
+ ```
99
+
100
+ Optional: add an AI-narrated review using Claude. Either set an
101
+ `ANTHROPIC_API_KEY`, or log in once with the [Claude Code CLI](https://docs.claude.com/claude-code)
102
+ to use your existing Pro/Max subscription:
103
+
104
+ ```bash
105
+ attackmap analyze /path/to/repo --output reports --llm
106
+ ```
107
+
108
+ Read `reports/defensive-review.md` (heuristic) and `reports/defensive-review-llm.md`
109
+ (LLM-narrated) side by side.
110
+
111
+ ---
112
+
113
+ ## Install
114
+
115
+ ### From PyPI
116
+
117
+ ```bash
118
+ pip install attackmap # core only
119
+ pip install "attackmap[llm]" # add LLM narrative support
120
+ pip install "attackmap[all]" # core + LLM + all 14 analyzer plugins
121
+ ```
122
+
123
+ You can also install individual analyzer plugins on demand:
124
+
125
+ ```bash
126
+ pip install attackmap-analyzer-python attackmap-analyzer-go
127
+ ```
128
+
129
+ Not sure which plugins your repo needs? Let AttackMap tell you:
130
+
131
+ ```bash
132
+ attackmap suggest ./path/to/repo # print ranked pip lines
133
+ attackmap suggest ./path/to/repo --install # and install them (prompts once)
134
+ ```
135
+
136
+ `suggest` inspects the repo's manifest files, extensions, and directory layout
137
+ and recommends only the plugins that would give it deeper signal — useful
138
+ when you want a smaller install footprint than `[all]`.
139
+
140
+ ### With Docker
141
+
142
+ ```bash
143
+ docker run --rm -v "$PWD:/src" ghcr.io/mlaify/attackmap:latest analyze /src --output /src/reports
144
+ ```
145
+
146
+ ### With Homebrew (macOS)
147
+
148
+ ```bash
149
+ brew install mlaify/tap/attackmap
150
+ ```
151
+
152
+ ### From source
153
+
154
+ ```bash
155
+ git clone https://github.com/mlaify/AttackMap.git
156
+ cd AttackMap
157
+ pip install -e ".[llm]"
158
+ ```
159
+
160
+ ---
161
+
162
+ ## What you get
163
+
164
+ Every `attackmap analyze` run writes:
165
+
166
+ | File | What it is |
167
+ |---|---|
168
+ | `architecture.md` | High-level summary of the repository |
169
+ | `attack-surface.md` | Surfaces classified by category, exposure, and risk |
170
+ | `defensive-review.md` | Notable Observations, Asset Inventory, Defensive Controls, Strengths, Weaknesses, Detection Opportunities, Recommendations |
171
+ | `defensive-review.json` | Structured equivalent (schema v1.2.0) |
172
+ | `review-context-pack.json` | Structured evidence pack consumed by the LLM stage |
173
+ | `attackmap-report.json` | Everything bundled |
174
+ | `attackmap-report.sarif` | SARIF 2.1.0 log — ingestable by GitHub Code Scanning, VS Code, and other SARIF consumers |
175
+ | `attackmap-paths.md` | Mermaid flowcharts of each attack path — renders inline on GitHub |
176
+ | `attackmap-topology.md` | Mermaid graph of the service topology, with edge kinds styled per relationship type |
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 |
179
+ | `defensive-review-llm.md` *(with `--llm`)* | Claude-narrated review |
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) |
182
+
183
+ ### GitHub Code Scanning integration
184
+
185
+ Drop this into `.github/workflows/attackmap.yml` to get AttackMap findings inline on every PR:
186
+
187
+ ```yaml
188
+ name: AttackMap
189
+ on: [pull_request, push]
190
+ jobs:
191
+ scan:
192
+ runs-on: ubuntu-latest
193
+ permissions:
194
+ security-events: write
195
+ contents: read
196
+ steps:
197
+ - uses: actions/checkout@v4
198
+ - uses: actions/setup-python@v5
199
+ with: { python-version: "3.12" }
200
+ - run: pip install "attackmap[all]"
201
+ - run: attackmap analyze . --output reports
202
+ - uses: github/codeql-action/upload-sarif@v3
203
+ with:
204
+ sarif_file: reports/attackmap-report.sarif
205
+ category: attackmap
206
+ ```
207
+
208
+ ### Diff mode (PR gating)
209
+
210
+ For a lighter CI integration than Code Scanning — a bot comment, a JSON delta,
211
+ or a hard fail on newly-introduced HIGH findings — point `--baseline` at a
212
+ prior report and AttackMap will emit a Markdown diff alongside the fresh
213
+ report:
214
+
215
+ ```bash
216
+ attackmap analyze . --output reports \
217
+ --baseline path/to/previous/attackmap-report.json \
218
+ --diff-output reports/attackmap-diff.md \
219
+ --fail-on-new-high # exit non-zero if the PR introduces any HIGH finding
220
+ ```
221
+
222
+ Findings get a stable id (hash of the finding title) that survives line drift
223
+ on unrelated commits, so a finding that persists across scans has the same id
224
+ in both. The diff has three sections — **New**, **Persisted**, **Resolved** —
225
+ which drop cleanly into a PR comment.
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
+
372
+ ### SBOM inventory
373
+
374
+ Every scan also produces a lightweight SBOM by parsing direct dependencies out
375
+ of the common manifest files:
376
+
377
+ | Ecosystem | Files parsed |
378
+ |---|---|
379
+ | PyPI (Python) | `pyproject.toml` (PEP 621 + Poetry), `requirements.txt` |
380
+ | npm (Node.js) | `package.json` (dependencies + devDependencies + peer/optional) |
381
+ | Go | `go.mod` (single-line + block-form `require`, `// indirect` flagged) |
382
+ | Cargo (Rust) | `Cargo.toml` (dependencies + dev-dependencies + build-dependencies) |
383
+ | Composer (PHP) | `composer.json` (require + require-dev; platform reqs skipped) |
384
+
385
+ Each entry appears in `attackmap-report.json` under `scan.dependencies` with
386
+ `{name, version, ecosystem, file, dev}`. Version ranges are kept verbatim
387
+ (`^4.16.0`, `>=2,<3`, `latest`) — this slice does not resolve lockfiles.
388
+
389
+ ### CVE cross-reference (opt-in)
390
+
391
+ `attackmap analyze --cve` cross-references every SBOM entry against
392
+ [OSV.dev](https://osv.dev) and emits one finding per vulnerable dependency
393
+ (all known advisories aggregated in the evidence list). CVSS scores map into
394
+ low/medium/high — anything ≥ 7.0 is HIGH.
395
+
396
+ ```bash
397
+ attackmap analyze . --cve
398
+ ```
399
+
400
+ - **Off by default.** The flag exists precisely because CVE lookup does
401
+ network I/O; regular scans stay offline.
402
+ - **Cached** under `~/.attackmap/cache/osv/` keyed by
403
+ `sha256(ecosystem+name+version)`. TTL is 24h by default, overridable via
404
+ `ATTACKMAP_OSV_CACHE_TTL_HOURS`. Repeat scans of the same repo don't hit
405
+ the network.
406
+ - **Offline-tolerant.** If the network's unavailable but the cache is warm,
407
+ cached results still surface; only fresh queries are skipped.
408
+ - **Version resolution is best-effort.** Manifest ranges (`^4.16.0`,
409
+ `>=2.28,<3`) resolve to a queryable lower-bound; OSV does the range math.
410
+ Unpinned specs (`*`, `latest`) are skipped.
411
+
412
+ The structured vulnerability list is available under
413
+ `scan.vulnerabilities` in `attackmap-report.json` with
414
+ `{id, aliases, summary, severity, cvss_score, references, affected_range,
415
+ package_name, package_version, ecosystem}`.
416
+
417
+ ---
418
+
419
+ ## How it works
420
+
421
+ AttackMap is built as four layers, each grounded in the layer below.
422
+
423
+ **1. Heuristic scanner + analyzer plugins.** Language-aware extraction of routes,
424
+ databases, external calls, auth signals, secrets, frameworks, and entrypoints.
425
+ Every signal carries a `file:line` citation, an evidence-text snippet, and a
426
+ confidence score. Plugins are auto-discovered through the `attackmap.analyzers`
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`).
431
+
432
+ **2. Asset and control overlay.** Identifies *what's at risk* (credentials,
433
+ sessions, PII, payment records, internal secrets — with criticality tiers) and
434
+ *what protects it* (authentication, authorization, input validation, rate
435
+ limiting, CSRF, encryption, audit logging, RBAC, MFA), including detection of
436
+ *absent* expected controls.
437
+
438
+ **3. Cross-cutting insight engine.** Connects findings into narratives —
439
+ sensitive-asset reachability, shared-secret blast radius, defense gaps in attack
440
+ chains, control-strength mismatches, asymmetric protection, audit gaps,
441
+ trust-boundary violations, and more.
442
+
443
+ **4. LLM narrative review.** With `--llm`, Claude Opus generates a final review
444
+ from the structured evidence pack. The model is forced to cite real
445
+ surface/asset/control IDs, so it can't invent findings.
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
+
459
+ Layered on top: **MITRE ATT&CK technique mappings** on every insight and
460
+ **detection opportunities** (Sigma/KQL/Splunk-style hints) for each weakness.
461
+
462
+ ---
463
+
464
+ ## Supported ecosystems
465
+
466
+ Fourteen official analyzer plugins, each distributable as a separate package:
467
+
468
+ | Plugin | Coverage |
469
+ |---|---|
470
+ | `attackmap-analyzer-python` | Django, Starlette, AIOHTTP, Sanic, Litestar, DRF; SQLAlchemy/asyncpg/motor; passlib/PyJWT/authlib; httpx/aiohttp |
471
+ | `attackmap-analyzer-rust` | axum, actix-web, rocket; sqlx, diesel, sea-orm; jsonwebtoken, argon2; reqwest |
472
+ | `attackmap-analyzer-go` | net/http, chi, gin, echo, fiber, gorilla/mux; database/sql, gorm, pgx; golang-jwt; resty |
473
+ | `attackmap-analyzer-java-spring` | Java/Kotlin Spring Boot, JAX-RS, Ktor; Spring Data; Spring Security; jjwt |
474
+ | `attackmap-analyzer-dotnet` | ASP.NET Core minimal APIs and attribute routing, EF Core, Identity, JwtBearer |
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 |
477
+ | `attackmap-analyzer-c` | libmicrohttpd, civetweb, mongoose; libcurl; OpenSSL/libsodium; sqlite3/libpq/mysql |
478
+ | `attackmap-analyzer-cpp` | Crow, Pistache, Drogon, cpprestsdk; libcurl/cpr; OpenSSL/Botan/libsodium; libpqxx/mongocxx |
479
+ | `attackmap-analyzer-node-service` | Node.js / TypeScript service ecosystems |
480
+ | `attackmap-analyzer-atproto` | AT Protocol (Bluesky) services |
481
+ | `attackmap-analyzer-php-web` / `-php-laminas` / `-omeka-s` | Generic PHP web, Laminas/Zend MVC, Omeka-S |
482
+
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.
485
+
486
+ ### Building your own analyzer
487
+
488
+ The plugin contract is documented in code at
489
+ [`attackmap.sdk`](src/attackmap/sdk/__init__.py); the developer cookbook with
490
+ scaffolding, testing, and publishing instructions is in
491
+ [`docs/external-analyzers.md`](docs/external-analyzers.md).
492
+
493
+ ---
494
+
495
+ ## CLI reference
496
+
497
+ ```bash
498
+ attackmap analyze <path> # run a review on a repository
499
+ attackmap analyze <path> --output dir # write outputs to `dir/`
500
+ attackmap analyze <path> --format json # json | markdown | all (default)
501
+ attackmap analyze <path> --module python --module rust # only these analyzers
502
+ attackmap analyze <path> --cve # cross-reference SBOM against OSV.dev
503
+ attackmap analyze <path> --llm # add LLM narrative (auto-resolve auth)
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
512
+ attackmap suggest ./repo # recommend plugins for a repo shape
513
+ attackmap suggest ./repo --install # and pip-install the missing ones
514
+ attackmap modules # list installed analyzers
515
+ ```
516
+
517
+ `--module` is repeatable. Missing requested external analyzers can be
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.
522
+
523
+ ---
524
+
525
+ ## What AttackMap is *not*
526
+
527
+ - **A runtime detector.** AttackMap is static. The detection opportunities it
528
+ emits are *hints* for your SIEM team — they are not deployable rules.
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.
537
+ - **Exhaustive.** AttackMap is heuristic by design. Findings are confidence-tiered
538
+ with explicit guardrails for stale signals.
539
+
540
+ ---
541
+
542
+ ## Project status
543
+
544
+ AttackMap is **beta** (v0.3.0) — 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
+
584
+ ## Documentation
585
+
586
+ - [`CHANGELOG.md`](CHANGELOG.md) — release notes
587
+ - [`CONTRIBUTING.md`](CONTRIBUTING.md) — development setup and PR process
588
+ - [`SECURITY.md`](SECURITY.md) — vulnerability disclosure
589
+ - [`AGENTS.md`](AGENTS.md) — agent-facing repo guide
590
+ - [`VISION.md`](VISION.md) — project direction
591
+ - [GitHub wiki](https://github.com/mlaify/AttackMap/wiki) — deeper architecture
592
+ and analyzer-contract references
593
+
594
+ ---
595
+
596
+ ## Contributing
597
+
598
+ Issues and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md)
599
+ for setup, testing, and submission guidelines. By contributing you agree that
600
+ your contributions will be MIT-licensed.
601
+
602
+ ## License
603
+
604
+ [MIT](LICENSE). Copyright (c) 2026 Matthew Davis and AttackMap Contributors.