sloptic 1.1.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 (267) hide show
  1. sloptic-1.1.0/.gitignore +36 -0
  2. sloptic-1.1.0/CONTRIBUTING.md +162 -0
  3. sloptic-1.1.0/CORPUS_REPORT.md +220 -0
  4. sloptic-1.1.0/LICENSE +201 -0
  5. sloptic-1.1.0/PKG-INFO +177 -0
  6. sloptic-1.1.0/README.md +156 -0
  7. sloptic-1.1.0/RELEASE_NOTES.md +135 -0
  8. sloptic-1.1.0/catalog/performance/perf-cache-001.yaml +15 -0
  9. sloptic-1.1.0/catalog/performance/perf-compress-001.yaml +13 -0
  10. sloptic-1.1.0/catalog/performance/perf-cwv-001.yaml +14 -0
  11. sloptic-1.1.0/catalog/performance/perf-cwv-002.yaml +17 -0
  12. sloptic-1.1.0/catalog/performance/perf-load-001.yaml +12 -0
  13. sloptic-1.1.0/catalog/performance/perf-loadtime-001.yaml +12 -0
  14. sloptic-1.1.0/catalog/performance/perf-requests-001.yaml +12 -0
  15. sloptic-1.1.0/catalog/performance/perf-ttfb-001.yaml +13 -0
  16. sloptic-1.1.0/catalog/performance/perf-ttfb-002.yaml +14 -0
  17. sloptic-1.1.0/catalog/performance/perf-ttfb-003.yaml +14 -0
  18. sloptic-1.1.0/catalog/performance/perf-weight-001.yaml +14 -0
  19. sloptic-1.1.0/catalog/performance/perf-weight-002.yaml +14 -0
  20. sloptic-1.1.0/catalog/qa/qa-a11y-001.yaml +23 -0
  21. sloptic-1.1.0/catalog/qa/qa-a11y-002.yaml +16 -0
  22. sloptic-1.1.0/catalog/qa/qa-backnav-001.yaml +15 -0
  23. sloptic-1.1.0/catalog/qa/qa-chunk-001.yaml +14 -0
  24. sloptic-1.1.0/catalog/qa/qa-console-001.yaml +12 -0
  25. sloptic-1.1.0/catalog/qa/qa-crash-010.yaml +17 -0
  26. sloptic-1.1.0/catalog/qa/qa-ctype-001.yaml +12 -0
  27. sloptic-1.1.0/catalog/qa/qa-deadctrl-001.yaml +16 -0
  28. sloptic-1.1.0/catalog/qa/qa-deeplink-001.yaml +16 -0
  29. sloptic-1.1.0/catalog/qa/qa-devbuild-001.yaml +47 -0
  30. sloptic-1.1.0/catalog/qa/qa-errhyg-001.yaml +12 -0
  31. sloptic-1.1.0/catalog/qa/qa-http-001.yaml +13 -0
  32. sloptic-1.1.0/catalog/qa/qa-http-002.yaml +13 -0
  33. sloptic-1.1.0/catalog/qa/qa-input-001.yaml +16 -0
  34. sloptic-1.1.0/catalog/qa/qa-integrity-001.yaml +12 -0
  35. sloptic-1.1.0/catalog/qa/qa-integrity-002.yaml +14 -0
  36. sloptic-1.1.0/catalog/qa/qa-links-001.yaml +16 -0
  37. sloptic-1.1.0/catalog/qa/qa-noerror-001.yaml +17 -0
  38. sloptic-1.1.0/catalog/qa/qa-race-001.yaml +12 -0
  39. sloptic-1.1.0/catalog/qa/qa-race-002.yaml +16 -0
  40. sloptic-1.1.0/catalog/qa/qa-seo-001.yaml +14 -0
  41. sloptic-1.1.0/catalog/qa/qa-staleui-001.yaml +16 -0
  42. sloptic-1.1.0/catalog/security/sec-authbypass-001.yaml +14 -0
  43. sloptic-1.1.0/catalog/security/sec-backend-001.yaml +14 -0
  44. sloptic-1.1.0/catalog/security/sec-backend-002.yaml +20 -0
  45. sloptic-1.1.0/catalog/security/sec-backend-003.yaml +24 -0
  46. sloptic-1.1.0/catalog/security/sec-cmdi-001.yaml +13 -0
  47. sloptic-1.1.0/catalog/security/sec-cors-001.yaml +14 -0
  48. sloptic-1.1.0/catalog/security/sec-csp-001.yaml +15 -0
  49. sloptic-1.1.0/catalog/security/sec-csrf-001.yaml +10 -0
  50. sloptic-1.1.0/catalog/security/sec-debug-001.yaml +11 -0
  51. sloptic-1.1.0/catalog/security/sec-deps-001.yaml +15 -0
  52. sloptic-1.1.0/catalog/security/sec-domxss-001.yaml +10 -0
  53. sloptic-1.1.0/catalog/security/sec-dos-001.yaml +12 -0
  54. sloptic-1.1.0/catalog/security/sec-exposure-001.yaml +12 -0
  55. sloptic-1.1.0/catalog/security/sec-exposure-002.yaml +13 -0
  56. sloptic-1.1.0/catalog/security/sec-exposure-003.yaml +13 -0
  57. sloptic-1.1.0/catalog/security/sec-exposure-004.yaml +12 -0
  58. sloptic-1.1.0/catalog/security/sec-exposure-005.yaml +14 -0
  59. sloptic-1.1.0/catalog/security/sec-exposure-006.yaml +11 -0
  60. sloptic-1.1.0/catalog/security/sec-exposure-007.yaml +18 -0
  61. sloptic-1.1.0/catalog/security/sec-exposure-008.yaml +25 -0
  62. sloptic-1.1.0/catalog/security/sec-filterinj-001.yaml +28 -0
  63. sloptic-1.1.0/catalog/security/sec-headers-001.yaml +12 -0
  64. sloptic-1.1.0/catalog/security/sec-headers-002.yaml +19 -0
  65. sloptic-1.1.0/catalog/security/sec-headers-003.yaml +12 -0
  66. sloptic-1.1.0/catalog/security/sec-headers-004.yaml +12 -0
  67. sloptic-1.1.0/catalog/security/sec-headers-005.yaml +12 -0
  68. sloptic-1.1.0/catalog/security/sec-headers-006.yaml +12 -0
  69. sloptic-1.1.0/catalog/security/sec-hosthdr-001.yaml +12 -0
  70. sloptic-1.1.0/catalog/security/sec-idor-001.yaml +10 -0
  71. sloptic-1.1.0/catalog/security/sec-idor-002.yaml +11 -0
  72. sloptic-1.1.0/catalog/security/sec-idor-003.yaml +11 -0
  73. sloptic-1.1.0/catalog/security/sec-idor-004.yaml +12 -0
  74. sloptic-1.1.0/catalog/security/sec-idor-005.yaml +19 -0
  75. sloptic-1.1.0/catalog/security/sec-lfi-001.yaml +13 -0
  76. sloptic-1.1.0/catalog/security/sec-mixed-001.yaml +13 -0
  77. sloptic-1.1.0/catalog/security/sec-ratelimit-001.yaml +13 -0
  78. sloptic-1.1.0/catalog/security/sec-redirect-001.yaml +10 -0
  79. sloptic-1.1.0/catalog/security/sec-secrets-001.yaml +13 -0
  80. sloptic-1.1.0/catalog/security/sec-secrets-002.yaml +12 -0
  81. sloptic-1.1.0/catalog/security/sec-session-001.yaml +11 -0
  82. sloptic-1.1.0/catalog/security/sec-session-002.yaml +11 -0
  83. sloptic-1.1.0/catalog/security/sec-session-003.yaml +13 -0
  84. sloptic-1.1.0/catalog/security/sec-session-004.yaml +11 -0
  85. sloptic-1.1.0/catalog/security/sec-session-005.yaml +11 -0
  86. sloptic-1.1.0/catalog/security/sec-split-001.yaml +12 -0
  87. sloptic-1.1.0/catalog/security/sec-sqli-001.yaml +12 -0
  88. sloptic-1.1.0/catalog/security/sec-sqli-002.yaml +12 -0
  89. sloptic-1.1.0/catalog/security/sec-sqli-003.yaml +12 -0
  90. sloptic-1.1.0/catalog/security/sec-sqli-004.yaml +17 -0
  91. sloptic-1.1.0/catalog/security/sec-sqli-005.yaml +12 -0
  92. sloptic-1.1.0/catalog/security/sec-ssrf-001.yaml +10 -0
  93. sloptic-1.1.0/catalog/security/sec-ssti-001.yaml +13 -0
  94. sloptic-1.1.0/catalog/security/sec-upload-001.yaml +12 -0
  95. sloptic-1.1.0/catalog/security/sec-upload-002.yaml +15 -0
  96. sloptic-1.1.0/catalog/security/sec-xss-001.yaml +19 -0
  97. sloptic-1.1.0/catalog/security/sec-xss-002.yaml +17 -0
  98. sloptic-1.1.0/catalog/security/sec-xxe-001.yaml +10 -0
  99. sloptic-1.1.0/claude.md +448 -0
  100. sloptic-1.1.0/pyproject.toml +59 -0
  101. sloptic-1.1.0/references/hardened/Dockerfile +8 -0
  102. sloptic-1.1.0/references/hardened/app.py +242 -0
  103. sloptic-1.1.0/references/jsonapi/app.py +183 -0
  104. sloptic-1.1.0/references/minimal/Dockerfile +8 -0
  105. sloptic-1.1.0/references/minimal/app.py +41 -0
  106. sloptic-1.1.0/references/qa-janky/app.py +79 -0
  107. sloptic-1.1.0/references/spa/app.py +73 -0
  108. sloptic-1.1.0/references/vulnerable/Dockerfile +8 -0
  109. sloptic-1.1.0/references/vulnerable/app.py +248 -0
  110. sloptic-1.1.0/scripts/benchmark.py +458 -0
  111. sloptic-1.1.0/scripts/charts.py +267 -0
  112. sloptic-1.1.0/scripts/deploy_and_grade.py +1489 -0
  113. sloptic-1.1.0/scripts/devpost_repos.py +287 -0
  114. sloptic-1.1.0/scripts/gapbench_run.py +418 -0
  115. sloptic-1.1.0/scripts/gapbench_score.py +300 -0
  116. sloptic-1.1.0/scripts/list_probes.py +103 -0
  117. sloptic-1.1.0/scripts/parity.py +262 -0
  118. sloptic-1.1.0/scripts/precision.py +408 -0
  119. sloptic-1.1.0/scripts/report_card.py +107 -0
  120. sloptic-1.1.0/scripts/run_batch.py +600 -0
  121. sloptic-1.1.0/scripts/stats.py +603 -0
  122. sloptic-1.1.0/sloptic/__init__.py +7 -0
  123. sloptic-1.1.0/sloptic/aggregate.py +120 -0
  124. sloptic-1.1.0/sloptic/auth.py +796 -0
  125. sloptic-1.1.0/sloptic/baas.py +157 -0
  126. sloptic-1.1.0/sloptic/browser.py +1377 -0
  127. sloptic-1.1.0/sloptic/catalog.py +69 -0
  128. sloptic-1.1.0/sloptic/cli.py +362 -0
  129. sloptic-1.1.0/sloptic/deploy.py +266 -0
  130. sloptic-1.1.0/sloptic/depscan.py +66 -0
  131. sloptic-1.1.0/sloptic/discovery.py +1355 -0
  132. sloptic-1.1.0/sloptic/ingest.py +84 -0
  133. sloptic-1.1.0/sloptic/jsmine.py +59 -0
  134. sloptic-1.1.0/sloptic/jsonl.py +22 -0
  135. sloptic-1.1.0/sloptic/net.py +106 -0
  136. sloptic-1.1.0/sloptic/oob.py +68 -0
  137. sloptic-1.1.0/sloptic/openapi.py +164 -0
  138. sloptic-1.1.0/sloptic/perf.py +71 -0
  139. sloptic-1.1.0/sloptic/pipeline.py +300 -0
  140. sloptic-1.1.0/sloptic/platform_id.py +138 -0
  141. sloptic-1.1.0/sloptic/probes.py +5483 -0
  142. sloptic-1.1.0/sloptic/provenance.py +118 -0
  143. sloptic-1.1.0/sloptic/reportcard.py +424 -0
  144. sloptic-1.1.0/sloptic/safety.py +64 -0
  145. sloptic-1.1.0/sloptic/schema.py +152 -0
  146. sloptic-1.1.0/sloptic/scope.py +45 -0
  147. sloptic-1.1.0/sloptic/secretscan.py +218 -0
  148. sloptic-1.1.0/sloptic/vendor/axe.min.js +12 -0
  149. sloptic-1.1.0/tests/test_a11y.py +83 -0
  150. sloptic-1.1.0/tests/test_aggregate.py +89 -0
  151. sloptic-1.1.0/tests/test_anon_bulk_and_schema.py +270 -0
  152. sloptic-1.1.0/tests/test_api_injection.py +330 -0
  153. sloptic-1.1.0/tests/test_audit_timeout.py +99 -0
  154. sloptic-1.1.0/tests/test_auth.py +197 -0
  155. sloptic-1.1.0/tests/test_auth_browser.py +93 -0
  156. sloptic-1.1.0/tests/test_auth_header.py +84 -0
  157. sloptic-1.1.0/tests/test_auth_modern_stack.py +187 -0
  158. sloptic-1.1.0/tests/test_auth_spa.py +63 -0
  159. sloptic-1.1.0/tests/test_authbypass.py +87 -0
  160. sloptic-1.1.0/tests/test_baas_module.py +185 -0
  161. sloptic-1.1.0/tests/test_baas_service_keys.py +109 -0
  162. sloptic-1.1.0/tests/test_backend_exposure.py +345 -0
  163. sloptic-1.1.0/tests/test_backend_observed_tables.py +57 -0
  164. sloptic-1.1.0/tests/test_backnav.py +71 -0
  165. sloptic-1.1.0/tests/test_batch_throttle.py +65 -0
  166. sloptic-1.1.0/tests/test_batch_tldr.py +58 -0
  167. sloptic-1.1.0/tests/test_batch_wedge.py +155 -0
  168. sloptic-1.1.0/tests/test_benchmark.py +167 -0
  169. sloptic-1.1.0/tests/test_bola_collection.py +136 -0
  170. sloptic-1.1.0/tests/test_bola_managed_backend.py +171 -0
  171. sloptic-1.1.0/tests/test_browser.py +635 -0
  172. sloptic-1.1.0/tests/test_browser_preflight.py +51 -0
  173. sloptic-1.1.0/tests/test_bundle_api_mining.py +151 -0
  174. sloptic-1.1.0/tests/test_caching.py +84 -0
  175. sloptic-1.1.0/tests/test_catalog_integrity.py +76 -0
  176. sloptic-1.1.0/tests/test_chunk.py +71 -0
  177. sloptic-1.1.0/tests/test_cli.py +132 -0
  178. sloptic-1.1.0/tests/test_cmdi.py +108 -0
  179. sloptic-1.1.0/tests/test_contrast_tiering.py +111 -0
  180. sloptic-1.1.0/tests/test_conventional_api_probe.py +133 -0
  181. sloptic-1.1.0/tests/test_conventional_pairs.py +140 -0
  182. sloptic-1.1.0/tests/test_coverage_gate.py +187 -0
  183. sloptic-1.1.0/tests/test_crash.py +80 -0
  184. sloptic-1.1.0/tests/test_create_read_pair.py +193 -0
  185. sloptic-1.1.0/tests/test_debug_mode.py +99 -0
  186. sloptic-1.1.0/tests/test_decompression_bomb.py +92 -0
  187. sloptic-1.1.0/tests/test_deeplink.py +83 -0
  188. sloptic-1.1.0/tests/test_deploy_meta.py +346 -0
  189. sloptic-1.1.0/tests/test_devbuild.py +158 -0
  190. sloptic-1.1.0/tests/test_devpost.py +148 -0
  191. sloptic-1.1.0/tests/test_discover_auth_crawl.py +74 -0
  192. sloptic-1.1.0/tests/test_discovery.py +722 -0
  193. sloptic-1.1.0/tests/test_docker_deploy.py +45 -0
  194. sloptic-1.1.0/tests/test_docker_hardened.py +113 -0
  195. sloptic-1.1.0/tests/test_exposed_files.py +150 -0
  196. sloptic-1.1.0/tests/test_filter_injection.py +157 -0
  197. sloptic-1.1.0/tests/test_gapbench_run.py +252 -0
  198. sloptic-1.1.0/tests/test_gapbench_score.py +208 -0
  199. sloptic-1.1.0/tests/test_grade_timeout.py +50 -0
  200. sloptic-1.1.0/tests/test_host_header.py +63 -0
  201. sloptic-1.1.0/tests/test_http_conformance.py +58 -0
  202. sloptic-1.1.0/tests/test_https_pipeline.py +73 -0
  203. sloptic-1.1.0/tests/test_idor_user_record.py +108 -0
  204. sloptic-1.1.0/tests/test_ingest.py +75 -0
  205. sloptic-1.1.0/tests/test_innocence_check.py +245 -0
  206. sloptic-1.1.0/tests/test_jsmine.py +35 -0
  207. sloptic-1.1.0/tests/test_json_injection.py +113 -0
  208. sloptic-1.1.0/tests/test_jsonl.py +23 -0
  209. sloptic-1.1.0/tests/test_lfi.py +104 -0
  210. sloptic-1.1.0/tests/test_links.py +87 -0
  211. sloptic-1.1.0/tests/test_liveness_vs_ttfb.py +88 -0
  212. sloptic-1.1.0/tests/test_login_creds.py +84 -0
  213. sloptic-1.1.0/tests/test_mixed_content.py +93 -0
  214. sloptic-1.1.0/tests/test_noerror.py +82 -0
  215. sloptic-1.1.0/tests/test_openapi.py +100 -0
  216. sloptic-1.1.0/tests/test_parity.py +74 -0
  217. sloptic-1.1.0/tests/test_perf.py +154 -0
  218. sloptic-1.1.0/tests/test_pipeline.py +288 -0
  219. sloptic-1.1.0/tests/test_platform.py +74 -0
  220. sloptic-1.1.0/tests/test_precision.py +129 -0
  221. sloptic-1.1.0/tests/test_probe_selection.py +87 -0
  222. sloptic-1.1.0/tests/test_probes.py +280 -0
  223. sloptic-1.1.0/tests/test_qa_data_spa.py +121 -0
  224. sloptic-1.1.0/tests/test_qa_janky.py +28 -0
  225. sloptic-1.1.0/tests/test_rate_limited_fetch.py +109 -0
  226. sloptic-1.1.0/tests/test_record_contract.py +52 -0
  227. sloptic-1.1.0/tests/test_redirect_oauth.py +128 -0
  228. sloptic-1.1.0/tests/test_remote.py +49 -0
  229. sloptic-1.1.0/tests/test_reportcard.py +78 -0
  230. sloptic-1.1.0/tests/test_repro.py +67 -0
  231. sloptic-1.1.0/tests/test_response_splitting.py +62 -0
  232. sloptic-1.1.0/tests/test_safety.py +49 -0
  233. sloptic-1.1.0/tests/test_scenario_selection.py +70 -0
  234. sloptic-1.1.0/tests/test_schema_discovery.py +166 -0
  235. sloptic-1.1.0/tests/test_scope.py +27 -0
  236. sloptic-1.1.0/tests/test_search_endpoint_discovery.py +220 -0
  237. sloptic-1.1.0/tests/test_secretscan.py +78 -0
  238. sloptic-1.1.0/tests/test_secretscan_config_formats.py +106 -0
  239. sloptic-1.1.0/tests/test_seo.py +76 -0
  240. sloptic-1.1.0/tests/test_session_cookie_pick.py +276 -0
  241. sloptic-1.1.0/tests/test_session_storage.py +111 -0
  242. sloptic-1.1.0/tests/test_soft404.py +102 -0
  243. sloptic-1.1.0/tests/test_spa_secrets.py +82 -0
  244. sloptic-1.1.0/tests/test_sqli_error_breadth.py +130 -0
  245. sloptic-1.1.0/tests/test_sqli_prefix_catchall.py +65 -0
  246. sloptic-1.1.0/tests/test_ssrf.py +61 -0
  247. sloptic-1.1.0/tests/test_ssrf_inband.py +96 -0
  248. sloptic-1.1.0/tests/test_ssti.py +86 -0
  249. sloptic-1.1.0/tests/test_staleui.py +133 -0
  250. sloptic-1.1.0/tests/test_stored_xss_api.py +92 -0
  251. sloptic-1.1.0/tests/test_subpath_targets.py +72 -0
  252. sloptic-1.1.0/tests/test_supabase_selfhosted_rls.py +188 -0
  253. sloptic-1.1.0/tests/test_trace.py +117 -0
  254. sloptic-1.1.0/tests/test_upload.py +89 -0
  255. sloptic-1.1.0/tests/test_upload_xss.py +137 -0
  256. sloptic-1.1.0/tests/test_weak_session.py +64 -0
  257. sloptic-1.1.0/tests/test_xss.py +94 -0
  258. sloptic-1.1.0/tests/test_xxe.py +72 -0
  259. sloptic-1.1.0/uv.lock +474 -0
  260. sloptic-1.1.0/validation/benchmark-curve.json +9291 -0
  261. sloptic-1.1.0/validation/vuln-corpus/README.md +101 -0
  262. sloptic-1.1.0/validation/vuln-corpus/anchors.txt +32 -0
  263. sloptic-1.1.0/validation/vuln-corpus/docker-compose.yml +40 -0
  264. sloptic-1.1.0/validation/vuln-corpus/gapbench-manifest.json +1 -0
  265. sloptic-1.1.0/validation/vuln-corpus/gapbench.txt +112 -0
  266. sloptic-1.1.0/validation/vuln-corpus/serve-anchors.sh +80 -0
  267. sloptic-1.1.0/validation/vuln-corpus/setup.sh +29 -0
@@ -0,0 +1,36 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .pytest_cache/
5
+
6
+ # Hidden-pool probes must NEVER be committed to this PUBLIC repo. The real boundary is a
7
+ # separate PRIVATE hidden-probe catalog repo; this is only a backstop.
8
+ **/hidden/
9
+ catalog-hidden/
10
+
11
+ # GRADING OUTPUT MUST NOT BE PUBLISHED. A results file names real third-party apps and carries, per finding, a
12
+ # paste-to-reproduce request against a live deployment — the v9/v10 corpus runs alone held 1,709 named Devpost
13
+ # projects and 8,825 repro blocks. Black-box scanning of a public URL is one thing; publishing per-app
14
+ # reproduction steps against someone else's submission is a different act, and it contradicts the product's own
15
+ # guardrail (hand the builder back a private report, upside-only).
16
+ #
17
+ # THIS FILE IS THE SOURCE OF TRUTH FOR BOTH REPOS, and that is the whole point. The league -> mirror sync is
18
+ # `rsync --delete` followed by `git add -A`, so rsync OVERWRITES the mirror's .gitignore with this one on every
19
+ # sync — a fix applied only on the mirror side survives until the next sync and then silently un-ignores
20
+ # everything (observed, not hypothesised). The sync command also carries matching --exclude flags; this is the
21
+ # backstop for when one is forgotten.
22
+ #
23
+ # *.jsonl and NOT *.json: validation/benchmark-curve.json is the frozen scoring curve and must stay tracked.
24
+ *.jsonl
25
+ *.log
26
+ *.tsv
27
+ v9-baseline-stats.json
28
+ nextjs-trace-sample.txt
29
+ sprint-sample.txt
30
+ terminal output of test.md
31
+
32
+ # Diagnostic URL worklists carry hundreds of named third-party apps (the v11 session-gap list is 311). Same
33
+ # reasoning as the grading output above: black-box scanning a public URL is one thing, publishing the list of
34
+ # who we scanned is another. Keep the *pattern* here so a regenerated list is covered without anyone rememb-
35
+ # ering to add it.
36
+ *.urls.txt
@@ -0,0 +1,162 @@
1
+ # Authoring probes
2
+
3
+ How to add, change, and remove probes. The engine is **fixed**; **probes are data**
4
+ (`catalog/**/*.yaml`, loaded by `load_catalog()` at run time). Reusing existing detection needs no
5
+ code change, only a *new* detection primitive touches Python. This is the practical recipe.
6
+
7
+ The live lists of detection primitives are **`MATCHERS` and `PREDICATES` in `sloptic/probes.py`**,
8
+ the source of truth (this doc deliberately does not enumerate them, so it cannot drift). Skim those
9
+ dicts to see everything that exists today.
10
+
11
+ ## The probe schema
12
+
13
+ ```yaml
14
+ id: sec-sqli-001 # unique: the LOADER KEYS ON THIS, NOT THE FILENAME (a dup id collides even
15
+ # across files with different names)
16
+ bundle: security # security | qa | performance
17
+ category: sql-injection # diminishing-returns damper applies WITHIN a category (sorted descending decay)
18
+ variant_group_id: <id> # optional; probes sharing one fire ONCE at the max penalty (same logical flaw)
19
+ pool: public # public | hidden
20
+ evidence_model: provable # provable (slop visible in a response) | oracle (differential / self-as-oracle)
21
+ penalty: 40 # slop added when it fires (deduction-only; always positive)
22
+ applicability:
23
+ requires: [any_endpoint_accepts_text_input] # capabilities from discovery; empty = always applicable
24
+ probe:
25
+ # EITHER declarative (fetch a target, apply matchers):
26
+ method: POST
27
+ target: /search # a literal path, or the selector "routes"/"forms" to fan across the surface
28
+ query: { q: "<payload>" } # optional query params
29
+ data: { age: abc } # optional form body
30
+ # OR a predicate (multi-step oracle):
31
+ predicate: sqli_auth_bypass
32
+ payload: "' OR '1'='1' -- " # arbitrary keys under probe: are read by the predicate via probe.probe
33
+ slop_if: # declarative ONLY; ALL must match -> slop. Omit for predicate probes.
34
+ - response_contains: "<payload>"
35
+ ```
36
+
37
+ ## The two detection primitives (contracts)
38
+
39
+ **Matcher**: `MATCHERS[name](resp, arg=None) -> bool`. A pure function over ONE response, `True` when
40
+ slop is present. For declarative probes.
41
+
42
+ **Predicate**: `PREDICATES[name](ctx, probe) -> bool | None`. A multi-step oracle. **Three-state, and
43
+ the third state is load-bearing:**
44
+
45
+ | return | meaning |
46
+ | --- | --- |
47
+ | `True` | slop detected → the probe's `penalty` applies |
48
+ | `False` | clean → tested and the flaw is absent |
49
+ | `None` | **not applicable**: could not establish the conditions to test (no such surface, self-registration failed, and so on). This is NOT a clean pass. A `False` when you could not actually test is a **false clean, a missed finding.** When in doubt between `False` and `None`, return `None`. |
50
+
51
+ The `ctx` object gives a predicate: `ctx.base_url`, `ctx.headers` (auth), `ctx.profile` (the discovered
52
+ surface: `.routes`, `.forms`, `.endpoints`, `.capabilities`), `ctx.client` (a shared httpx client), and
53
+ `ctx.evidence` (see below). For a fresh, correctly authenticated client use
54
+ `make_client(ctx.base_url, ctx.headers)` (seeds the cookie into the jar so a rotating session is
55
+ followed; defaults `verify=False` so an https target with a self-signed cert is reachable).
56
+
57
+ ### Evidence (required for a new predicate)
58
+
59
+ Every predicate should record what it measured or attempted via `ctx.evidence.update(key=value, ...)`,
60
+ for **all** outcomes, clean and n/a too, not just slop. It rides in `--json` and the `-v` view, and is
61
+ the product's transparency ("load_time_s=0.4 ✓", "tried error+boolean+union+time, none hit"). Keep it
62
+ small and typed (numbers, short strings, small lists). Example:
63
+
64
+ ```python
65
+ def perf_ttfb(ctx, probe) -> bool:
66
+ thresh = perf.TTFB_PROFILE
67
+ with make_client(ctx.base_url, ctx.headers) as c:
68
+ sample = perf.sample_ttfb(c, "/")
69
+ ctx.evidence.update(ttfb_s=round(sample, 3), threshold_s=thresh) # <- what it measured
70
+ return sample >= thresh
71
+ ```
72
+
73
+ ### Safety (a probe fetches an UNTRUSTED, possibly authenticated target)
74
+
75
+ - **Never GET a discovered `<a href>` navigation or a state-changing endpoint with the auth cookie.**
76
+ A blind fetch of `<a href="logout.php">` logs the grader's own session out mid-run and blinds every
77
+ later probe (this actually happened, `fix 8071b67`). Fetch only true subresources
78
+ (`<img/script/media src>`, `<link href>`), and skip logout/delete-looking links (see `broken_links`).
79
+ - Never send `PUT`/`PATCH`/`DELETE` payloads that mutate the target's state; grading must be safe to
80
+ re-run. Read-only injection (`GET`/benign `POST`) only.
81
+ - A predicate that raises is caught and degraded to N/A for that one probe (the run never DNFs), but
82
+ do not rely on it; handle `httpx.HTTPError`/`InvalidURL` yourself.
83
+
84
+ ## Add a probe
85
+
86
+ ### 1. Declarative, reusing a matcher: one file, no code
87
+ Drop a YAML in `catalog/<bundle>/` with a `target` + `slop_if` using an existing matcher.
88
+
89
+ ### 2. A variant of an existing class: one file, same `variant_group_id`
90
+ A new SQLi syntax or XSS payload: copy a sibling YAML, change the `payload`, keep the
91
+ `variant_group_id`. It reuses the oracle and folds into the fire-once group (the group counts one
92
+ penalty no matter how many syntaxes fire). **Give it a unique `id`.**
93
+
94
+ ### 3. A new detection primitive: +1 function, then the YAML
95
+ Add a `MATCHERS` or `PREDICATES` entry (and a matching `_MATCHER_REASONS`/`_PREDICATE_REASONS` line for
96
+ the human "why it fired"). Predicates emit `ctx.evidence`. **One finding per class, all its techniques:**
97
+ cover the class's techniques (SQLi = error/boolean/UNION/time; XSS = script/img/svg/attr/…) but collapse
98
+ them to ONE finding, a single predicate that returns once, or siblings sharing a `variant_group_id`.
99
+ Breadth is recall, not score inflation; keep each technique precise (marker, differential, confirmation
100
+ guards) so breadth does not cost false positives.
101
+
102
+ ### CI-lock it (per-technique reference servers)
103
+ Add `tests/test_<name>.py` that stands up a throwaway `http.server` exhibiting exactly the flaw (one
104
+ per technique) and asserts the predicate fires, plus a clean server it must not fire on, plus the N/A
105
+ case. A fake `ctx` is `type("C", (), {"base_url": url, "headers": None, "client": None, "evidence": {}})()`.
106
+ Note the **`evidence: {}`** (a predicate writes to it; the full suite catches a missing one via
107
+ `AttributeError`).
108
+
109
+ ## Change a probe
110
+ - **Tuning** (penalty, payload, threshold, applicability, pool) → edit the YAML field, re-run the suite.
111
+ - **Detection logic** → edit the matcher/predicate (affects every probe that uses it, so review
112
+ accordingly).
113
+ - **Pool flip** (public ↔ hidden) → change `pool:` and move the file between this public catalog and
114
+ the private hidden-probe catalog repo.
115
+
116
+ ## Remove a probe
117
+ Delete the YAML and the runner stops loading it. Remove its assertion in `tests/`. For an event-grade
118
+ catalog, *deprecate in the changelog* rather than silently delete, so past results stay interpretable.
119
+
120
+ ## Pricing a penalty (risk = frequency × severity)
121
+ A penalty is **expected harm**, not raw severity. Price it by how often a real user is hurt × how badly:
122
+
123
+ - **Security = low-frequency × terminal-severity.** A DB-dumping SQLi, auth bypass, or RCE is rare per
124
+ app (injection incidence ~3% of endpoints, Verizon DBIR / OWASP) but a single one is company-ending
125
+ (avg breach $4.4M, IBM 2025). These sit at the **per-instance ceiling (≈40)** and no other class
126
+ outranks a single one. Defense in depth (missing headers) is low × low, so it stays small.
127
+ - **QA / performance = high-frequency × moderate-severity.** Every visitor on slow 4G hits the slow
128
+ page (~53% bounce past 3s, Google 2016; ~79% never return); every wrong-order user hits the crash
129
+ (~32% churn after one bad experience, PwC 2018); ~16% of people are barred by a11y failures (WHO
130
+ 2023). Priced **up toward the deadly range but strictly below the catastrophic-security ceiling**, so
131
+ no single qa/perf penalty is ≥ the worst single security penalty.
132
+ - **Net effect (deliberate):** the aggregate leans qa/perf (high-frequency harm stacks across many
133
+ probes and instances), while the per-incident ceiling stays with catastrophic security.
134
+
135
+ Do not multiply ordinal severities (Cox 2008, *What's Wrong with Risk Matrices?*, ordinal labels are
136
+ not cardinal). These magnitudes are a **designed table** with a consequence-triggered override band
137
+ (terminal severity keeps the ceiling regardless of low frequency), the practice NIST 800-30 /
138
+ MIL-STD-882E use.
139
+
140
+ ## The calibration gate (non-negotiable)
141
+ Every add or change must keep `uv run pytest` green. A probe must read **slop on `references/vulnerable`,
142
+ clean on `references/hardened`, and N/A or clean on `references/minimal`**: the same surface, three
143
+ verdicts. If your probe needs a surface the references lack, add it (broken in `vulnerable`, defended
144
+ in `hardened`). So "add a probe" is usually three coupled edits:
145
+
146
+ 1. the probe YAML,
147
+ 2. the reference surface (if new),
148
+ 3. the test assertion.
149
+
150
+ That coupling is the point: a probe that cannot separate defended from broken from absent does not
151
+ merge.
152
+
153
+ **The score:** `tests/test_pipeline.py` holds the **single authoritative** vulnerable-app score
154
+ (`assert report.slop_score == N`, plus an `axis_slop` decomposition assertion that must sum to it). A
155
+ probe that fires on `vulnerable` changes `N` by its (damped) penalty, so update it there, in **one**
156
+ place. `test_remote.py` and the docker tests assert *deployer-equivalence* (they equal the
157
+ SubprocessDeployer baseline), so they self-track and never need editing for a scoring change.
158
+
159
+ ## Over time
160
+ Versioning follows semver on a quarterly cadence, with PR review and public-vs-hidden pool governance.
161
+ Hidden probes are authored the same way but live in the private hidden-probe catalog repo, never this
162
+ public one.
@@ -0,0 +1,220 @@
1
+ # The Shape of AI Era Web App Slop
2
+
3
+ ### A black-box quality audit of 1,528 live hackathon web apps
4
+
5
+ **Reference release:** `2026.1` · **Instrument:** Sloptic (deduction-only black-box grader) · **Population:** live hackathon submissions
6
+
7
+ ---
8
+
9
+ ## TL;DR
10
+
11
+ - On a corpus of **1,528** live web apps graded black-box, AI era "slop" is overwhelmingly **chronic**, not **acute**. Pervasive missing hygiene, not exploitable holes.
12
+ - **98%** ship no Content-Security-Policy, **42%** never rate limit a login, **70%** have a critical accessibility violation. But only **3.8%** expose any exploitable vulnerability, and **zero** of the 1,528 a remote code execution class.
13
+ - The acute danger has not disappeared. It **relocated behind authentication and vendor boundaries**: only **16.6%** of the apps with observed runtime traffic (176 of 1,063) even have an own injectable backend, so a black-box grader mostly cannot reach the dangerous surface.
14
+ - **AI-builder apps are measurably sloppier, and it is a performance tax.** Apps generated by Lovable carry a statistically significant slop premium (median **72 vs 49** hand-built, p = 1.1e-5) that is **entirely performance**, heavy, slow bundles, not weaker security.
15
+ - The overall score is smooth and unimodal (good for ranking), but the security axis is **bimodal**, two "header flat tax" values account for **70%** of it.
16
+ - The median app defends **~94%** of its worst case failure surface. Slop is the rare exception, not the rule, per app.
17
+
18
+ ---
19
+
20
+ ## 1. The question
21
+
22
+ AI assisted building makes shipping a web app nearly free, and the volume of "looks done" submissions has exploded. The security research is blunt about the tradeoff. Veracode's 2025 report, testing over 100 models on 80 tasks, found that **45%** of AI generated code introduces an OWASP Top 10 vulnerability and that AI written code carries **2.74 times** more flaws than human written code, a pass rate that had not budged by early 2026. The Cloud Security Alliance put the share of AI generated solutions carrying a design flaw or known vulnerability at **62%**. Hackathons feel this directly: when any team can generate a polished UI in minutes, judges report the bar for "impressive" moving from "does it look done" to "does it hold up." So a natural question for anyone grading these apps at scale:
23
+
24
+ > When you look at a large population of real, deployed, AI era web apps from the outside, **what does the failure actually look like?** A field of exploitable vulnerabilities, or something else?
25
+
26
+ This report answers that from one instrument's black-box view of 1,528 apps.
27
+
28
+ ## 2. The dataset
29
+
30
+ | property | value |
31
+ |---|---|
32
+ | Apps ingested | 2,250 |
33
+ | Apps successfully graded | **1,528** |
34
+ | Attrition | dead URLs, pages that are not web apps, and submissions that never deployed |
35
+ | Each row | one deployed app, graded over HTTP with no source and no spec |
36
+ | Grader version | frozen catalog of 91 probes across 3 axes |
37
+
38
+ Rows that could not be graded (a URL that never answered, a repo that never deployed) are excluded rather than scored, so the population is "apps that actually presented a working surface."
39
+
40
+ ### 2.1 Where the apps came from
41
+
42
+ The corpus is drawn from **60 hackathons** on Devpost, whose public project galleries were scraped for submissions that shipped a live URL. The events span North America (the majority, largely US and Canadian university hackathons), Europe (London, Barcelona, Ireland), Latin America (Monterrey), and Asia Pacific (Singapore and Australia), with editions concentrated in 2025 and 2026. From these galleries, **2,250** submissions carried a gradeable URL and **1,528** graded successfully. The full list of 60 events is in Appendix A.
43
+
44
+ This provenance matters for reading the results. The population is young, collegiate, time boxed (a hackathon is a day or a weekend), and built in the AI era, so it is a clean look at what teams ship when speed is everything and the tooling writes much of the code. It is deliberately **not** a sample of production software.
45
+
46
+ Every figure in this report is computed on one grading run (n = 1,528). The frozen percentile curve used to rank a new app against this population remains **2026.1**, built from the prior run; it stays valid because the two runs rank correlate at **0.967** with an unchanged median, so the scored numbers here and the ranking curve describe the same population.
47
+
48
+ ## 3. Method
49
+
50
+ Sloptic is a **black-box** grader. It reads no source, needs no spec, and emits one **slop score**: deduction-only, unbounded, lower is better, `0` means nothing was found. The score decomposes into three axes (security, quality, performance) whose subtotals sum exactly to the total. Penalties are risk priced (frequency times severity) and damped, so one root cause counts once.
51
+
52
+ Because it ignores the stack, the same 91 probes run identically against every app, which is what makes 1,528 unrelated apps **comparable on one axis**. Every grade also ships a coverage report, so a `0` that means "clean" is distinguishable from a `0` that means "we could not reach the surface."
53
+
54
+ Two things this method is honest about up front: it grades the **unauthenticated, observable** surface, and it measures **intent-independent** failures only (defects no matter what the app is for).
55
+
56
+ ## 4. Results
57
+
58
+ ### 4.1 The score distribution
59
+
60
+ | statistic | value |
61
+ |---|---|
62
+ | mean | 55.1 |
63
+ | median | 49 |
64
+ | max | 168 |
65
+ | distinct values | 132 |
66
+ | landmarks (p10 / p25 / p50 / p75 / p90 / p99) | 26 / 35 / 49 / 70 / 89 / 142 |
67
+
68
+ The overall score is **smooth and nearly unimodal**, the largest single spike holds under 5% of the population. This is exactly the property a ranking needs: the convolution of three axes and many probes spreads apps out, so a percentile is meaningful.
69
+
70
+ ### 4.2 What drives the score
71
+
72
+ Penalty mass splits across the three axes like this:
73
+
74
+ | axis | share of total slop | median | shape |
75
+ |---|---:|---:|---|
76
+ | security | **41.9%** | 14 | bimodal (two values = 70%) |
77
+ | quality | 36.4% | 20 | spike at 0 (15%), then spread |
78
+ | performance | 21.7% | 0 | **62% score zero** |
79
+
80
+ The probes that fire most often are not exotic. They are missing HTTP headers:
81
+
82
+ | prevalence | probe |
83
+ |---:|---|
84
+ | 98% | missing Content-Security-Policy |
85
+ | 97% | no clickjacking defense |
86
+ | 91% | missing `X-Content-Type-Options` |
87
+ | 90% | missing `Referrer-Policy` |
88
+ | 70% | critical accessibility violation |
89
+ | 42% | login with no rate limiting |
90
+
91
+ A finding at 98% prevalence is nearly a constant, it taxes everyone and separates no one. The **discriminating** signal lives in the middle band (rate limiting at 42%, source map disclosure at ~10%, accessibility tiers, Core Web Vitals), which is where apps actually pull apart.
92
+
93
+ ### 4.3 Severity composition: chronic, not acute
94
+
95
+ This is the headline. Split every security finding into **acute** (exploitable now) versus **chronic** (missing mitigation), and the population is lopsided:
96
+
97
+ | tier | rate | examples |
98
+ |---|---:|---|
99
+ | any acute finding | **3.8%** | |
100
+ | remote code execution / injection | **0%** | zero of 1,528 apps (SQLi / command / template injection) |
101
+ | data exposure | 2.68% | world readable managed backend, bulk PII |
102
+ | secret or source file leak | 0.85% | served `.env`, `.git`, backups, keys |
103
+ | source map disclosure (moderate) | ~10% | production `.map` leaks original source |
104
+ | chronic hygiene (representative) | 41 to 98% | headers, rate limiting, accessibility |
105
+
106
+ Read the two ends together: **~4% of apps are exploitable, not one has a remote code execution hole, while 40 to 98% are missing basic hygiene.** The functionality is mostly there; the nonfunctional floor is pervasively absent. That is the empirical signature of AI era slop from the outside, chronic rot, not a field of smoking guns.
107
+
108
+ ### 4.4 Why the acute surface is so thin
109
+
110
+ The low acute rate is not "these apps are safe." It is an artifact of **where the modern stack puts the danger.** Of the graded apps, **1,063 exposed observed runtime traffic** we could classify by host tier. An app's traffic routinely spans several tiers at once (a same-origin API *and* a managed BaaS *and* a consumed vendor), so **the tiers OVERLAP: each row counts how many of the 1,063 have *any* host of that tier, not a slice of a pie. They sum to 1,487 tier-memberships across 1,063 apps (≈140%), not to 100%, and must not be read as shares of a whole.**
111
+
112
+ | host tier | apps with this tier (of 1,063 classified; overlapping) | injectable black-box? |
113
+ |---|---:|---|
114
+ | same-origin (static frontend) | 682 (64%) | no backend to inject |
115
+ | third-party vendor (consumed) | 272 (26%) | not the app's surface |
116
+ | opaque (unattributable off-origin) | 203 (19%) | not probed (flagged, no clean-bill credit) |
117
+ | **own backend (attributed)** | **176 (16.6%)** | **yes** |
118
+ | managed backend (Supabase / Firebase) | 154 (14%) | only via row-level security config |
119
+
120
+ **Only 16.6% of the classified apps (176 of 1,063 with observed runtime traffic) have an own injectable backend**, and that is already a share of the traffic-bearing subset, not of the full corpus. You cannot inject SQL into a static site, and a managed backend app's only misconfiguration knob is row-level security. So the classic acute classes (SQLi, RCE) have almost no surface to land on, and the genuine acute risk that remains is disproportionately **backend misconfiguration** (the data-exposure tier), which is exactly where a black-box probe can still reach it. (Tier counts are off-score diagnostics from `scripts/stats.py`; they are the overlapping tiers over the 1,063 classified population.)
121
+
122
+ By hosting platform, identified from response headers and origin suffix (`platform_id`, off-score), the population is dominated by Vercel:
123
+
124
+ | platform | apps (of 1,528) |
125
+ |---|---:|
126
+ | Vercel | 988 (65%) |
127
+ | unknown / custom (unattributable) | 136 (9%) |
128
+ | Netlify | 99 (6%) |
129
+ | GitHub Pages | 71 (5%) |
130
+ | Streamlit | 66 (4%) |
131
+ | Lovable | 56 (4%) |
132
+ | other (Render, Firebase, Cloud Run, Cloudflare, Railway, ...) | 112 (7%) |
133
+
134
+ A further 200 apps sit behind a Cloudflare edge and 70 behind Fastly; a fronting CDN can mask the origin platform, which is why 9% stay unattributable rather than guessed. Reading response headers as well as the domain suffix cuts that unattributable share to 9% (a suffix-only pass leaves ~32% "custom/other"). A population this heavy on Vercel also explains why bot challenges rarely interfered: Vercel's bot protection is opt-in, and hackathon teams almost never configure it.
135
+
136
+ ### 4.5 The AI-builder slop premium
137
+
138
+ Because `platform_id` also fingerprints the *builder* from served markup (Lovable ships `cdn.gpteng.co`, Bolt its own signature), we can test the question the AI-slop thesis rests on: do AI-built apps carry more slop than hand-deployed ones? For Lovable the answer is yes, and it is specific.
139
+
140
+ | group | n | median slop | mean slop |
141
+ |---|---:|---:|---:|
142
+ | hand-built (no builder signature) | 1,459 | 49 | 54 |
143
+ | **Lovable** | **58** | **72** | **73** |
144
+ | Bolt | 11 | 44 | (n too small to read) |
145
+
146
+ The Lovable gap is statistically significant (Mann-Whitney U, one-sided, **p = 1.1e-5**) and it is **entirely performance**. Decomposed by axis (mean penalty per app), Lovable's performance slop is **30.0 versus 11.1** for hand-built (a +18.9 gap), while its security is marginally *lower* (−2.8) and its QA marginally higher (+2.6). Lovable apps are not less secure; they ship **heavy and slow**: large unsplit bundles, uncompressed responses, weak Core Web Vitals, the diffuse performance floor an AI builder trades away for generation speed.
147
+
148
+ Three bounds on the claim, stated. It is a correlation, not a controlled experiment, though the all-performance decomposition makes the mechanism concrete. Bolt's n = 11 is too small to read (its median is *lower*, but on eleven apps that is noise). And detection is a floor: a Lovable app on a custom domain with its signature stripped falls into the hand-built bucket, which can only *understate* the gap. The same pattern shows up by host: Streamlit is the sloppiest platform (median 88, another auto-generation stack), GitHub Pages the cleanest (34, static sites have little floor to miss).
149
+
150
+ ### 4.6 Measurement validity
151
+
152
+ A ranking is only trustworthy if the ruler is stable. Two independent runs over the full corpus agree closely:
153
+
154
+ | metric | value |
155
+ |---|---:|
156
+ | Spearman rank correlation | **0.974** |
157
+ | deciles identical | 92.6% (96% within one) |
158
+ | apps scoring exactly the same | 92% |
159
+ | systematic drift | none (mean delta +0.15) |
160
+
161
+ The residual movement is confined to the probes where black-box nondeterminism is unavoidable (stateful browser behavior, Core Web Vitals timing, and the security tail behind authentication); the deterministic surface holds.
162
+
163
+ Coverage is reported per grade: the median app had **62%** of the battery apply to it, so the scores are legible as "clean," not "untested."
164
+
165
+ ## 5. Interpretation
166
+
167
+ One number captures the thesis. The median app's **worst case slop** (the score it would carry if every applicable probe fired) is **866**, while its actual median score is **49**. The median app therefore realizes only about **6%** of its potential failure surface: it defends nearly everything it exposes, and fails on the diffuse hygiene it never thought about.
168
+
169
+ So the story of this corpus is not "AI writes insecure code that gets exploited." From the black-box, it is "AI writes **functional** code that ships without the boring, universal, nonfunctional floor," no headers, no rate limiting, no accessibility, sometimes a leaked source map. The acute danger is real but rare and increasingly hidden behind authentication and vendor APIs, which is a finding about the modern stack as much as about the apps.
170
+
171
+ ## 6. Limitations (stated, not hidden)
172
+
173
+ - **Unauthenticated surface only.** Defects behind a login the grader cannot establish are undercounted. The true acute rate is a floor.
174
+ - **Recall is not audited, and precision is vouched, not blanket.** This release guarantees **stability** (the ruler repeats) and **precision on the classes that carry explicit precision rules**; findings elsewhere are **unaudited, not endorsed**. That unaudited mass (most of the in-score penalty by count) is dominated by **deterministic presence checks** (a security header is absent, a `.map` resolves, a control is dead) where false-positive risk is structurally low. But the audit cannot distinguish "no rule needed" from "no rule written," and we can, so we report it as unaudited rather than claim a precision we have not checked. The false-negative rate against ground truth is measured separately and is ongoing: a low finding rate for a class could mean "rare" or "our detector missed it," and only a recall benchmark distinguishes them.
175
+ - **Intent-independent scope.** Sloptic grades the universal floor, not whether a feature is good. Originality, product quality, and creativity are out of scope by design.
176
+ - **Population, not universe.** Hackathon submissions skew toward young, small apps that are heavy on the frontend. The distribution should not be read as representative of production software at large.
177
+
178
+ ## 7. Reproduce
179
+
180
+ ```sh
181
+ # freeze the reference distribution from a corpus run
182
+ uv run python scripts/benchmark.py build <run>.jsonl --version 2026.1 --status final
183
+
184
+ # place any single app on that curve
185
+ uv run python -m sloptic.cli --target https://your-app.example.com --out app.jsonl
186
+ uv run python scripts/benchmark.py rank --results app.jsonl
187
+ ```
188
+
189
+ ## Sources
190
+
191
+ Background figures on AI generated code are external; the corpus figures are this instrument's own measurements over the 2026.1 population.
192
+
193
+ - [Veracode 2025 GenAI Code Security Report](https://www.veracode.com/resources/analyst-reports/2025-genai-code-security-report/) (45% of AI generated code introduces an OWASP Top 10 flaw; 2.74x more vulnerabilities than human written code)
194
+ - [Veracode, Spring 2026 GenAI Code Security update](https://www.veracode.com/blog/spring-2026-genai-code-security/) (the 45% pass rate had not improved through early 2026)
195
+ - [Cloud Security Alliance, AI generated code vulnerability research](https://labs.cloudsecurityalliance.org/research/csa-research-note-ai-codegen-vulnerability-debt-20260406-csa/) (62% carry a design flaw or known vulnerability)
196
+ - [Vercel Bot Management docs](https://vercel.com/docs/bot-management) (bot protection is opt-in, which is why it rarely interfered)
197
+
198
+ ## Appendix A: the 60 hackathons
199
+
200
+ Devpost event slugs, as ingested:
201
+
202
+ ```
203
+ hack-brown-2026 ds-x bigred-hacks-2025 luddyhacks
204
+ innovation-hacks-2 hackgt-12 hacktech-by-caltech-2026 mhacks-2025
205
+ hacknyu-2025 vthacks-13 jumbohack-2025 devfest-2026
206
+ hack-mit-2023 ai-hackathon-2026 hacktx2025 jumbohack-2026
207
+ hackrice-15 hackprinceton-fall-2025 hackdartmouth-xi hackbeanpot2025
208
+ la-hacks-2026 la-hacks-2025 treehacks-2026 bostonhacks-2025
209
+ hackharvard-2025 hackduke-code-for-good-2026 hackillinois-2026 hackcwru-012025
210
+ beaverhacks boilermake-xii terrahacks-2025 hackpsu-spring-2026
211
+ uwb-hacks-the-future civic-hacks-2026 hackumass-xiii uofthacks-13
212
+ deltahacks-12 hack-western-12 nwhacks-2026 hackku26
213
+ newhacks-2025 hacknc-2025 hacklondon-2026 hackupc-2026
214
+ kenthackit emory-hacks-2025-fall interhackbcn steminate-hacks-2026
215
+ hackeurope hack4her-mty hackmty2025 hacknroll2026
216
+ uncommon-hacks-2026 swamphacks-xi hack-arizona-2026 wildhacks-2026
217
+ nus-fintech-summit-2026 unihack2026 usaii-global-ai-hackathon-2026 hack-ireland-2025
218
+ ```
219
+
220
+ *All figures are aggregate over the 2026.1 population. No per app identities are stored or reported.*
sloptic-1.1.0/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2026 Ian Sun
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.