@skillsmith/core 0.11.6 → 0.12.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 (211) hide show
  1. package/CHANGELOG.md +208 -0
  2. package/README.md +2 -2
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/src/api/client.types.d.ts +9 -0
  5. package/dist/src/api/client.types.d.ts.map +1 -1
  6. package/dist/src/api/schemas.d.ts +6 -0
  7. package/dist/src/api/schemas.d.ts.map +1 -1
  8. package/dist/src/api/schemas.js +5 -0
  9. package/dist/src/api/schemas.js.map +1 -1
  10. package/dist/src/api/security-summary.d.ts +10 -1
  11. package/dist/src/api/security-summary.d.ts.map +1 -1
  12. package/dist/src/api/security-summary.js +9 -0
  13. package/dist/src/api/security-summary.js.map +1 -1
  14. package/dist/src/api/security-summary.test.js +79 -1
  15. package/dist/src/api/security-summary.test.js.map +1 -1
  16. package/dist/src/api/types.d.ts +9 -0
  17. package/dist/src/api/types.d.ts.map +1 -1
  18. package/dist/src/exports/services.d.ts +2 -2
  19. package/dist/src/exports/services.d.ts.map +1 -1
  20. package/dist/src/exports/services.js +4 -2
  21. package/dist/src/exports/services.js.map +1 -1
  22. package/dist/src/index.d.ts +3 -2
  23. package/dist/src/index.d.ts.map +1 -1
  24. package/dist/src/index.js +8 -2
  25. package/dist/src/index.js.map +1 -1
  26. package/dist/src/install/agent-config-merge.json-array.d.ts +16 -0
  27. package/dist/src/install/agent-config-merge.json-array.d.ts.map +1 -1
  28. package/dist/src/install/agent-config-merge.json-array.js +32 -3
  29. package/dist/src/install/agent-config-merge.json-array.js.map +1 -1
  30. package/dist/src/install/agent-harness-targets.d.ts +5 -0
  31. package/dist/src/install/agent-harness-targets.d.ts.map +1 -1
  32. package/dist/src/install/agent-harness-targets.js +19 -4
  33. package/dist/src/install/agent-harness-targets.js.map +1 -1
  34. package/dist/src/install/agent-pack-installer.cursor-hooks.d.ts +29 -0
  35. package/dist/src/install/agent-pack-installer.cursor-hooks.d.ts.map +1 -0
  36. package/dist/src/install/agent-pack-installer.cursor-hooks.js +233 -0
  37. package/dist/src/install/agent-pack-installer.cursor-hooks.js.map +1 -0
  38. package/dist/src/install/agent-pack-installer.cursor-hooks.test.d.ts +2 -0
  39. package/dist/src/install/agent-pack-installer.cursor-hooks.test.d.ts.map +1 -0
  40. package/dist/src/install/agent-pack-installer.cursor-hooks.test.js +225 -0
  41. package/dist/src/install/agent-pack-installer.cursor-hooks.test.js.map +1 -0
  42. package/dist/src/install/agent-pack-installer.d.ts +10 -5
  43. package/dist/src/install/agent-pack-installer.d.ts.map +1 -1
  44. package/dist/src/install/agent-pack-installer.harness.d.ts +10 -2
  45. package/dist/src/install/agent-pack-installer.harness.d.ts.map +1 -1
  46. package/dist/src/install/agent-pack-installer.harness.js +9 -2
  47. package/dist/src/install/agent-pack-installer.harness.js.map +1 -1
  48. package/dist/src/install/agent-pack-installer.js +15 -6
  49. package/dist/src/install/agent-pack-installer.js.map +1 -1
  50. package/dist/src/install/agent-pack-installer.test.js +3 -0
  51. package/dist/src/install/agent-pack-installer.test.js.map +1 -1
  52. package/dist/src/scripts/__tests__/scan-imported-skills.test.js +25 -0
  53. package/dist/src/scripts/__tests__/scan-imported-skills.test.js.map +1 -1
  54. package/dist/src/scripts/skill-scanner/trust-scorer.js +1 -1
  55. package/dist/src/scripts/skill-scanner/trust-scorer.js.map +1 -1
  56. package/dist/src/security/scanner/SecurityScanner.archive.d.ts +34 -0
  57. package/dist/src/security/scanner/SecurityScanner.archive.d.ts.map +1 -0
  58. package/dist/src/security/scanner/SecurityScanner.archive.js +218 -0
  59. package/dist/src/security/scanner/SecurityScanner.archive.js.map +1 -0
  60. package/dist/src/security/scanner/SecurityScanner.compound.d.ts +1 -0
  61. package/dist/src/security/scanner/SecurityScanner.compound.d.ts.map +1 -1
  62. package/dist/src/security/scanner/SecurityScanner.compound.js +117 -38
  63. package/dist/src/security/scanner/SecurityScanner.compound.js.map +1 -1
  64. package/dist/src/security/scanner/SecurityScanner.d.ts +41 -4
  65. package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
  66. package/dist/src/security/scanner/SecurityScanner.decoy.d.ts +72 -0
  67. package/dist/src/security/scanner/SecurityScanner.decoy.d.ts.map +1 -0
  68. package/dist/src/security/scanner/SecurityScanner.decoy.js +265 -0
  69. package/dist/src/security/scanner/SecurityScanner.decoy.js.map +1 -0
  70. package/dist/src/security/scanner/SecurityScanner.encoding.d.ts +56 -0
  71. package/dist/src/security/scanner/SecurityScanner.encoding.d.ts.map +1 -0
  72. package/dist/src/security/scanner/SecurityScanner.encoding.js +270 -0
  73. package/dist/src/security/scanner/SecurityScanner.encoding.js.map +1 -0
  74. package/dist/src/security/scanner/SecurityScanner.exec.d.ts +23 -20
  75. package/dist/src/security/scanner/SecurityScanner.exec.d.ts.map +1 -1
  76. package/dist/src/security/scanner/SecurityScanner.exec.js +207 -52
  77. package/dist/src/security/scanner/SecurityScanner.exec.js.map +1 -1
  78. package/dist/src/security/scanner/SecurityScanner.fetch-correlation.d.ts +115 -0
  79. package/dist/src/security/scanner/SecurityScanner.fetch-correlation.d.ts.map +1 -0
  80. package/dist/src/security/scanner/SecurityScanner.fetch-correlation.js +181 -0
  81. package/dist/src/security/scanner/SecurityScanner.fetch-correlation.js.map +1 -0
  82. package/dist/src/security/scanner/SecurityScanner.helpers.d.ts +14 -11
  83. package/dist/src/security/scanner/SecurityScanner.helpers.d.ts.map +1 -1
  84. package/dist/src/security/scanner/SecurityScanner.helpers.js +26 -124
  85. package/dist/src/security/scanner/SecurityScanner.helpers.js.map +1 -1
  86. package/dist/src/security/scanner/SecurityScanner.js +114 -36
  87. package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
  88. package/dist/src/security/scanner/SecurityScanner.paste-host.d.ts +69 -0
  89. package/dist/src/security/scanner/SecurityScanner.paste-host.d.ts.map +1 -0
  90. package/dist/src/security/scanner/SecurityScanner.paste-host.js +342 -0
  91. package/dist/src/security/scanner/SecurityScanner.paste-host.js.map +1 -0
  92. package/dist/src/security/scanner/SecurityScanner.risk-score.d.ts +27 -0
  93. package/dist/src/security/scanner/SecurityScanner.risk-score.d.ts.map +1 -0
  94. package/dist/src/security/scanner/SecurityScanner.risk-score.js +178 -0
  95. package/dist/src/security/scanner/SecurityScanner.risk-score.js.map +1 -0
  96. package/dist/src/security/scanner/SecurityScanner.urls.d.ts +20 -0
  97. package/dist/src/security/scanner/SecurityScanner.urls.d.ts.map +1 -0
  98. package/dist/src/security/scanner/SecurityScanner.urls.js +26 -0
  99. package/dist/src/security/scanner/SecurityScanner.urls.js.map +1 -0
  100. package/dist/src/security/scanner/index.d.ts +2 -2
  101. package/dist/src/security/scanner/index.d.ts.map +1 -1
  102. package/dist/src/security/scanner/index.js +5 -1
  103. package/dist/src/security/scanner/index.js.map +1 -1
  104. package/dist/src/security/scanner/multiline-category-closure.test.js +6 -0
  105. package/dist/src/security/scanner/multiline-category-closure.test.js.map +1 -1
  106. package/dist/src/security/scanner/patterns.d.ts +41 -21
  107. package/dist/src/security/scanner/patterns.d.ts.map +1 -1
  108. package/dist/src/security/scanner/patterns.exec.d.ts +89 -0
  109. package/dist/src/security/scanner/patterns.exec.d.ts.map +1 -0
  110. package/dist/src/security/scanner/patterns.exec.js +115 -0
  111. package/dist/src/security/scanner/patterns.exec.js.map +1 -0
  112. package/dist/src/security/scanner/patterns.js +78 -41
  113. package/dist/src/security/scanner/patterns.js.map +1 -1
  114. package/dist/src/security/scanner/types.d.ts +15 -1
  115. package/dist/src/security/scanner/types.d.ts.map +1 -1
  116. package/dist/src/security/scanner/typosquat.d.ts +10 -0
  117. package/dist/src/security/scanner/typosquat.d.ts.map +1 -1
  118. package/dist/src/security/scanner/typosquat.js +5 -1
  119. package/dist/src/security/scanner/typosquat.js.map +1 -1
  120. package/dist/src/security/scanner/weights.d.ts +12 -3
  121. package/dist/src/security/scanner/weights.d.ts.map +1 -1
  122. package/dist/src/security/scanner/weights.js +50 -1
  123. package/dist/src/security/scanner/weights.js.map +1 -1
  124. package/dist/src/services/agent-pack/prompt-source.d.ts +15 -0
  125. package/dist/src/services/agent-pack/prompt-source.d.ts.map +1 -1
  126. package/dist/src/services/agent-pack/prompt-source.js +32 -1
  127. package/dist/src/services/agent-pack/prompt-source.js.map +1 -1
  128. package/dist/src/services/agent-pack/skill-md.d.ts.map +1 -1
  129. package/dist/src/services/agent-pack/skill-md.js +9 -1
  130. package/dist/src/services/agent-pack/skill-md.js.map +1 -1
  131. package/dist/src/services/bundled-sibling-scan.d.ts +87 -13
  132. package/dist/src/services/bundled-sibling-scan.d.ts.map +1 -1
  133. package/dist/src/services/bundled-sibling-scan.js +177 -33
  134. package/dist/src/services/bundled-sibling-scan.js.map +1 -1
  135. package/dist/src/services/recommend-guard.d.ts +19 -0
  136. package/dist/src/services/recommend-guard.d.ts.map +1 -1
  137. package/dist/src/services/recommend-guard.js +28 -0
  138. package/dist/src/services/recommend-guard.js.map +1 -1
  139. package/dist/src/services/recommend-guard.test.js +23 -3
  140. package/dist/src/services/recommend-guard.test.js.map +1 -1
  141. package/dist/src/sync/index.d.ts +1 -0
  142. package/dist/src/sync/index.d.ts.map +1 -1
  143. package/dist/src/sync/index.js +2 -0
  144. package/dist/src/sync/index.js.map +1 -1
  145. package/dist/src/sync/license-status-client.d.ts +56 -0
  146. package/dist/src/sync/license-status-client.d.ts.map +1 -0
  147. package/dist/src/sync/license-status-client.js +118 -0
  148. package/dist/src/sync/license-status-client.js.map +1 -0
  149. package/dist/src/sync/license-status-client.test.d.ts +14 -0
  150. package/dist/src/sync/license-status-client.test.d.ts.map +1 -0
  151. package/dist/src/sync/license-status-client.test.js +136 -0
  152. package/dist/src/sync/license-status-client.test.js.map +1 -0
  153. package/dist/src/types.d.ts +13 -0
  154. package/dist/src/types.d.ts.map +1 -1
  155. package/dist/src/utils/version-check.d.ts +58 -5
  156. package/dist/src/utils/version-check.d.ts.map +1 -1
  157. package/dist/src/utils/version-check.js +73 -2
  158. package/dist/src/utils/version-check.js.map +1 -1
  159. package/dist/src/utils/version-check.test.js +49 -10
  160. package/dist/src/utils/version-check.test.js.map +1 -1
  161. package/dist/tests/SecurityScanner.scoring.test.js +123 -0
  162. package/dist/tests/SecurityScanner.scoring.test.js.map +1 -1
  163. package/dist/tests/security/advisory-severity-guard.test.d.ts +20 -0
  164. package/dist/tests/security/advisory-severity-guard.test.d.ts.map +1 -0
  165. package/dist/tests/security/advisory-severity-guard.test.js +70 -0
  166. package/dist/tests/security/advisory-severity-guard.test.js.map +1 -0
  167. package/dist/tests/security/archive-evasion.test.d.ts +2 -0
  168. package/dist/tests/security/archive-evasion.test.d.ts.map +1 -0
  169. package/dist/tests/security/archive-evasion.test.js +126 -0
  170. package/dist/tests/security/archive-evasion.test.js.map +1 -0
  171. package/dist/tests/security/clawhavoc-e2e.fixtures.d.ts +71 -0
  172. package/dist/tests/security/clawhavoc-e2e.fixtures.d.ts.map +1 -0
  173. package/dist/tests/security/clawhavoc-e2e.fixtures.js +135 -0
  174. package/dist/tests/security/clawhavoc-e2e.fixtures.js.map +1 -0
  175. package/dist/tests/security/co-signal-escalation.test.d.ts +30 -0
  176. package/dist/tests/security/co-signal-escalation.test.d.ts.map +1 -0
  177. package/dist/tests/security/co-signal-escalation.test.js +494 -0
  178. package/dist/tests/security/co-signal-escalation.test.js.map +1 -0
  179. package/dist/tests/security/decoy-misdirection.test.d.ts +2 -0
  180. package/dist/tests/security/decoy-misdirection.test.d.ts.map +1 -0
  181. package/dist/tests/security/decoy-misdirection.test.js +130 -0
  182. package/dist/tests/security/decoy-misdirection.test.js.map +1 -0
  183. package/dist/tests/security/encoded-payload.test.d.ts +2 -0
  184. package/dist/tests/security/encoded-payload.test.d.ts.map +1 -0
  185. package/dist/tests/security/encoded-payload.test.js +199 -0
  186. package/dist/tests/security/encoded-payload.test.js.map +1 -0
  187. package/dist/tests/security/gatekeeper-bypass.test.d.ts +2 -0
  188. package/dist/tests/security/gatekeeper-bypass.test.d.ts.map +1 -0
  189. package/dist/tests/security/gatekeeper-bypass.test.js +167 -0
  190. package/dist/tests/security/gatekeeper-bypass.test.js.map +1 -0
  191. package/dist/tests/security/paste-host-fetch.test.d.ts +2 -0
  192. package/dist/tests/security/paste-host-fetch.test.d.ts.map +1 -0
  193. package/dist/tests/security/paste-host-fetch.test.js +199 -0
  194. package/dist/tests/security/paste-host-fetch.test.js.map +1 -0
  195. package/dist/tests/security/scanner-regression-guard.test.js +5 -0
  196. package/dist/tests/security/scanner-regression-guard.test.js.map +1 -1
  197. package/dist/tests/security/smi5879-corroboration.core.test.d.ts +31 -0
  198. package/dist/tests/security/smi5879-corroboration.core.test.d.ts.map +1 -0
  199. package/dist/tests/security/smi5879-corroboration.core.test.js +157 -0
  200. package/dist/tests/security/smi5879-corroboration.core.test.js.map +1 -0
  201. package/dist/tests/services/aidefence-feedback.test.js +5 -0
  202. package/dist/tests/services/aidefence-feedback.test.js.map +1 -1
  203. package/dist/tests/services/bundled-sibling-scan.test.js +171 -10
  204. package/dist/tests/services/bundled-sibling-scan.test.js.map +1 -1
  205. package/dist/tests/skill-md-cli-fallback-parity.test.d.ts +22 -0
  206. package/dist/tests/skill-md-cli-fallback-parity.test.d.ts.map +1 -0
  207. package/dist/tests/skill-md-cli-fallback-parity.test.js +92 -0
  208. package/dist/tests/skill-md-cli-fallback-parity.test.js.map +1 -0
  209. package/dist/tests/skill-scanner/allowlist.test.js +14 -1
  210. package/dist/tests/skill-scanner/allowlist.test.js.map +1 -1
  211. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityScanner.compound.js","sourceRoot":"","sources":["../../../../src/security/scanner/SecurityScanner.compound.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SecurityScanner.compound.js","sourceRoot":"","sources":["../../../../src/security/scanner/SecurityScanner.compound.ts"],"names":[],"mappings":"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"}
@@ -5,10 +5,12 @@
5
5
  */
6
6
  import type { ScanReport, ScannerOptions } from './types.js';
7
7
  import type { LineContext } from './SecurityScanner.helpers.js';
8
- import { analyzeMarkdownContext, isDocumentationContext, isWithinInlineCode, calculateRiskScore } from './SecurityScanner.helpers.js';
8
+ import { analyzeMarkdownContext, isDocumentationContext, isWithinInlineCode } from './SecurityScanner.helpers.js';
9
+ import { extractUrls } from './SecurityScanner.urls.js';
10
+ import { calculateRiskScore } from './SecurityScanner.risk-score.js';
9
11
  import { scanSsrfPatterns } from './SecurityScanner.ssrf.js';
10
12
  import { toMinimalRefs, toSARIF, toGitHubAnnotations, toSummary } from './SecurityScanner.formatters.js';
11
- export { LineContext, analyzeMarkdownContext, isDocumentationContext, isWithinInlineCode, calculateRiskScore, };
13
+ export { LineContext, analyzeMarkdownContext, isDocumentationContext, isWithinInlineCode, calculateRiskScore, extractUrls, };
12
14
  export { scanSsrfPatterns };
13
15
  export { toMinimalRefs, toSARIF, toGitHubAnnotations, toSummary };
14
16
  export declare class SecurityScanner {
@@ -17,7 +19,6 @@ export declare class SecurityScanner {
17
19
  private maxContentLength;
18
20
  private riskThreshold;
19
21
  constructor(options?: ScannerOptions);
20
- private extractUrls;
21
22
  private isAllowedDomain;
22
23
  private scanUrls;
23
24
  private scanJailbreakPatterns;
@@ -25,7 +26,43 @@ export declare class SecurityScanner {
25
26
  private scanAIDefenceVulnerabilities;
26
27
  /** @deprecated Use standalone calculateRiskScore function for new code */
27
28
  calculateRiskScore: typeof calculateRiskScore;
28
- scan(skillId: string, content: string): ScanReport;
29
+ /**
30
+ * Run every content-scanning detector against `content` and return the
31
+ * combined findings. Factored out of `scan()` (SMI-6033 Wave 2, Gap 2) so
32
+ * the encoded-payload detector's recursive rescan of DECODED content can
33
+ * reuse the exact same detector suite instead of a parallel, narrower
34
+ * reimplementation.
35
+ *
36
+ * `skipEncodedPayload` is the STRUCTURAL depth-1 recursion guarantee: the
37
+ * recursive callback passed to `scanEncodedPayload` below always calls this
38
+ * method with `skipEncodedPayload: true`, so a base64 blob discovered
39
+ * INSIDE already-decoded content can never itself be decoded — the inner
40
+ * call cannot reach `scanEncodedPayload` again no matter what the decoded
41
+ * text contains. This disables ONLY the encoded-payload detector on the
42
+ * inner call, not the rest of the suite — a decoded `curl|bash` still
43
+ * trips `code_execution`, decoded secrets still trip `sensitive_path`, etc.
44
+ */
45
+ private runDetectors;
46
+ /**
47
+ * SMI-6033 Wave 3 (Gap 5): `isHighTrustAuthor` (default `false`) is the
48
+ * Gatekeeper-bypass trust-tier carve-out — see `scanGatekeeperBypass`'s own
49
+ * header (`SecurityScanner.compound.ts`) for the full policy. No in-repo
50
+ * caller of this method currently has a verified author signal to pass
51
+ * here (the indexer scans via the edge twin, not this core class); the
52
+ * parameter exists so a future verified-author caller can opt in, and so
53
+ * every existing call site (skill_validate, skill_rescan,
54
+ * bundled-sibling-scan, skill-installation.*) defaults closed by
55
+ * construction, not by convention.
56
+ *
57
+ * SMI-6033 Wave 2 (Gap 8) fix (2026-08-17): `isMarkdown` defaults `true`,
58
+ * preserving byte-identical behavior for every existing caller. Pass
59
+ * `false` when `content` is a real source file, not markdown — see
60
+ * `analyzeMarkdownContext`'s own header (SecurityScanner.helpers.ts) for
61
+ * why the markdown-only indented-code-block heuristic must never apply to
62
+ * non-markdown content. `bundled-sibling-scan.ts`'s
63
+ * `collectExecutableCodeFiles` candidates are the first real caller.
64
+ */
65
+ scan(skillId: string, content: string, isHighTrustAuthor?: boolean, isMarkdown?: boolean): ScanReport;
29
66
  quickCheck(content: string): boolean;
30
67
  addAllowedDomain(domain: string): void;
31
68
  addBlockedPattern(pattern: RegExp): void;
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityScanner.d.ts","sourceRoot":"","sources":["../../../../src/security/scanner/SecurityScanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAmB,UAAU,EAAE,cAAc,EAAqB,MAAM,YAAY,CAAA;AAUhG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAEnB,MAAM,8BAA8B,CAAA;AAGrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AA0B5D,OAAO,EACL,aAAa,EACb,OAAO,EACP,mBAAmB,EACnB,SAAS,EACV,MAAM,iCAAiC,CAAA;AAGxC,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,GACnB,CAAA;AACD,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAC3B,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,CAAA;AAEjE,qBAAa,eAAe;IAC1B,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,aAAa,CAAQ;gBAEjB,OAAO,GAAE,cAAmB;IAOxC,OAAO,CAAC,WAAW;IAenB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,qBAAqB;IAkB7B,OAAO,CAAC,sBAAsB;IA6D9B,OAAO,CAAC,4BAA4B;IAkBpC,0EAA0E;IAC1E,kBAAkB,4BAAqB;IAEvC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU;IA2FlD,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAOpC,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAItC,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKxC,MAAM,CAAC,aAAa,uBAAgB;IACpC,MAAM,CAAC,OAAO,iBAAU;IACxB,MAAM,CAAC,mBAAmB,6BAAsB;IAChD,MAAM,CAAC,SAAS,mBAAY;CAC7B;AAED,eAAe,eAAe,CAAA"}
1
+ {"version":3,"file":"SecurityScanner.d.ts","sourceRoot":"","sources":["../../../../src/security/scanner/SecurityScanner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAmB,UAAU,EAAE,cAAc,EAAqB,MAAM,YAAY,CAAA;AAUhG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC/D,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAEvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AAGpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAA;AAsC5D,OAAO,EACL,aAAa,EACb,OAAO,EACP,mBAAmB,EACnB,SAAS,EACV,MAAM,iCAAiC,CAAA;AAGxC,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,sBAAsB,EACtB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,GACZ,CAAA;AACD,OAAO,EAAE,gBAAgB,EAAE,CAAA;AAC3B,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,CAAA;AAEjE,qBAAa,eAAe;IAC1B,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,gBAAgB,CAAQ;IAChC,OAAO,CAAC,aAAa,CAAQ;gBAEjB,OAAO,GAAE,cAAmB;IAOxC,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,qBAAqB;IAkB7B,OAAO,CAAC,sBAAsB;IA6D9B,OAAO,CAAC,4BAA4B;IAkBpC,0EAA0E;IAC1E,kBAAkB,4BAAqB;IAEvC;;;;;;;;;;;;;;;OAeG;IACH,OAAO,CAAC,YAAY;IAwGpB;;;;;;;;;;;;;;;;;;OAkBG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,iBAAiB,UAAQ,EAAE,UAAU,UAAO,GAAG,UAAU;IA+ChG,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAOpC,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAItC,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKxC,MAAM,CAAC,aAAa,uBAAgB;IACpC,MAAM,CAAC,OAAO,iBAAU;IACxB,MAAM,CAAC,mBAAmB,6BAAsB;IAChD,MAAM,CAAC,SAAS,mBAAY;CAC7B;AAED,eAAe,eAAe,CAAA"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Security Scanner — decoy/misdirection URL-target heuristic
3
+ * @module @skillsmith/core/security/scanner/SecurityScanner.decoy
4
+ *
5
+ * SMI-6033 Wave 4 (Gap 6): reuses the typosquat detector's brand data —
6
+ * `BRAND_ALIASES` (typosquat.ts) and `AUTHORITY_CLAIMING_AFFIXES`
7
+ * (typosquat.ts, exported for exactly this reuse as part of Wave 1's Gap 6
8
+ * prerequisite) — to catch a fetch/exec instruction whose surrounding prose
9
+ * claims a specific vendor (a brand token, optionally reinforced by an
10
+ * authority-claiming affix like "official"/"verified") while the fetch
11
+ * target's actual domain does not belong to that vendor and is not in the
12
+ * general `DEFAULT_ALLOWED_DOMAINS` allowlist.
13
+ *
14
+ * Per the plan's §9 reconciliation table: `decoy_misdirection` is "N/A —
15
+ * never standalone... Approximate NL heuristic by construction; co-signal
16
+ * required (medium tier), unchanged." This detector therefore NEVER emits
17
+ * `high`/`critical` — only `medium`, or nothing (see the doc-context
18
+ * downgrade below, which uses `low`, not a third severity choice for the
19
+ * non-doc case). The co-signal mechanism that would let this medium finding
20
+ * contribute toward escalating a separate weak `code_execution` finding is a
21
+ * SEPARATE dispatch's job — `SecurityScanner.exec.ts`'s
22
+ * `CO_SIGNAL_MIN_SEVERITY` replacement — and is NOT implemented in this file.
23
+ *
24
+ * Design note, NOT explicit in the plan text and flagged here for review:
25
+ * the plan says to compare "the claimed vendor's canonical domain" against
26
+ * the fetch target's domain, but `BRAND_ALIASES`'s values are GitHub OWNER
27
+ * SLUGS (`anthropics`, `google-gemini`, ...) — they answer "whose GitHub org
28
+ * publishes this," not "what is this vendor's real website." A small
29
+ * curated `BRAND_CANONICAL_DOMAINS` map below, scoped to the exact same six
30
+ * brand tokens `BRAND_ALIASES` already curates, fills that gap; a brand
31
+ * token with no entry here is not currently possible (the two maps share the
32
+ * same key set by construction) but the lookup fails safe (empty domain
33
+ * list -> never matches -> never suppresses) if that ever drifts.
34
+ *
35
+ * Second design note: the plan text reads "a brand token OR an
36
+ * authority-claiming phrase implying a specific vendor." An authority-
37
+ * claiming affix ALONE ("the official installer") never names a specific
38
+ * vendor and so cannot resolve a canonical domain to compare against — this
39
+ * detector therefore requires a brand-token match to identify "the claimed
40
+ * vendor" at all (necessary for the domain comparison to mean anything), and
41
+ * treats a co-occurring authority-claiming affix as a confidence booster
42
+ * (medium -> high), not an alternate, independently-sufficient trigger. This
43
+ * mirrors typosquat.ts's own rule 3 (`hasBrandToken && hasAuthorityAffix`),
44
+ * which also requires both signals together.
45
+ *
46
+ * Two fixes from adversarial review (2026-08-16 — see
47
+ * docs/internal/code_review/2026-08-15-smi6033-wave4-escalation-model.md
48
+ * for the full account):
49
+ *
50
+ * 1. Fetch-target correlation. The original version treated ANY URL on a
51
+ * line that ALSO matched the generic FETCH_COMMAND_PATTERN as the fetch
52
+ * target — including a URL that was merely mentioned in prose alongside
53
+ * an unrelated fetch-verb usage on the same line (e.g.
54
+ * "curl --version; see mirror documentation at <url>", where curl is
55
+ * checking its own version, not fetching that URL). Replaced with
56
+ * `isActualFetchTarget`, which requires the fetch verb to be
57
+ * IMMEDIATELY followed (only flag-like tokens and whitespace, no
58
+ * command separator, no prose) by the URL — i.e. the URL must actually
59
+ * be the verb's argument.
60
+ *
61
+ * 2. Authority-affix proximity. `hasAuthorityAffix` used to scan the ENTIRE
62
+ * ±5-line window independently of where the brand token itself was
63
+ * found, so an unrelated authority phrase elsewhere in the window (e.g.
64
+ * "for official documentation on Python packaging, see PEP 517") could
65
+ * wrongly boost confidence to 'high' for a brand claim it has nothing to
66
+ * do with. Now scoped to a tight window around the brand token's OWN
67
+ * line (`DECOY_AUTHORITY_AFFIX_PROXIMITY_LINES`).
68
+ */
69
+ import type { SecurityFinding } from './types.js';
70
+ import type { LineContext } from './SecurityScanner.helpers.js';
71
+ export declare function scanDecoyMisdirection(content: string, lineContexts?: LineContext[]): SecurityFinding[];
72
+ //# sourceMappingURL=SecurityScanner.decoy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecurityScanner.decoy.d.ts","sourceRoot":"","sources":["../../../../src/security/scanner/SecurityScanner.decoy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAuK/D,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,WAAW,EAAE,GAC3B,eAAe,EAAE,CAiDnB"}
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Security Scanner — decoy/misdirection URL-target heuristic
3
+ * @module @skillsmith/core/security/scanner/SecurityScanner.decoy
4
+ *
5
+ * SMI-6033 Wave 4 (Gap 6): reuses the typosquat detector's brand data —
6
+ * `BRAND_ALIASES` (typosquat.ts) and `AUTHORITY_CLAIMING_AFFIXES`
7
+ * (typosquat.ts, exported for exactly this reuse as part of Wave 1's Gap 6
8
+ * prerequisite) — to catch a fetch/exec instruction whose surrounding prose
9
+ * claims a specific vendor (a brand token, optionally reinforced by an
10
+ * authority-claiming affix like "official"/"verified") while the fetch
11
+ * target's actual domain does not belong to that vendor and is not in the
12
+ * general `DEFAULT_ALLOWED_DOMAINS` allowlist.
13
+ *
14
+ * Per the plan's §9 reconciliation table: `decoy_misdirection` is "N/A —
15
+ * never standalone... Approximate NL heuristic by construction; co-signal
16
+ * required (medium tier), unchanged." This detector therefore NEVER emits
17
+ * `high`/`critical` — only `medium`, or nothing (see the doc-context
18
+ * downgrade below, which uses `low`, not a third severity choice for the
19
+ * non-doc case). The co-signal mechanism that would let this medium finding
20
+ * contribute toward escalating a separate weak `code_execution` finding is a
21
+ * SEPARATE dispatch's job — `SecurityScanner.exec.ts`'s
22
+ * `CO_SIGNAL_MIN_SEVERITY` replacement — and is NOT implemented in this file.
23
+ *
24
+ * Design note, NOT explicit in the plan text and flagged here for review:
25
+ * the plan says to compare "the claimed vendor's canonical domain" against
26
+ * the fetch target's domain, but `BRAND_ALIASES`'s values are GitHub OWNER
27
+ * SLUGS (`anthropics`, `google-gemini`, ...) — they answer "whose GitHub org
28
+ * publishes this," not "what is this vendor's real website." A small
29
+ * curated `BRAND_CANONICAL_DOMAINS` map below, scoped to the exact same six
30
+ * brand tokens `BRAND_ALIASES` already curates, fills that gap; a brand
31
+ * token with no entry here is not currently possible (the two maps share the
32
+ * same key set by construction) but the lookup fails safe (empty domain
33
+ * list -> never matches -> never suppresses) if that ever drifts.
34
+ *
35
+ * Second design note: the plan text reads "a brand token OR an
36
+ * authority-claiming phrase implying a specific vendor." An authority-
37
+ * claiming affix ALONE ("the official installer") never names a specific
38
+ * vendor and so cannot resolve a canonical domain to compare against — this
39
+ * detector therefore requires a brand-token match to identify "the claimed
40
+ * vendor" at all (necessary for the domain comparison to mean anything), and
41
+ * treats a co-occurring authority-claiming affix as a confidence booster
42
+ * (medium -> high), not an alternate, independently-sufficient trigger. This
43
+ * mirrors typosquat.ts's own rule 3 (`hasBrandToken && hasAuthorityAffix`),
44
+ * which also requires both signals together.
45
+ *
46
+ * Two fixes from adversarial review (2026-08-16 — see
47
+ * docs/internal/code_review/2026-08-15-smi6033-wave4-escalation-model.md
48
+ * for the full account):
49
+ *
50
+ * 1. Fetch-target correlation. The original version treated ANY URL on a
51
+ * line that ALSO matched the generic FETCH_COMMAND_PATTERN as the fetch
52
+ * target — including a URL that was merely mentioned in prose alongside
53
+ * an unrelated fetch-verb usage on the same line (e.g.
54
+ * "curl --version; see mirror documentation at <url>", where curl is
55
+ * checking its own version, not fetching that URL). Replaced with
56
+ * `isActualFetchTarget`, which requires the fetch verb to be
57
+ * IMMEDIATELY followed (only flag-like tokens and whitespace, no
58
+ * command separator, no prose) by the URL — i.e. the URL must actually
59
+ * be the verb's argument.
60
+ *
61
+ * 2. Authority-affix proximity. `hasAuthorityAffix` used to scan the ENTIRE
62
+ * ±5-line window independently of where the brand token itself was
63
+ * found, so an unrelated authority phrase elsewhere in the window (e.g.
64
+ * "for official documentation on Python packaging, see PEP 517") could
65
+ * wrongly boost confidence to 'high' for a brand claim it has nothing to
66
+ * do with. Now scoped to a tight window around the brand token's OWN
67
+ * line (`DECOY_AUTHORITY_AFFIX_PROXIMITY_LINES`).
68
+ */
69
+ import { analyzeMarkdownContext, isDocumentationContext } from './SecurityScanner.helpers.js';
70
+ import { extractUrls } from './SecurityScanner.urls.js';
71
+ import { DEFAULT_ALLOWED_DOMAINS } from './patterns.js';
72
+ import { BRAND_ALIASES, AUTHORITY_CLAIMING_AFFIXES } from './typosquat.js';
73
+ /** Bounded prose window (±N lines) around a fetch/exec instruction, per the plan's Gap 6 text. */
74
+ const DECOY_WINDOW_LINES = 5;
75
+ /**
76
+ * How close an authority-claiming affix ("official", "verified", ...) must
77
+ * be to the brand token's OWN line for it to count as a confidence booster.
78
+ * Same-line-only (adversarial-review fix, 2026-08-16) — the affix and the
79
+ * brand claim must plausibly be part of the SAME sentence/claim, not merely
80
+ * co-located somewhere in the wider fetch-correlation window OR on an
81
+ * adjacent line carrying an unrelated sentence (a real adversarial-review
82
+ * example: "For official documentation on Python packaging, see PEP 517."
83
+ * on the line right after a genuine, affix-free "Claude API" brand mention —
84
+ * a ±1-line window still wrongly pairs the two).
85
+ */
86
+ const DECOY_AUTHORITY_AFFIX_PROXIMITY_LINES = 0;
87
+ const FETCH_VERBS = new Set(['curl', 'wget', 'npx']);
88
+ /** A bare flag token, e.g. `-o`, `-fsSL`, `--output`, `--data=x`. */
89
+ const FLAG_TOKEN = /^-{1,2}[A-Za-z][\w-]*$/;
90
+ /**
91
+ * Common curl/wget/npx flags that take a SEPARATE value token (e.g.
92
+ * `-o setup.sh`, `-X POST`) — that value token must be consumed as part of
93
+ * the flag, not mistaken for prose.
94
+ */
95
+ const VALUE_TAKING_FLAGS = new Set([
96
+ '-o',
97
+ '-x',
98
+ '-h',
99
+ '-d',
100
+ '-a',
101
+ '-e',
102
+ '-u',
103
+ '-b',
104
+ '--output',
105
+ '--request',
106
+ '--header',
107
+ '--data',
108
+ '--data-raw',
109
+ '--data-binary',
110
+ '--data-urlencode',
111
+ '--user-agent',
112
+ '--referer',
113
+ '--proxy',
114
+ '--cookie',
115
+ ]);
116
+ /**
117
+ * True when `url` (verbatim substring of `lineContent`) is actually the
118
+ * argument to a fetch verb (curl/wget/npx, or `git clone`) on that line —
119
+ * not merely co-located with one. Tokenizes the prefix before the URL:
120
+ * rejects outright on any command separator (`;`, `|`, `&`), requires the
121
+ * prefix to start with the fetch verb, and requires every remaining token to
122
+ * be either a flag or the value argument of a value-taking flag (e.g.
123
+ * `curl -o setup.sh <url>`) — any other token (prose) fails the match.
124
+ * Rejects "curl --version; see mirror documentation at <url>" (the URL is
125
+ * not curl's argument, and the `;` alone already disqualifies it); accepts
126
+ * "curl -fsSL <url>", "curl -o setup.sh <url>", "wget <url>",
127
+ * "git clone <url>", "npx --yes <url>".
128
+ */
129
+ function isActualFetchTarget(lineContent, url) {
130
+ const urlIndex = lineContent.indexOf(url);
131
+ if (urlIndex < 0)
132
+ return false;
133
+ const prefix = lineContent.slice(0, urlIndex);
134
+ if (/[;|&]/.test(prefix))
135
+ return false;
136
+ const tokens = prefix
137
+ .trim()
138
+ .split(/\s+/)
139
+ .filter((t) => t.length > 0);
140
+ if (tokens.length === 0)
141
+ return false;
142
+ let i;
143
+ if (tokens[0]?.toLowerCase() === 'git' && tokens[1]?.toLowerCase() === 'clone') {
144
+ i = 2;
145
+ }
146
+ else if (FETCH_VERBS.has(tokens[0]?.toLowerCase() ?? '')) {
147
+ i = 1;
148
+ }
149
+ else {
150
+ return false;
151
+ }
152
+ for (; i < tokens.length; i++) {
153
+ const token = tokens[i];
154
+ if (!FLAG_TOKEN.test(token))
155
+ return false;
156
+ if (VALUE_TAKING_FLAGS.has(token.toLowerCase()) && i + 1 < tokens.length) {
157
+ i++; // consume the flag's own value token too
158
+ }
159
+ }
160
+ return true;
161
+ }
162
+ /**
163
+ * Curated canonical domain(s) per `BRAND_ALIASES` brand token — see this
164
+ * file's own header for why this cannot simply reuse `BRAND_ALIASES`'
165
+ * values directly (those are GitHub owner slugs, not DNS domains).
166
+ */
167
+ const BRAND_CANONICAL_DOMAINS = {
168
+ anthropic: ['anthropic.com', 'claude.ai'],
169
+ claude: ['anthropic.com', 'claude.ai'],
170
+ gemini: ['google.com', 'ai.google.dev', 'deepmind.google'],
171
+ copilot: ['github.com', 'microsoft.com'],
172
+ vercel: ['vercel.com'],
173
+ salesforce: ['salesforce.com'],
174
+ };
175
+ /** Split a line into lowercase alphanumeric tokens on any separator (mirrors typosquat.ts's own `tokenize`). */
176
+ function tokenize(raw) {
177
+ return raw
178
+ .toLowerCase()
179
+ .split(/[^a-z0-9]+/i)
180
+ .filter((t) => t.length > 0);
181
+ }
182
+ /** Exact-or-subdomain match against a domain set (mirrors `isAllowedDomain`'s own logic in SecurityScanner.ts). */
183
+ function matchesDomainSet(hostname, domains) {
184
+ return domains.some((d) => hostname === d || hostname.endsWith('.' + d));
185
+ }
186
+ /**
187
+ * Scan a bounded ±`DECOY_WINDOW_LINES` window around `lineIndex` for a brand
188
+ * token (required). Returns `null` when no brand token is present — nothing
189
+ * to compare a fetch target's domain against. `hasAuthorityAffix` is then
190
+ * resolved separately, scoped tightly to the brand token's OWN line (see
191
+ * `DECOY_AUTHORITY_AFFIX_PROXIMITY_LINES` and this file's header note on the
192
+ * adversarial-review fix) — NOT the wider fetch-correlation window, so an
193
+ * authority phrase unrelated to this specific brand claim can't wrongly
194
+ * boost confidence.
195
+ */
196
+ function findVendorClaimInWindow(lines, lineIndex) {
197
+ const start = Math.max(0, lineIndex - DECOY_WINDOW_LINES);
198
+ const end = Math.min(lines.length - 1, lineIndex + DECOY_WINDOW_LINES);
199
+ let brandToken = null;
200
+ let brandLineIndex = -1;
201
+ for (let i = start; i <= end && !brandToken; i++) {
202
+ for (const token of tokenize(lines[i] ?? '')) {
203
+ if (Object.prototype.hasOwnProperty.call(BRAND_ALIASES, token)) {
204
+ brandToken = token;
205
+ brandLineIndex = i;
206
+ break;
207
+ }
208
+ }
209
+ }
210
+ if (!brandToken)
211
+ return null;
212
+ const affixStart = Math.max(0, brandLineIndex - DECOY_AUTHORITY_AFFIX_PROXIMITY_LINES);
213
+ const affixEnd = Math.min(lines.length - 1, brandLineIndex + DECOY_AUTHORITY_AFFIX_PROXIMITY_LINES);
214
+ const hasAuthorityAffix = tokenize(lines.slice(affixStart, affixEnd + 1).join(' ')).some((t) => AUTHORITY_CLAIMING_AFFIXES.has(t));
215
+ return { brandToken, hasAuthorityAffix };
216
+ }
217
+ export function scanDecoyMisdirection(content, lineContexts) {
218
+ const findings = [];
219
+ const lines = content.split('\n');
220
+ const contexts = lineContexts ?? analyzeMarkdownContext(content);
221
+ const urls = extractUrls(content);
222
+ for (const { url, line } of urls) {
223
+ const lineIndex = line - 1;
224
+ const lineContent = lines[lineIndex] ?? '';
225
+ // Only a URL that is ACTUALLY the argument to a fetch verb is in scope —
226
+ // a bare linked URL ("see https://docs.example.com") is not, and neither
227
+ // is a URL merely co-located on a line with an unrelated fetch-verb
228
+ // usage (adversarial-review fix, 2026-08-16 — see isActualFetchTarget's
229
+ // own doc comment).
230
+ if (!isActualFetchTarget(lineContent, url))
231
+ continue;
232
+ let hostname;
233
+ try {
234
+ hostname = new URL(url).hostname.toLowerCase();
235
+ }
236
+ catch {
237
+ continue;
238
+ }
239
+ const claim = findVendorClaimInWindow(lines, lineIndex);
240
+ if (!claim)
241
+ continue; // no vendor claim nearby -> nothing to compare against; not a general brand-mention detector
242
+ const canonicalDomains = BRAND_CANONICAL_DOMAINS[claim.brandToken] ?? [];
243
+ if (matchesDomainSet(hostname, canonicalDomains))
244
+ continue; // fetch target IS the claimed vendor's own domain
245
+ if (matchesDomainSet(hostname, DEFAULT_ALLOWED_DOMAINS))
246
+ continue; // generally-trusted host, excluded per the plan text
247
+ const ctx = contexts[lineIndex];
248
+ const inDocContext = ctx ? isDocumentationContext(ctx) : false;
249
+ findings.push({
250
+ type: 'decoy_misdirection',
251
+ // Never high/critical — an approximate NL heuristic by construction
252
+ // (plan §9 reconciliation table); the escalation-into-code_execution
253
+ // co-signal mechanism lives in a separate dispatch.
254
+ severity: inDocContext ? 'low' : 'medium',
255
+ message: `Fetch target domain ("${hostname}") does not match the "${claim.brandToken}" vendor claimed nearby in the skill's own prose: ${url}`,
256
+ location: lineContent.trim().slice(0, 100),
257
+ lineNumber: line,
258
+ category: 'decoy_misdirection',
259
+ inDocumentationContext: inDocContext,
260
+ confidence: inDocContext ? 'low' : claim.hasAuthorityAffix ? 'high' : 'medium',
261
+ });
262
+ }
263
+ return findings;
264
+ }
265
+ //# sourceMappingURL=SecurityScanner.decoy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecurityScanner.decoy.js","sourceRoot":"","sources":["../../../../src/security/scanner/SecurityScanner.decoy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Security Scanner — encoded (base64) payload detect-decode-recursively-rescan
3
+ * @module @skillsmith/core/security/scanner/SecurityScanner.encoding
4
+ *
5
+ * SMI-6033 Wave 2 (Gap 2): before this file, `base64 -d | sh` (the DECODE
6
+ * INVOCATION syntax) was already caught by CODE_EXECUTION_PATTERNS, but an
7
+ * inert base64 blob the agent is merely instructed to decode and run itself
8
+ * scored zero.
9
+ *
10
+ * Rather than a parallel "this looks suspicious" heuristic (high FP risk —
11
+ * base64 blobs are extremely common in legitimate skills: image data URIs,
12
+ * git hashes, JWTs), this detector DECODES the candidate and recursively runs
13
+ * the caller's full detector suite against the decoded text, reusing the
14
+ * whole pattern arsenal instead of duplicating it. The escalation this gap
15
+ * achieves is free: a decoded `curl|bash` natively trips `code_execution` at
16
+ * ITS OWN severity, exactly as if the attacker had shipped it undecoded.
17
+ *
18
+ * Depth-1-only, STRUCTURALLY (not by convention). This module never scans
19
+ * itself — `rescan`, the callback the caller supplies, is expected to be the
20
+ * caller's OWN "run every detector" entry point with the encoded-payload
21
+ * detector specifically disabled for that inner call (see
22
+ * `SecurityScanner.ts`'s `runDetectors(content, lineContexts,
23
+ * skipEncodedPayload)`, where the recursive callback always passes `true`).
24
+ * The inner call therefore cannot reach this detector again no matter what
25
+ * the decoded content contains — a base64 blob discovered INSIDE decoded
26
+ * content is never itself decoded.
27
+ *
28
+ * Candidate detection: a contiguous base64-alphabet run,
29
+ * `[A-Za-z0-9+/]{120,}={0,2}`. Deliberately EXCLUDES `-`/`_` (base64url), so
30
+ * a JWT never becomes a candidate at all — that is the intentional mechanism
31
+ * keeping JWTs out, not a separate check. Bounded/ReDoS-safe: a single
32
+ * character-class quantifier has no catastrophic-backtracking surface, so
33
+ * this intentionally does NOT route through `safeRegexTest`'s 10,000-char
34
+ * truncation — a legitimate base64 blob routinely runs past that on one long
35
+ * line, and truncating it would silently defeat detection.
36
+ *
37
+ * The wrapper finding (`encoded_payload`) is advisory-tier ONLY (weight 1.2 /
38
+ * coefficient 0.04 — the sensitive_path/typosquat tier, NOT the 2.0/0.40 tier
39
+ * the other three Wave 2 detectors use, see weights.ts): this detector is
40
+ * pure observability/provenance-marking, not itself a strong signal. Every
41
+ * finding folded in from the decoded content carries a NEW `decodedFrom`
42
+ * field (types.ts) set to the OUTER document line the blob was found on —
43
+ * the same provenance-marker role `filePath` already plays for a
44
+ * sibling-file finding, just for a decoded-blob origin instead of a
45
+ * different file.
46
+ */
47
+ import type { SecurityFinding } from './types.js';
48
+ import type { LineContext } from './SecurityScanner.helpers.js';
49
+ /**
50
+ * Callback the caller (`SecurityScanner`) supplies to run its OWN full
51
+ * detector suite against decoded text, with the encoded-payload detector
52
+ * itself disabled — the structural depth-1 guarantee (see module header).
53
+ */
54
+ export type EncodedPayloadRescanner = (decodedContent: string) => SecurityFinding[];
55
+ export declare function scanEncodedPayload(content: string, lineContexts: LineContext[] | undefined, rescan: EncodedPayloadRescanner): SecurityFinding[];
56
+ //# sourceMappingURL=SecurityScanner.encoding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SecurityScanner.encoding.d.ts","sourceRoot":"","sources":["../../../../src/security/scanner/SecurityScanner.encoding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AA2I/D;;;;GAIG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,cAAc,EAAE,MAAM,KAAK,eAAe,EAAE,CAAA;AAEnF,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,WAAW,EAAE,GAAG,SAAS,EACvC,MAAM,EAAE,uBAAuB,GAC9B,eAAe,EAAE,CAsGnB"}