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,84 @@
1
+ {
2
+ "pack": "laravel",
3
+ "fail_dir": "test/fixtures/map-more/fail",
4
+ "pass_dir": "test/fixtures/map-more/pass",
5
+ "stacks": [
6
+ "laravel"
7
+ ],
8
+ "detect_expected": [
9
+ "laravel",
10
+ "php"
11
+ ],
12
+ "mapped_what": "entry points",
13
+ "mapped": [
14
+ "http_route DELETE /notes/:note",
15
+ "http_route GET /api/export",
16
+ "http_route GET /api/items",
17
+ "http_route POST /admin/users/:user/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": "laravel"
28
+ },
29
+ {
30
+ "check": "data-read-without-auth",
31
+ "stack": "laravel"
32
+ },
33
+ {
34
+ "check": "mutating-route-without-auth",
35
+ "stack": "laravel"
36
+ },
37
+ {
38
+ "check": "privileged-action-without-audit",
39
+ "stack": "laravel"
40
+ },
41
+ {
42
+ "check": "privileged-field-from-request",
43
+ "stack": "laravel"
44
+ },
45
+ {
46
+ "check": "redirect-from-request",
47
+ "stack": "laravel"
48
+ },
49
+ {
50
+ "check": "request-url-fetched",
51
+ "stack": "laravel"
52
+ },
53
+ {
54
+ "check": "webhook-verify-before-use",
55
+ "stack": "laravel"
56
+ },
57
+ {
58
+ "check": "write-by-id-without-owner",
59
+ "stack": "laravel"
60
+ }
61
+ ],
62
+ "notes": [
63
+ "Synthetic fixture only. No real Laravel application has been measured."
64
+ ],
65
+ "recorded": [
66
+ {
67
+ "name": "koel/koel (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
+ "laravel",
5
+ "php"
6
+ ],
7
+ "found": [
8
+ "laravel",
9
+ "php"
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 laravel (key packs/laravel/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": "koel/koel (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 Laravel application has been measured."
56
+ ],
57
+ "pack": "laravel",
58
+ "proof": [],
59
+ "schema": 1
60
+ }
@@ -0,0 +1,91 @@
1
+ {
2
+ "schema": 1,
3
+ "id": "laravel",
4
+ "name": "PHP and Laravel",
5
+ "summary": "routes/*.php joined to controllers with their middleware, policies and form requests, taint rules and checks.",
6
+ "edition": "free",
7
+ "languages": [
8
+ "php"
9
+ ],
10
+ "frameworks": [
11
+ "laravel"
12
+ ],
13
+ "level": "L2",
14
+ "limits": [
15
+ "Planted flaws were not measured on a real application."
16
+ ],
17
+ "parts": {
18
+ "detectors": [
19
+ "php",
20
+ "laravel"
21
+ ],
22
+ "extractors": [
23
+ {
24
+ "file": "src/map/laravel.ts"
25
+ }
26
+ ],
27
+ "auth_patterns": [
28
+ {
29
+ "file": "src/map/light-profiles.ts"
30
+ }
31
+ ],
32
+ "sources_sinks": [
33
+ {
34
+ "file": "rules/semgrep/taint-php.yaml"
35
+ }
36
+ ],
37
+ "rules": [
38
+ {
39
+ "file": "rules/semgrep/taint-php.yaml",
40
+ "tests": [
41
+ "test/fixtures/rules/taint-php.php"
42
+ ]
43
+ }
44
+ ],
45
+ "checks": [
46
+ {
47
+ "id": "check.map.admin-route-without-role"
48
+ },
49
+ {
50
+ "id": "check.map.data-read-without-auth"
51
+ },
52
+ {
53
+ "id": "check.map.mutating-route-without-auth"
54
+ },
55
+ {
56
+ "id": "check.map.privileged-action-without-audit"
57
+ },
58
+ {
59
+ "id": "check.map.privileged-field-from-request"
60
+ },
61
+ {
62
+ "id": "check.map.redirect-from-request"
63
+ },
64
+ {
65
+ "id": "check.map.request-url-fetched"
66
+ },
67
+ {
68
+ "id": "check.map.webhook-verify-before-use"
69
+ },
70
+ {
71
+ "id": "check.map.write-by-id-without-owner"
72
+ },
73
+ {
74
+ "id": "check.map.read-by-id-without-owner"
75
+ }
76
+ ],
77
+ "mapping": [
78
+ {
79
+ "file": "src/checks/map/entry-checks.ts"
80
+ }
81
+ ]
82
+ },
83
+ "fixture": {
84
+ "dir": "test/fixtures/map-more/fail",
85
+ "fixed_dir": "test/fixtures/map-more/pass",
86
+ "answer_keys": [
87
+ "in_repo"
88
+ ],
89
+ "result": "packs/laravel/fixture-result.json"
90
+ }
91
+ }
@@ -0,0 +1,220 @@
1
+ {
2
+ "pack": "node-ts",
3
+ "fail_dir": "test/fixtures/map/fail",
4
+ "pass_dir": "test/fixtures/map/pass",
5
+ "stacks": [
6
+ "express",
7
+ "nextapp",
8
+ "nest"
9
+ ],
10
+ "detect_expected": [
11
+ "express",
12
+ "nextjs",
13
+ "javascript",
14
+ "typescript"
15
+ ],
16
+ "mapped_what": "entry points",
17
+ "mapped": [
18
+ "http_route DELETE /api/notes/:id",
19
+ "http_route DELETE /api/notes/:id",
20
+ "http_route DELETE /notes/:id",
21
+ "http_route GET /api/export",
22
+ "http_route GET /api/export",
23
+ "http_route GET /api/items",
24
+ "http_route GET /api/items",
25
+ "http_route GET /notes",
26
+ "http_route GET /notes/export",
27
+ "http_route POST /admin/users/role",
28
+ "http_route POST /api/admin/users",
29
+ "http_route POST /api/admin/users",
30
+ "http_route POST /api/import",
31
+ "http_route POST /api/import",
32
+ "http_route POST /api/login",
33
+ "http_route POST /api/login",
34
+ "http_route POST /api/notes",
35
+ "http_route POST /api/notes",
36
+ "http_route POST /api/upload",
37
+ "http_route POST /api/upload",
38
+ "http_route POST /notes",
39
+ "http_route POST /notes/upload",
40
+ "server_action POST updateProfile",
41
+ "webhook POST /api/webhooks/pay",
42
+ "webhook POST /webhooks/pay",
43
+ "webhook POST /webhooks/pay"
44
+ ],
45
+ "flaws": [
46
+ {
47
+ "check": "admin-route-without-role",
48
+ "stack": "express"
49
+ },
50
+ {
51
+ "check": "admin-route-without-role",
52
+ "stack": "nest"
53
+ },
54
+ {
55
+ "check": "admin-route-without-role",
56
+ "stack": "nextapp"
57
+ },
58
+ {
59
+ "check": "data-read-without-auth",
60
+ "stack": "express"
61
+ },
62
+ {
63
+ "check": "data-read-without-auth",
64
+ "stack": "nest"
65
+ },
66
+ {
67
+ "check": "data-read-without-auth",
68
+ "stack": "nextapp"
69
+ },
70
+ {
71
+ "check": "mutating-route-without-auth",
72
+ "stack": "express"
73
+ },
74
+ {
75
+ "check": "mutating-route-without-auth",
76
+ "stack": "nest"
77
+ },
78
+ {
79
+ "check": "mutating-route-without-auth",
80
+ "stack": "nextapp"
81
+ },
82
+ {
83
+ "check": "privileged-action-without-audit",
84
+ "stack": "express"
85
+ },
86
+ {
87
+ "check": "privileged-action-without-audit",
88
+ "stack": "nest"
89
+ },
90
+ {
91
+ "check": "privileged-action-without-audit",
92
+ "stack": "nextapp"
93
+ },
94
+ {
95
+ "check": "privileged-field-from-request",
96
+ "stack": "express"
97
+ },
98
+ {
99
+ "check": "privileged-field-from-request",
100
+ "stack": "nest"
101
+ },
102
+ {
103
+ "check": "privileged-field-from-request",
104
+ "stack": "nextapp"
105
+ },
106
+ {
107
+ "check": "redirect-from-request",
108
+ "stack": "express"
109
+ },
110
+ {
111
+ "check": "redirect-from-request",
112
+ "stack": "nextapp"
113
+ },
114
+ {
115
+ "check": "request-url-fetched",
116
+ "stack": "express"
117
+ },
118
+ {
119
+ "check": "request-url-fetched",
120
+ "stack": "nextapp"
121
+ },
122
+ {
123
+ "check": "webhook-verify-before-use",
124
+ "stack": "express"
125
+ },
126
+ {
127
+ "check": "webhook-verify-before-use",
128
+ "stack": "nest"
129
+ },
130
+ {
131
+ "check": "webhook-verify-before-use",
132
+ "stack": "nextapp"
133
+ },
134
+ {
135
+ "check": "write-by-id-without-owner",
136
+ "stack": "express"
137
+ },
138
+ {
139
+ "check": "write-by-id-without-owner",
140
+ "stack": "nest"
141
+ },
142
+ {
143
+ "check": "write-by-id-without-owner",
144
+ "stack": "nextapp"
145
+ }
146
+ ],
147
+ "recorded": [
148
+ {
149
+ "name": "hullproof-demo",
150
+ "kind": "demo",
151
+ "blind_key": true,
152
+ "source": "bench/PHASE2-MEASURED-2026-10-11.md sections 2.1 and 2.2 (open core rules, new checks as leads), key from the Pro repository, the whole demo app, which includes flaws in Supabase configuration, infrastructure files and CI as well as in application code, so this recall belongs to the engine on this app and not to this pack alone",
153
+ "mapped": {
154
+ "what": "entry points",
155
+ "expected": 27,
156
+ "matched": 27,
157
+ "extra": 0
158
+ },
159
+ "flaws": {
160
+ "planted": 30,
161
+ "found": 20,
162
+ "false_findings": 0
163
+ },
164
+ "stability": {
165
+ "runs": 3,
166
+ "identical": true
167
+ }
168
+ },
169
+ {
170
+ "name": "mikro-orm/nestjs-realworld-example-app (seeded sample of its route registrations)",
171
+ "kind": "third_party",
172
+ "blind_key": true,
173
+ "source": "bench/PHASE6C-MEASURED-2026-10-14.md, recall by bench/phase6c-sample.ts with seed 20261017, three byte identical ci runs",
174
+ "mapped": {
175
+ "what": "entry points (real route registrations)",
176
+ "expected": 21,
177
+ "matched": 21,
178
+ "extra": 0
179
+ },
180
+ "flaws": null,
181
+ "stability": {
182
+ "runs": 3,
183
+ "identical": true
184
+ }
185
+ },
186
+ {
187
+ "name": "vercel/commerce (seeded sample of its route registrations)",
188
+ "kind": "third_party",
189
+ "blind_key": true,
190
+ "source": "bench/PHASE6C-MEASURED-2026-10-14.md, recall by bench/phase6c-sample.ts with seed 20261017, three byte identical ci runs",
191
+ "mapped": {
192
+ "what": "entry points (real route registrations)",
193
+ "expected": 6,
194
+ "matched": 6,
195
+ "extra": 0
196
+ },
197
+ "flaws": null,
198
+ "stability": {
199
+ "runs": 3,
200
+ "identical": true
201
+ }
202
+ }
203
+ ],
204
+ "proof": [
205
+ {
206
+ "scope": "Express with SQLite",
207
+ "planted": 4,
208
+ "proven": 4,
209
+ "runs": 3,
210
+ "false_proofs_fixed": 0,
211
+ "identical": true,
212
+ "source": "bench/PHASE4-MEASURED-2026-10-14.md (Colima, fixture test/fixtures/prove/express-sqlite)"
213
+ }
214
+ ],
215
+ "notes": [
216
+ "Entry points and flaws on the synthetic fixture come from a key kept in this repository, so that measurement is not blind. The blind measurement is the demo app, whose key lives in the Pro repository.",
217
+ "Express with SQLite is the only stack with a start recipe, measured on one fixture app. Next.js and NestJS entry points were measured on the demo and on Juice Shop only.",
218
+ "The NestJS fixture has no package.json, so NestJS detection is not exercised by it; its entry points are."
219
+ ]
220
+ }
@@ -0,0 +1,114 @@
1
+ {
2
+ "detect": {
3
+ "expected": [
4
+ "express",
5
+ "javascript",
6
+ "nextjs",
7
+ "typescript"
8
+ ],
9
+ "found": [
10
+ "express",
11
+ "javascript",
12
+ "nextjs",
13
+ "typescript"
14
+ ]
15
+ },
16
+ "engine": "0.5.0",
17
+ "measured": "2026-10-14",
18
+ "measurements": [
19
+ {
20
+ "blind_key": false,
21
+ "flaws": {
22
+ "false_findings": 0,
23
+ "found": 25,
24
+ "planted": 25
25
+ },
26
+ "kind": "synthetic",
27
+ "mapped": {
28
+ "expected": 26,
29
+ "extra": 0,
30
+ "matched": 26,
31
+ "what": "entry points"
32
+ },
33
+ "name": "test/fixtures/map/fail and test/fixtures/map/pass",
34
+ "source": "node bench/packs-measure.ts node-ts (key packs/node-ts/answer-key.json)",
35
+ "stability": {
36
+ "identical": true,
37
+ "runs": 3
38
+ }
39
+ },
40
+ {
41
+ "blind_key": true,
42
+ "flaws": {
43
+ "false_findings": 0,
44
+ "found": 20,
45
+ "planted": 30
46
+ },
47
+ "kind": "demo",
48
+ "mapped": {
49
+ "expected": 27,
50
+ "extra": 0,
51
+ "matched": 27,
52
+ "what": "entry points"
53
+ },
54
+ "name": "hullproof-demo",
55
+ "source": "bench/PHASE2-MEASURED-2026-10-11.md sections 2.1 and 2.2 (open core rules, new checks as leads), key from the Pro repository, the whole demo app, which includes flaws in Supabase configuration, infrastructure files and CI as well as in application code, so this recall belongs to the engine on this app and not to this pack alone",
56
+ "stability": {
57
+ "identical": true,
58
+ "runs": 3
59
+ }
60
+ },
61
+ {
62
+ "blind_key": true,
63
+ "flaws": null,
64
+ "kind": "third_party",
65
+ "mapped": {
66
+ "expected": 21,
67
+ "extra": 0,
68
+ "matched": 21,
69
+ "what": "entry points (real route registrations)"
70
+ },
71
+ "name": "mikro-orm/nestjs-realworld-example-app (seeded sample of its route registrations)",
72
+ "source": "bench/PHASE6C-MEASURED-2026-10-14.md, recall by bench/phase6c-sample.ts with seed 20261017, three byte identical ci runs",
73
+ "stability": {
74
+ "identical": true,
75
+ "runs": 3
76
+ }
77
+ },
78
+ {
79
+ "blind_key": true,
80
+ "flaws": null,
81
+ "kind": "third_party",
82
+ "mapped": {
83
+ "expected": 6,
84
+ "extra": 0,
85
+ "matched": 6,
86
+ "what": "entry points (real route registrations)"
87
+ },
88
+ "name": "vercel/commerce (seeded sample of its route registrations)",
89
+ "source": "bench/PHASE6C-MEASURED-2026-10-14.md, recall by bench/phase6c-sample.ts with seed 20261017, three byte identical ci runs",
90
+ "stability": {
91
+ "identical": true,
92
+ "runs": 3
93
+ }
94
+ }
95
+ ],
96
+ "notes": [
97
+ "Entry points and flaws on the synthetic fixture come from a key kept in this repository, so that measurement is not blind. The blind measurement is the demo app, whose key lives in the Pro repository.",
98
+ "Express with SQLite is the only stack with a start recipe, measured on one fixture app. Next.js and NestJS entry points were measured on the demo and on Juice Shop only.",
99
+ "The NestJS fixture has no package.json, so NestJS detection is not exercised by it; its entry points are."
100
+ ],
101
+ "pack": "node-ts",
102
+ "proof": [
103
+ {
104
+ "false_proofs_fixed": 0,
105
+ "identical": true,
106
+ "planted": 4,
107
+ "proven": 4,
108
+ "runs": 3,
109
+ "scope": "Express with SQLite",
110
+ "source": "bench/PHASE4-MEASURED-2026-10-14.md (Colima, fixture test/fixtures/prove/express-sqlite)"
111
+ }
112
+ ],
113
+ "schema": 1
114
+ }
@@ -0,0 +1,134 @@
1
+ {
2
+ "schema": 1,
3
+ "id": "node-ts",
4
+ "name": "Node and TypeScript",
5
+ "summary": "Next.js, Express and Fastify family, NestJS and tRPC: entry points, protections, taint rules and checks. L4 for Express with a local SQLite file.",
6
+ "edition": "free",
7
+ "languages": [
8
+ "javascript",
9
+ "typescript"
10
+ ],
11
+ "frameworks": [
12
+ "nextjs",
13
+ "express",
14
+ "fastify",
15
+ "koa",
16
+ "hono",
17
+ "nestjs",
18
+ "trpc"
19
+ ],
20
+ "level": "L3",
21
+ "scopes": [
22
+ {
23
+ "where": "Express with SQLite",
24
+ "level": "L4"
25
+ }
26
+ ],
27
+ "limits": [
28
+ "Planted flaws were not measured on a real application. Routes that a library creates at run time and socket.io handlers are not read. A handler that passes the request to a helper which checks a secret is not followed."
29
+ ],
30
+ "parts": {
31
+ "detectors": [
32
+ "javascript",
33
+ "typescript",
34
+ "nextjs",
35
+ "express",
36
+ "fastify",
37
+ "koa",
38
+ "hono",
39
+ "nestjs",
40
+ "trpc"
41
+ ],
42
+ "extractors": [
43
+ {
44
+ "file": "src/map/js-express.ts"
45
+ },
46
+ {
47
+ "file": "src/map/js-next.ts"
48
+ },
49
+ {
50
+ "file": "src/map/js-misc.ts"
51
+ }
52
+ ],
53
+ "auth_patterns": [
54
+ {
55
+ "file": "src/map/vocab.ts"
56
+ }
57
+ ],
58
+ "sources_sinks": [
59
+ {
60
+ "file": "rules/semgrep/taint-javascript.yaml"
61
+ }
62
+ ],
63
+ "rules": [
64
+ {
65
+ "file": "rules/semgrep/taint-javascript.yaml",
66
+ "tests": [
67
+ "test/fixtures/rules/taint-javascript.js",
68
+ "test/fixtures/rules/taint-javascript.tsx"
69
+ ]
70
+ }
71
+ ],
72
+ "checks": [
73
+ {
74
+ "id": "check.map.admin-route-without-role"
75
+ },
76
+ {
77
+ "id": "check.map.data-read-without-auth"
78
+ },
79
+ {
80
+ "id": "check.map.mutating-route-without-auth"
81
+ },
82
+ {
83
+ "id": "check.map.privileged-action-without-audit"
84
+ },
85
+ {
86
+ "id": "check.map.privileged-field-from-request"
87
+ },
88
+ {
89
+ "id": "check.map.redirect-from-request"
90
+ },
91
+ {
92
+ "id": "check.map.request-url-fetched"
93
+ },
94
+ {
95
+ "id": "check.map.webhook-verify-before-use"
96
+ },
97
+ {
98
+ "id": "check.map.write-by-id-without-owner"
99
+ },
100
+ {
101
+ "id": "check.map.read-by-id-without-owner"
102
+ },
103
+ {
104
+ "id": "check.web.cors-no-reflected-origin"
105
+ },
106
+ {
107
+ "id": "check.api.webhook-verified-before-use"
108
+ },
109
+ {
110
+ "id": "check.authz.owner-filter-on-id-read"
111
+ },
112
+ {
113
+ "id": "check.authz.admin-role-check"
114
+ }
115
+ ],
116
+ "mapping": [
117
+ {
118
+ "file": "src/checks/map/entry-checks.ts"
119
+ }
120
+ ],
121
+ "start_recipe": {
122
+ "file": "src/prove/recipe.ts",
123
+ "recipe": "node-express"
124
+ }
125
+ },
126
+ "fixture": {
127
+ "dir": "test/fixtures/map/fail",
128
+ "fixed_dir": "test/fixtures/map/pass",
129
+ "answer_keys": [
130
+ "in_repo"
131
+ ],
132
+ "result": "packs/node-ts/fixture-result.json"
133
+ }
134
+ }