hullproof 0.0.0-stage → 0.5.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.
Files changed (363) hide show
  1. package/LICENSE +222 -0
  2. package/NOTICE +32 -0
  3. package/README.md +313 -2
  4. package/checks/db.firebase-rules-not-open.json +24 -0
  5. package/checks/db.rls-every-table.json +25 -0
  6. package/checks/log.no-credential-in-logs.json +30 -0
  7. package/checks/secrets.no-env-file-committed.json +31 -0
  8. package/checks/secrets.no-secret-in-public-env.json +37 -0
  9. package/checks/storage.firebase-rules-not-open.json +22 -0
  10. package/checks/supply.no-untrusted-event-in-run.json +23 -0
  11. package/checks/web.cors-no-reflected-origin.json +31 -0
  12. package/detectors/ai.json +25 -0
  13. package/detectors/auth.json +27 -0
  14. package/detectors/ci.json +19 -0
  15. package/detectors/containers.json +8 -0
  16. package/detectors/data_stores.json +38 -0
  17. package/detectors/frameworks.json +94 -0
  18. package/detectors/hosting.json +44 -0
  19. package/detectors/iac.json +43 -0
  20. package/detectors/languages.json +48 -0
  21. package/detectors/mobile.json +22 -0
  22. package/detectors/package_managers.json +39 -0
  23. package/detectors/payments.json +19 -0
  24. package/detectors/runtimes.json +17 -0
  25. package/dist/checks/code/admin-role.js +46 -0
  26. package/dist/checks/code/owner-filter.js +91 -0
  27. package/dist/checks/code/shared.js +84 -0
  28. package/dist/checks/code/webhook-verify.js +77 -0
  29. package/dist/checks/context.js +64 -0
  30. package/dist/checks/map/config-checks.js +74 -0
  31. package/dist/checks/map/entry-checks.js +97 -0
  32. package/dist/checks/map/shared.js +44 -0
  33. package/dist/checks/ops.js +307 -0
  34. package/dist/checks/pro-map.js +1 -0
  35. package/dist/checks/run.js +92 -0
  36. package/dist/checks/types.js +1 -0
  37. package/dist/ci/comment.js +44 -0
  38. package/dist/ci/sarif-check.js +157 -0
  39. package/dist/ci/sarif.js +61 -0
  40. package/dist/cli.js +358 -0
  41. package/dist/commands/ci.js +115 -0
  42. package/dist/commands/git.js +58 -0
  43. package/dist/commands/hooks.js +30 -0
  44. package/dist/commands/hunt-pro.js +1 -0
  45. package/dist/commands/hunt.js +86 -0
  46. package/dist/commands/map.js +33 -0
  47. package/dist/commands/mcp.js +17 -0
  48. package/dist/commands/pack.js +48 -0
  49. package/dist/commands/prove-pro.js +1 -0
  50. package/dist/commands/prove.js +173 -0
  51. package/dist/commands/report-gate.js +92 -0
  52. package/dist/commands/scan.js +158 -0
  53. package/dist/confirm/agreement.js +18 -0
  54. package/dist/confirm/chain.js +84 -0
  55. package/dist/confirm/confirm.js +112 -0
  56. package/dist/confirm/honesty.js +75 -0
  57. package/dist/confirm/lead.js +92 -0
  58. package/dist/confirm/merge.js +88 -0
  59. package/dist/confirm/query.js +145 -0
  60. package/dist/confirm/rule.js +86 -0
  61. package/dist/confirm/store.js +42 -0
  62. package/dist/confirm/summary.js +6 -0
  63. package/dist/confirm/synthesis.js +28 -0
  64. package/dist/discover/detectors.js +50 -0
  65. package/dist/discover/discover.js +270 -0
  66. package/dist/discover/extract.js +282 -0
  67. package/dist/discover/git.js +40 -0
  68. package/dist/discover/kit-files.js +47 -0
  69. package/dist/discover/walk.js +110 -0
  70. package/dist/env.js +57 -0
  71. package/dist/gate/gate.js +173 -0
  72. package/dist/hooks/install.js +153 -0
  73. package/dist/hooks/run.js +112 -0
  74. package/dist/map/analyze.js +201 -0
  75. package/dist/map/build.js +253 -0
  76. package/dist/map/candidates.js +49 -0
  77. package/dist/map/cblocks.js +77 -0
  78. package/dist/map/config.js +291 -0
  79. package/dist/map/dotnet.js +242 -0
  80. package/dist/map/entry.js +78 -0
  81. package/dist/map/expo.js +190 -0
  82. package/dist/map/go.js +292 -0
  83. package/dist/map/js-express.js +143 -0
  84. package/dist/map/js-misc.js +295 -0
  85. package/dist/map/js-next.js +292 -0
  86. package/dist/map/laravel.js +389 -0
  87. package/dist/map/lex-more.js +305 -0
  88. package/dist/map/lex.js +425 -0
  89. package/dist/map/light-index.js +191 -0
  90. package/dist/map/light-profiles.js +324 -0
  91. package/dist/map/light.js +574 -0
  92. package/dist/map/local-vocab.js +27 -0
  93. package/dist/map/mobile.js +326 -0
  94. package/dist/map/py-django.js +281 -0
  95. package/dist/map/py.js +391 -0
  96. package/dist/map/rails.js +391 -0
  97. package/dist/map/repo.js +178 -0
  98. package/dist/map/rust.js +312 -0
  99. package/dist/map/spring.js +207 -0
  100. package/dist/map/taint.js +96 -0
  101. package/dist/map/touches.js +355 -0
  102. package/dist/map/vocab.js +88 -0
  103. package/dist/mapping/controls.js +34 -0
  104. package/dist/mapping/dependency-policy.js +44 -0
  105. package/dist/mapping/map.js +44 -0
  106. package/dist/mapping/maps/gitleaks.json +12 -0
  107. package/dist/mapping/maps/osv-scanner.json +7 -0
  108. package/dist/mapping/maps/trivy.json +13 -0
  109. package/dist/mcp/confine.js +59 -0
  110. package/dist/mcp/protocol.js +140 -0
  111. package/dist/mcp/schema.js +43 -0
  112. package/dist/mcp/server.js +37 -0
  113. package/dist/mcp/tools.js +238 -0
  114. package/dist/packs/coverage.js +79 -0
  115. package/dist/packs/manifest.js +36 -0
  116. package/dist/packs/validate.js +271 -0
  117. package/dist/prove/container.js +276 -0
  118. package/dist/prove/exec-main.js +20 -0
  119. package/dist/prove/executor.js +149 -0
  120. package/dist/prove/local.js +131 -0
  121. package/dist/prove/probes.js +65 -0
  122. package/dist/prove/recipe.js +278 -0
  123. package/dist/prove/run.js +136 -0
  124. package/dist/prove/runner.js +1 -0
  125. package/dist/prove/safety.js +126 -0
  126. package/dist/prove/spec.js +357 -0
  127. package/dist/prove/store.js +65 -0
  128. package/dist/report/build.js +297 -0
  129. package/dist/report/entry-points.js +75 -0
  130. package/dist/report/hunt-section.js +71 -0
  131. package/dist/report/kit.js +41 -0
  132. package/dist/report/load.js +35 -0
  133. package/dist/report/messages.js +273 -0
  134. package/dist/report/prove-section.js +65 -0
  135. package/dist/report/report.js +156 -0
  136. package/dist/report/surface.js +21 -0
  137. package/dist/report/test-code.js +51 -0
  138. package/dist/report/tiers.js +44 -0
  139. package/dist/scanners/common.js +162 -0
  140. package/dist/scanners/gitleaks.js +90 -0
  141. package/dist/scanners/index.js +113 -0
  142. package/dist/scanners/osv-scanner.js +77 -0
  143. package/dist/scanners/run-targets.js +34 -0
  144. package/dist/scanners/secret-noise.js +89 -0
  145. package/dist/scanners/semgrep.js +142 -0
  146. package/dist/scanners/trivy.js +65 -0
  147. package/dist/scanners/types.js +1 -0
  148. package/dist/types/check.js +1 -0
  149. package/dist/types/codemap.js +1 -0
  150. package/dist/types/findings.js +5 -0
  151. package/dist/types/hunt.js +1 -0
  152. package/dist/types/index.js +1 -0
  153. package/dist/types/prove.js +1 -0
  154. package/dist/types/results.js +2 -0
  155. package/dist/types/scan.js +1 -0
  156. package/dist/types/stack.js +5 -0
  157. package/dist/util.js +71 -0
  158. package/dist/version.js +2 -0
  159. package/package.json +46 -4
  160. package/packs/android/fixture-result.json +43 -0
  161. package/packs/android/pack.json +56 -0
  162. package/packs/dotnet/fixture-result.json +62 -0
  163. package/packs/dotnet/pack.json +88 -0
  164. package/packs/expo/answer-key.json +51 -0
  165. package/packs/expo/fixture-result.json +62 -0
  166. package/packs/expo/pack.json +79 -0
  167. package/packs/firebase/answer-key.json +27 -0
  168. package/packs/firebase/fixture-result.json +43 -0
  169. package/packs/firebase/pack.json +58 -0
  170. package/packs/go/answer-key.json +101 -0
  171. package/packs/go/fixture-result.json +64 -0
  172. package/packs/go/pack.json +99 -0
  173. package/packs/ios/fixture-result.json +43 -0
  174. package/packs/ios/pack.json +55 -0
  175. package/packs/laravel/answer-key.json +84 -0
  176. package/packs/laravel/fixture-result.json +60 -0
  177. package/packs/laravel/pack.json +91 -0
  178. package/packs/node-ts/answer-key.json +220 -0
  179. package/packs/node-ts/fixture-result.json +114 -0
  180. package/packs/node-ts/pack.json +134 -0
  181. package/packs/python/answer-key.json +195 -0
  182. package/packs/python/fixture-result.json +119 -0
  183. package/packs/python/pack.json +121 -0
  184. package/packs/rails/answer-key.json +84 -0
  185. package/packs/rails/fixture-result.json +60 -0
  186. package/packs/rails/pack.json +78 -0
  187. package/packs/rust/fixture-result.json +43 -0
  188. package/packs/rust/pack.json +69 -0
  189. package/packs/spring/fixture-result.json +63 -0
  190. package/packs/spring/pack.json +103 -0
  191. package/packs/supabase/answer-key.json +52 -0
  192. package/packs/supabase/fixture-result.json +58 -0
  193. package/packs/supabase/pack.json +60 -0
  194. package/rules/gitleaks.toml +256 -0
  195. package/rules/semgrep/api-route-no-auth.yaml +31 -0
  196. package/rules/semgrep/cors-reflect-origin.yaml +48 -0
  197. package/rules/semgrep/eval-or-new-function.yaml +185 -0
  198. package/rules/semgrep/log-session-token.yaml +48 -0
  199. package/rules/semgrep/math-random-tokens.yaml +24 -0
  200. package/rules/semgrep/next-public-secret-name.yaml +32 -0
  201. package/rules/semgrep/postgrest-filter-injection.yaml +78 -0
  202. package/rules/semgrep/raw-sql-concat.yaml +42 -0
  203. package/rules/semgrep/read-by-id-no-owner.yaml +49 -0
  204. package/rules/semgrep/server-action-no-auth.yaml +26 -0
  205. package/rules/semgrep/sql-variants.yaml +99 -0
  206. package/rules/semgrep/ssrf-unguarded-url.yaml +137 -0
  207. package/rules/semgrep/subprocess-injection.yaml +163 -0
  208. package/rules/semgrep/taint-go.yaml +333 -0
  209. package/rules/semgrep/taint-java.yaml +317 -0
  210. package/rules/semgrep/taint-javascript.yaml +412 -0
  211. package/rules/semgrep/taint-php.yaml +361 -0
  212. package/rules/semgrep/taint-python.yaml +414 -0
  213. package/rules/semgrep/tool-endpoint-admin-client.yaml +86 -0
  214. package/rules/semgrep/user-metadata-authz.yaml +22 -0
  215. package/rules/semgrep/verify-result-unused.yaml +62 -0
  216. package/rules/semgrep/webhook-parse-before-verify.yaml +29 -0
  217. package/rules/test-artifact-ids.json +4 -0
  218. package/rules/tiers.json +427 -0
  219. package/schemas/check-results.schema.json +55 -0
  220. package/schemas/check.schema.json +41 -0
  221. package/schemas/codemap.schema.json +216 -0
  222. package/schemas/findings.schema.json +1048 -0
  223. package/schemas/hunt-output.schema.json +46 -0
  224. package/schemas/hunt-result.schema.json +58 -0
  225. package/schemas/results.schema.json +17 -0
  226. package/schemas/scan-hits.schema.json +32 -0
  227. package/schemas/scan-meta.schema.json +25 -0
  228. package/schemas/stack.schema.json +93 -0
  229. package/src/checks/README.md +32 -0
  230. package/src/checks/code/admin-role.ts +49 -0
  231. package/src/checks/code/owner-filter.ts +95 -0
  232. package/src/checks/code/shared.ts +66 -0
  233. package/src/checks/code/webhook-verify.ts +75 -0
  234. package/src/checks/context.ts +72 -0
  235. package/src/checks/map/config-checks.ts +79 -0
  236. package/src/checks/map/entry-checks.ts +116 -0
  237. package/src/checks/map/shared.ts +63 -0
  238. package/src/checks/ops.ts +280 -0
  239. package/src/checks/pro-map.ts +4 -0
  240. package/src/checks/run.ts +80 -0
  241. package/src/checks/types.ts +12 -0
  242. package/src/ci/comment.ts +52 -0
  243. package/src/ci/sarif-check.ts +100 -0
  244. package/src/ci/sarif.ts +72 -0
  245. package/src/cli.ts +273 -0
  246. package/src/commands/ci.ts +104 -0
  247. package/src/commands/git.ts +59 -0
  248. package/src/commands/hooks.ts +27 -0
  249. package/src/commands/hunt-pro.ts +4 -0
  250. package/src/commands/hunt.ts +68 -0
  251. package/src/commands/map.ts +27 -0
  252. package/src/commands/mcp.ts +18 -0
  253. package/src/commands/pack.ts +34 -0
  254. package/src/commands/prove-pro.ts +4 -0
  255. package/src/commands/prove.ts +126 -0
  256. package/src/commands/report-gate.ts +75 -0
  257. package/src/commands/scan.ts +156 -0
  258. package/src/confirm/agreement.ts +23 -0
  259. package/src/confirm/chain.ts +67 -0
  260. package/src/confirm/confirm.ts +107 -0
  261. package/src/confirm/honesty.ts +65 -0
  262. package/src/confirm/lead.ts +76 -0
  263. package/src/confirm/merge.ts +89 -0
  264. package/src/confirm/query.ts +126 -0
  265. package/src/confirm/rule.ts +76 -0
  266. package/src/confirm/store.ts +42 -0
  267. package/src/confirm/summary.ts +9 -0
  268. package/src/confirm/synthesis.ts +33 -0
  269. package/src/discover/detectors.ts +71 -0
  270. package/src/discover/discover.ts +253 -0
  271. package/src/discover/extract.ts +235 -0
  272. package/src/discover/git.ts +31 -0
  273. package/src/discover/kit-files.ts +37 -0
  274. package/src/discover/walk.ts +88 -0
  275. package/src/env.ts +51 -0
  276. package/src/gate/gate.ts +169 -0
  277. package/src/hooks/install.ts +142 -0
  278. package/src/hooks/run.ts +121 -0
  279. package/src/map/analyze.ts +219 -0
  280. package/src/map/build.ts +206 -0
  281. package/src/map/candidates.ts +47 -0
  282. package/src/map/cblocks.ts +55 -0
  283. package/src/map/config.ts +207 -0
  284. package/src/map/dotnet.ts +205 -0
  285. package/src/map/entry.ts +80 -0
  286. package/src/map/expo.ts +171 -0
  287. package/src/map/go.ts +271 -0
  288. package/src/map/js-express.ts +135 -0
  289. package/src/map/js-misc.ts +221 -0
  290. package/src/map/js-next.ts +282 -0
  291. package/src/map/laravel.ts +327 -0
  292. package/src/map/lex-more.ts +152 -0
  293. package/src/map/lex.ts +274 -0
  294. package/src/map/light-index.ts +134 -0
  295. package/src/map/light-profiles.ts +363 -0
  296. package/src/map/light.ts +484 -0
  297. package/src/map/local-vocab.ts +30 -0
  298. package/src/map/mobile.ts +263 -0
  299. package/src/map/py-django.ts +239 -0
  300. package/src/map/py.ts +329 -0
  301. package/src/map/rails.ts +291 -0
  302. package/src/map/repo.ts +150 -0
  303. package/src/map/rust.ts +256 -0
  304. package/src/map/spring.ts +185 -0
  305. package/src/map/taint.ts +86 -0
  306. package/src/map/touches.ts +296 -0
  307. package/src/map/vocab.ts +106 -0
  308. package/src/mapping/controls.ts +47 -0
  309. package/src/mapping/dependency-policy.ts +55 -0
  310. package/src/mapping/map.ts +59 -0
  311. package/src/mapping/maps/gitleaks.json +12 -0
  312. package/src/mapping/maps/osv-scanner.json +7 -0
  313. package/src/mapping/maps/trivy.json +13 -0
  314. package/src/mcp/confine.ts +44 -0
  315. package/src/mcp/protocol.ts +144 -0
  316. package/src/mcp/schema.ts +35 -0
  317. package/src/mcp/server.ts +32 -0
  318. package/src/mcp/tools.ts +235 -0
  319. package/src/packs/coverage.ts +98 -0
  320. package/src/packs/manifest.ts +97 -0
  321. package/src/packs/validate.ts +204 -0
  322. package/src/prove/container.ts +237 -0
  323. package/src/prove/exec-main.ts +16 -0
  324. package/src/prove/executor.ts +130 -0
  325. package/src/prove/local.ts +100 -0
  326. package/src/prove/probes.ts +68 -0
  327. package/src/prove/recipe.ts +215 -0
  328. package/src/prove/run.ts +124 -0
  329. package/src/prove/runner.ts +28 -0
  330. package/src/prove/safety.ts +98 -0
  331. package/src/prove/spec.ts +256 -0
  332. package/src/prove/store.ts +48 -0
  333. package/src/report/build.ts +304 -0
  334. package/src/report/entry-points.ts +78 -0
  335. package/src/report/hunt-section.ts +67 -0
  336. package/src/report/kit.ts +59 -0
  337. package/src/report/load.ts +49 -0
  338. package/src/report/messages.ts +270 -0
  339. package/src/report/prove-section.ts +61 -0
  340. package/src/report/report.ts +160 -0
  341. package/src/report/surface.ts +32 -0
  342. package/src/report/test-code.ts +56 -0
  343. package/src/report/tiers.ts +50 -0
  344. package/src/scanners/common.ts +149 -0
  345. package/src/scanners/gitleaks.ts +89 -0
  346. package/src/scanners/index.ts +103 -0
  347. package/src/scanners/osv-scanner.ts +90 -0
  348. package/src/scanners/run-targets.ts +35 -0
  349. package/src/scanners/secret-noise.ts +80 -0
  350. package/src/scanners/semgrep.ts +139 -0
  351. package/src/scanners/trivy.ts +66 -0
  352. package/src/scanners/types.ts +98 -0
  353. package/src/types/check.ts +52 -0
  354. package/src/types/codemap.ts +142 -0
  355. package/src/types/findings.ts +107 -0
  356. package/src/types/hunt.ts +97 -0
  357. package/src/types/index.ts +10 -0
  358. package/src/types/prove.ts +83 -0
  359. package/src/types/results.ts +15 -0
  360. package/src/types/scan.ts +63 -0
  361. package/src/types/stack.ts +61 -0
  362. package/src/util.ts +59 -0
  363. package/src/version.ts +2 -0
@@ -0,0 +1,195 @@
1
+ {
2
+ "pack": "python",
3
+ "fail_dir": "test/fixtures/map/fail",
4
+ "pass_dir": "test/fixtures/map/pass",
5
+ "stacks": [
6
+ "flask",
7
+ "fastapi",
8
+ "django"
9
+ ],
10
+ "detect_expected": [
11
+ "flask",
12
+ "fastapi",
13
+ "django",
14
+ "python"
15
+ ],
16
+ "mapped_what": "entry points",
17
+ "mapped": [
18
+ "http_route ANY /api/export",
19
+ "http_route ANY /api/items",
20
+ "http_route DELETE /api/notes/:note_id",
21
+ "http_route DELETE /api/notes/:note_id",
22
+ "http_route GET /api/export",
23
+ "http_route GET /api/export",
24
+ "http_route GET /api/items",
25
+ "http_route GET /api/items",
26
+ "http_route POST /api/admin/role",
27
+ "http_route POST /api/admin/role",
28
+ "http_route POST /api/admin/users/:uid/role",
29
+ "http_route POST /api/import",
30
+ "http_route POST /api/import",
31
+ "http_route POST /api/import",
32
+ "http_route POST /api/notes",
33
+ "http_route POST /api/notes",
34
+ "http_route POST /api/notes",
35
+ "http_route POST /api/notes/:pk/delete",
36
+ "http_route POST /api/upload",
37
+ "http_route POST /api/upload",
38
+ "http_route POST /api/upload",
39
+ "http_route POST /login",
40
+ "http_route POST /login",
41
+ "http_route POST /login",
42
+ "webhook POST /webhooks/pay",
43
+ "webhook POST /webhooks/pay",
44
+ "webhook POST /webhooks/pay"
45
+ ],
46
+ "flaws": [
47
+ {
48
+ "check": "admin-route-without-role",
49
+ "stack": "django"
50
+ },
51
+ {
52
+ "check": "admin-route-without-role",
53
+ "stack": "fastapi"
54
+ },
55
+ {
56
+ "check": "admin-route-without-role",
57
+ "stack": "flask"
58
+ },
59
+ {
60
+ "check": "data-read-without-auth",
61
+ "stack": "django"
62
+ },
63
+ {
64
+ "check": "data-read-without-auth",
65
+ "stack": "fastapi"
66
+ },
67
+ {
68
+ "check": "data-read-without-auth",
69
+ "stack": "flask"
70
+ },
71
+ {
72
+ "check": "mutating-route-without-auth",
73
+ "stack": "django"
74
+ },
75
+ {
76
+ "check": "mutating-route-without-auth",
77
+ "stack": "fastapi"
78
+ },
79
+ {
80
+ "check": "mutating-route-without-auth",
81
+ "stack": "flask"
82
+ },
83
+ {
84
+ "check": "privileged-action-without-audit",
85
+ "stack": "django"
86
+ },
87
+ {
88
+ "check": "privileged-action-without-audit",
89
+ "stack": "fastapi"
90
+ },
91
+ {
92
+ "check": "privileged-action-without-audit",
93
+ "stack": "flask"
94
+ },
95
+ {
96
+ "check": "privileged-field-from-request",
97
+ "stack": "django"
98
+ },
99
+ {
100
+ "check": "privileged-field-from-request",
101
+ "stack": "fastapi"
102
+ },
103
+ {
104
+ "check": "privileged-field-from-request",
105
+ "stack": "flask"
106
+ },
107
+ {
108
+ "check": "redirect-from-request",
109
+ "stack": "django"
110
+ },
111
+ {
112
+ "check": "redirect-from-request",
113
+ "stack": "fastapi"
114
+ },
115
+ {
116
+ "check": "redirect-from-request",
117
+ "stack": "flask"
118
+ },
119
+ {
120
+ "check": "request-url-fetched",
121
+ "stack": "django"
122
+ },
123
+ {
124
+ "check": "request-url-fetched",
125
+ "stack": "fastapi"
126
+ },
127
+ {
128
+ "check": "request-url-fetched",
129
+ "stack": "flask"
130
+ },
131
+ {
132
+ "check": "webhook-verify-before-use",
133
+ "stack": "django"
134
+ },
135
+ {
136
+ "check": "webhook-verify-before-use",
137
+ "stack": "fastapi"
138
+ },
139
+ {
140
+ "check": "webhook-verify-before-use",
141
+ "stack": "flask"
142
+ },
143
+ {
144
+ "check": "write-by-id-without-owner",
145
+ "stack": "django"
146
+ },
147
+ {
148
+ "check": "write-by-id-without-owner",
149
+ "stack": "fastapi"
150
+ },
151
+ {
152
+ "check": "write-by-id-without-owner",
153
+ "stack": "flask"
154
+ }
155
+ ],
156
+ "notes": [
157
+ "Measured on synthetic fixtures with a key kept in this repository. BenchmarkPython (Flask, 2463 routes) matched its decorator count in Phase 2, but no recall figure for planted flaws has been taken on a blind key yet."
158
+ ],
159
+ "recorded": [
160
+ {
161
+ "name": "fastapi/full-stack-fastapi-template (seeded sample of its route registrations)",
162
+ "kind": "third_party",
163
+ "blind_key": true,
164
+ "source": "bench/PHASE6C-MEASURED-2026-10-14.md, recall by bench/phase6c-sample.ts with seed 20261017, three byte identical ci runs",
165
+ "mapped": {
166
+ "what": "entry points (real route registrations)",
167
+ "expected": 23,
168
+ "matched": 23,
169
+ "extra": 0
170
+ },
171
+ "flaws": null,
172
+ "stability": {
173
+ "runs": 3,
174
+ "identical": true
175
+ }
176
+ },
177
+ {
178
+ "name": "healthchecks/healthchecks (seeded sample of its route registrations)",
179
+ "kind": "third_party",
180
+ "blind_key": true,
181
+ "source": "bench/PHASE6C-MEASURED-2026-10-14.md, recall by bench/phase6c-sample.ts with seed 20261017, three byte identical ci runs",
182
+ "mapped": {
183
+ "what": "entry points (real route registrations)",
184
+ "expected": 25,
185
+ "matched": 25,
186
+ "extra": 0
187
+ },
188
+ "flaws": null,
189
+ "stability": {
190
+ "runs": 3,
191
+ "identical": true
192
+ }
193
+ }
194
+ ]
195
+ }
@@ -0,0 +1,119 @@
1
+ {
2
+ "detect": {
3
+ "expected": [
4
+ "django",
5
+ "fastapi",
6
+ "flask",
7
+ "python"
8
+ ],
9
+ "found": [
10
+ "django",
11
+ "django-auth",
12
+ "fastapi",
13
+ "flask",
14
+ "python",
15
+ "sqlite"
16
+ ]
17
+ },
18
+ "engine": "0.5.0",
19
+ "measured": "2026-10-14",
20
+ "measurements": [
21
+ {
22
+ "blind_key": false,
23
+ "flaws": {
24
+ "false_findings": 0,
25
+ "found": 27,
26
+ "planted": 27
27
+ },
28
+ "kind": "synthetic",
29
+ "mapped": {
30
+ "expected": 27,
31
+ "extra": 0,
32
+ "matched": 27,
33
+ "what": "entry points"
34
+ },
35
+ "name": "test/fixtures/map/fail and test/fixtures/map/pass",
36
+ "source": "node bench/packs-measure.ts python (key packs/python/answer-key.json)",
37
+ "stability": {
38
+ "identical": true,
39
+ "runs": 3
40
+ }
41
+ },
42
+ {
43
+ "blind_key": true,
44
+ "flaws": {
45
+ "false_findings": 0,
46
+ "found": 4,
47
+ "planted": 4
48
+ },
49
+ "kind": "synthetic",
50
+ "mapped": {
51
+ "expected": 8,
52
+ "extra": 0,
53
+ "matched": 8,
54
+ "what": "entry points"
55
+ },
56
+ "name": "test/fixtures/prove/flask-sqlite/vulnerable and test/fixtures/prove/flask-sqlite/fixed",
57
+ "source": "node bench/packs-measure.ts python (key kept outside the repository)",
58
+ "stability": {
59
+ "identical": true,
60
+ "runs": 3
61
+ }
62
+ },
63
+ {
64
+ "blind_key": true,
65
+ "flaws": null,
66
+ "kind": "third_party",
67
+ "mapped": {
68
+ "expected": 23,
69
+ "extra": 0,
70
+ "matched": 23,
71
+ "what": "entry points (real route registrations)"
72
+ },
73
+ "name": "fastapi/full-stack-fastapi-template (seeded sample of its route registrations)",
74
+ "source": "bench/PHASE6C-MEASURED-2026-10-14.md, recall by bench/phase6c-sample.ts with seed 20261017, three byte identical ci runs",
75
+ "stability": {
76
+ "identical": true,
77
+ "runs": 3
78
+ }
79
+ },
80
+ {
81
+ "blind_key": true,
82
+ "flaws": null,
83
+ "kind": "third_party",
84
+ "mapped": {
85
+ "expected": 25,
86
+ "extra": 0,
87
+ "matched": 25,
88
+ "what": "entry points (real route registrations)"
89
+ },
90
+ "name": "healthchecks/healthchecks (seeded sample of its route registrations)",
91
+ "source": "bench/PHASE6C-MEASURED-2026-10-14.md, recall by bench/phase6c-sample.ts with seed 20261017, three byte identical ci runs",
92
+ "stability": {
93
+ "identical": true,
94
+ "runs": 3
95
+ }
96
+ }
97
+ ],
98
+ "notes": [
99
+ "Measured on synthetic fixtures with a key kept in this repository. BenchmarkPython (Flask, 2463 routes) matched its decorator count in Phase 2, but no recall figure for planted flaws has been taken on a blind key yet.",
100
+ "Flask with SQLite: four planted authorization flaws and a fixed copy. The key was written before the first measurement.",
101
+ "Correction after the first measurement: the first flaw listed a second check by mistake (a copy of the delete flaw). Nothing else in the key changed.",
102
+ "First measurement on this fixture, before any engine change: 8 of 8 entry points, 3 of 4 flaws found, 6 findings on the fixed copy. The six were checks that did not see the decorators require_user and require_admin as a session read and a role check. The Python vocabulary now names require_* decorators; the fixed copy then gave 1 finding, a missing audit record on the admin route, which was a real gap in the fixture and was repaired in both copies. The measurement is therefore no longer blind for these two decorator names.",
103
+ "The read by id flaw is missed: check.authz.owner-filter-on-id-read does not find it in this layout (a Python SELECT with the id placeholder inside a function that is not in a file the check reads as a handler file).",
104
+ "2026-10-14: the first flaw also accepts check.map.read-by-id-without-owner, which was built in step 6c after these fixtures missed the flaw."
105
+ ],
106
+ "pack": "python",
107
+ "proof": [
108
+ {
109
+ "false_proofs_fixed": 0,
110
+ "identical": true,
111
+ "planted": 4,
112
+ "proven": 4,
113
+ "runs": 3,
114
+ "scope": "Flask with SQLite",
115
+ "source": "bench/results/phase6-flask-metrics-container.json (Colima, 3 rounds, fixture test/fixtures/prove/flask-sqlite)"
116
+ }
117
+ ],
118
+ "schema": 1
119
+ }
@@ -0,0 +1,121 @@
1
+ {
2
+ "schema": 1,
3
+ "id": "python",
4
+ "name": "Python",
5
+ "summary": "Flask, FastAPI, Django and Django REST framework: entry points, protections, taint rules and checks. L4 for Flask with a local SQLite file.",
6
+ "edition": "free",
7
+ "languages": [
8
+ "python"
9
+ ],
10
+ "frameworks": [
11
+ "flask",
12
+ "fastapi",
13
+ "django",
14
+ "quart",
15
+ "sanic",
16
+ "starlette"
17
+ ],
18
+ "level": "L3",
19
+ "scopes": [
20
+ {
21
+ "where": "Flask with SQLite",
22
+ "level": "L4"
23
+ }
24
+ ],
25
+ "limits": [
26
+ "Flask, FastAPI and Django are read; other Python frameworks are not. Planted flaws were not measured on a real application. A view that dispatches by method to decorated functions shows no protection."
27
+ ],
28
+ "parts": {
29
+ "detectors": [
30
+ "python",
31
+ "flask",
32
+ "fastapi",
33
+ "django",
34
+ "quart",
35
+ "sanic",
36
+ "starlette"
37
+ ],
38
+ "extractors": [
39
+ {
40
+ "file": "src/map/py.ts"
41
+ },
42
+ {
43
+ "file": "src/map/py-django.ts"
44
+ }
45
+ ],
46
+ "auth_patterns": [
47
+ {
48
+ "file": "src/map/vocab.ts"
49
+ }
50
+ ],
51
+ "sources_sinks": [
52
+ {
53
+ "file": "rules/semgrep/taint-python.yaml"
54
+ }
55
+ ],
56
+ "rules": [
57
+ {
58
+ "file": "rules/semgrep/taint-python.yaml",
59
+ "tests": [
60
+ "test/fixtures/rules/taint-python.py"
61
+ ]
62
+ }
63
+ ],
64
+ "checks": [
65
+ {
66
+ "id": "check.map.admin-route-without-role"
67
+ },
68
+ {
69
+ "id": "check.map.data-read-without-auth"
70
+ },
71
+ {
72
+ "id": "check.map.mutating-route-without-auth"
73
+ },
74
+ {
75
+ "id": "check.map.privileged-action-without-audit"
76
+ },
77
+ {
78
+ "id": "check.map.privileged-field-from-request"
79
+ },
80
+ {
81
+ "id": "check.map.redirect-from-request"
82
+ },
83
+ {
84
+ "id": "check.map.request-url-fetched"
85
+ },
86
+ {
87
+ "id": "check.map.webhook-verify-before-use"
88
+ },
89
+ {
90
+ "id": "check.map.write-by-id-without-owner"
91
+ },
92
+ {
93
+ "id": "check.map.read-by-id-without-owner"
94
+ },
95
+ {
96
+ "id": "check.authz.admin-role-check"
97
+ },
98
+ {
99
+ "id": "check.authz.owner-filter-on-id-read"
100
+ }
101
+ ],
102
+ "mapping": [
103
+ {
104
+ "file": "src/checks/map/entry-checks.ts"
105
+ }
106
+ ],
107
+ "start_recipe": {
108
+ "file": "src/prove/recipe.ts",
109
+ "recipe": "python-flask"
110
+ }
111
+ },
112
+ "fixture": {
113
+ "dir": "test/fixtures/map/fail",
114
+ "fixed_dir": "test/fixtures/map/pass",
115
+ "answer_keys": [
116
+ "in_repo",
117
+ "outside_repo"
118
+ ],
119
+ "result": "packs/python/fixture-result.json"
120
+ }
121
+ }
@@ -0,0 +1,84 @@
1
+ {
2
+ "pack": "rails",
3
+ "fail_dir": "test/fixtures/map-more/fail",
4
+ "pass_dir": "test/fixtures/map-more/pass",
5
+ "stacks": [
6
+ "rails"
7
+ ],
8
+ "detect_expected": [
9
+ "rails",
10
+ "ruby"
11
+ ],
12
+ "mapped_what": "entry points",
13
+ "mapped": [
14
+ "http_route DELETE /notes/:id",
15
+ "http_route GET /api/export",
16
+ "http_route GET /api/items",
17
+ "http_route POST /admin/users/:id/role",
18
+ "http_route POST /api/import",
19
+ "http_route POST /api/upload",
20
+ "http_route POST /login",
21
+ "http_route POST /notes",
22
+ "webhook POST /webhooks/pay"
23
+ ],
24
+ "flaws": [
25
+ {
26
+ "check": "admin-route-without-role",
27
+ "stack": "rails"
28
+ },
29
+ {
30
+ "check": "data-read-without-auth",
31
+ "stack": "rails"
32
+ },
33
+ {
34
+ "check": "mutating-route-without-auth",
35
+ "stack": "rails"
36
+ },
37
+ {
38
+ "check": "privileged-action-without-audit",
39
+ "stack": "rails"
40
+ },
41
+ {
42
+ "check": "privileged-field-from-request",
43
+ "stack": "rails"
44
+ },
45
+ {
46
+ "check": "redirect-from-request",
47
+ "stack": "rails"
48
+ },
49
+ {
50
+ "check": "request-url-fetched",
51
+ "stack": "rails"
52
+ },
53
+ {
54
+ "check": "webhook-verify-before-use",
55
+ "stack": "rails"
56
+ },
57
+ {
58
+ "check": "write-by-id-without-owner",
59
+ "stack": "rails"
60
+ }
61
+ ],
62
+ "notes": [
63
+ "Synthetic fixture only. No real Rails application has been measured."
64
+ ],
65
+ "recorded": [
66
+ {
67
+ "name": "lobsters/lobsters (seeded sample of its route registrations)",
68
+ "kind": "third_party",
69
+ "blind_key": true,
70
+ "source": "bench/PHASE6C-MEASURED-2026-10-14.md, recall by bench/phase6c-sample.ts with seed 20261017, three byte identical ci runs",
71
+ "mapped": {
72
+ "what": "entry points (real route registrations)",
73
+ "expected": 25,
74
+ "matched": 25,
75
+ "extra": 0
76
+ },
77
+ "flaws": null,
78
+ "stability": {
79
+ "runs": 3,
80
+ "identical": true
81
+ }
82
+ }
83
+ ]
84
+ }
@@ -0,0 +1,60 @@
1
+ {
2
+ "detect": {
3
+ "expected": [
4
+ "rails",
5
+ "ruby"
6
+ ],
7
+ "found": [
8
+ "rails",
9
+ "ruby"
10
+ ]
11
+ },
12
+ "engine": "0.5.0",
13
+ "measured": "2026-10-14",
14
+ "measurements": [
15
+ {
16
+ "blind_key": false,
17
+ "flaws": {
18
+ "false_findings": 0,
19
+ "found": 9,
20
+ "planted": 9
21
+ },
22
+ "kind": "synthetic",
23
+ "mapped": {
24
+ "expected": 9,
25
+ "extra": 0,
26
+ "matched": 9,
27
+ "what": "entry points"
28
+ },
29
+ "name": "test/fixtures/map-more/fail and test/fixtures/map-more/pass",
30
+ "source": "node bench/packs-measure.ts rails (key packs/rails/answer-key.json)",
31
+ "stability": {
32
+ "identical": true,
33
+ "runs": 3
34
+ }
35
+ },
36
+ {
37
+ "blind_key": true,
38
+ "flaws": null,
39
+ "kind": "third_party",
40
+ "mapped": {
41
+ "expected": 25,
42
+ "extra": 0,
43
+ "matched": 25,
44
+ "what": "entry points (real route registrations)"
45
+ },
46
+ "name": "lobsters/lobsters (seeded sample of its route registrations)",
47
+ "source": "bench/PHASE6C-MEASURED-2026-10-14.md, recall by bench/phase6c-sample.ts with seed 20261017, three byte identical ci runs",
48
+ "stability": {
49
+ "identical": true,
50
+ "runs": 3
51
+ }
52
+ }
53
+ ],
54
+ "notes": [
55
+ "Synthetic fixture only. No real Rails application has been measured."
56
+ ],
57
+ "pack": "rails",
58
+ "proof": [],
59
+ "schema": 1
60
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "schema": 1,
3
+ "id": "rails",
4
+ "name": "Ruby on Rails",
5
+ "summary": "config/routes.rb joined to controller actions and their before_action filters, with checks.",
6
+ "edition": "free",
7
+ "languages": [
8
+ "ruby"
9
+ ],
10
+ "frameworks": [
11
+ "rails"
12
+ ],
13
+ "level": "L2",
14
+ "limits": [
15
+ "Planted flaws were not measured on a real application. A filter that only looks a user up is told apart from one that blocks a guest by reading its body, which other shapes of filter may defeat."
16
+ ],
17
+ "parts": {
18
+ "detectors": [
19
+ "ruby",
20
+ "rails"
21
+ ],
22
+ "extractors": [
23
+ {
24
+ "file": "src/map/rails.ts"
25
+ }
26
+ ],
27
+ "auth_patterns": [
28
+ {
29
+ "file": "src/map/light-profiles.ts"
30
+ }
31
+ ],
32
+ "checks": [
33
+ {
34
+ "id": "check.map.admin-route-without-role"
35
+ },
36
+ {
37
+ "id": "check.map.data-read-without-auth"
38
+ },
39
+ {
40
+ "id": "check.map.mutating-route-without-auth"
41
+ },
42
+ {
43
+ "id": "check.map.privileged-action-without-audit"
44
+ },
45
+ {
46
+ "id": "check.map.privileged-field-from-request"
47
+ },
48
+ {
49
+ "id": "check.map.redirect-from-request"
50
+ },
51
+ {
52
+ "id": "check.map.request-url-fetched"
53
+ },
54
+ {
55
+ "id": "check.map.webhook-verify-before-use"
56
+ },
57
+ {
58
+ "id": "check.map.write-by-id-without-owner"
59
+ },
60
+ {
61
+ "id": "check.map.read-by-id-without-owner"
62
+ }
63
+ ],
64
+ "mapping": [
65
+ {
66
+ "file": "src/checks/map/entry-checks.ts"
67
+ }
68
+ ]
69
+ },
70
+ "fixture": {
71
+ "dir": "test/fixtures/map-more/fail",
72
+ "fixed_dir": "test/fixtures/map-more/pass",
73
+ "answer_keys": [
74
+ "in_repo"
75
+ ],
76
+ "result": "packs/rails/fixture-result.json"
77
+ }
78
+ }
@@ -0,0 +1,43 @@
1
+ {
2
+ "detect": {
3
+ "expected": [
4
+ "axum",
5
+ "rust"
6
+ ],
7
+ "found": [
8
+ "axum",
9
+ "rust"
10
+ ]
11
+ },
12
+ "engine": "0.5.0",
13
+ "measured": "2026-10-14",
14
+ "measurements": [
15
+ {
16
+ "blind_key": true,
17
+ "flaws": {
18
+ "false_findings": 0,
19
+ "found": 3,
20
+ "planted": 6
21
+ },
22
+ "kind": "synthetic",
23
+ "mapped": {
24
+ "expected": 10,
25
+ "extra": 0,
26
+ "matched": 10,
27
+ "what": "entry points"
28
+ },
29
+ "name": "test/fixtures/packs/rust/fail and test/fixtures/packs/rust/pass",
30
+ "source": "node bench/packs-measure.ts rust (key kept outside the repository)",
31
+ "stability": {
32
+ "identical": true,
33
+ "runs": 3
34
+ }
35
+ }
36
+ ],
37
+ "notes": [
38
+ "Rust service on axum: six planted flaws and a fixed copy. Two are settled by checks that belong to the Pro edition. The export route flaw needs a read of the handler body, which the Rust reader does not do. Written before the Rust extractor existed."
39
+ ],
40
+ "pack": "rust",
41
+ "proof": [],
42
+ "schema": 1
43
+ }