insa-check-core 0.1.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 (258) hide show
  1. package/LICENSE +24 -0
  2. package/dist/annex-b.d.ts +6 -0
  3. package/dist/annex-b.d.ts.map +1 -0
  4. package/dist/annex-b.js +152 -0
  5. package/dist/annex-b.js.map +1 -0
  6. package/dist/checks/content/page.d.ts +7 -0
  7. package/dist/checks/content/page.d.ts.map +1 -0
  8. package/dist/checks/content/page.js +133 -0
  9. package/dist/checks/content/page.js.map +1 -0
  10. package/dist/checks/cookies/cookie-flags.d.ts +3 -0
  11. package/dist/checks/cookies/cookie-flags.d.ts.map +1 -0
  12. package/dist/checks/cookies/cookie-flags.js +41 -0
  13. package/dist/checks/cookies/cookie-flags.js.map +1 -0
  14. package/dist/checks/cookies/cookie-scope.d.ts +6 -0
  15. package/dist/checks/cookies/cookie-scope.d.ts.map +1 -0
  16. package/dist/checks/cookies/cookie-scope.js +60 -0
  17. package/dist/checks/cookies/cookie-scope.js.map +1 -0
  18. package/dist/checks/deployment/server-banner.d.ts +4 -0
  19. package/dist/checks/deployment/server-banner.d.ts.map +1 -0
  20. package/dist/checks/deployment/server-banner.js +60 -0
  21. package/dist/checks/deployment/server-banner.js.map +1 -0
  22. package/dist/checks/deployment/trace.d.ts +3 -0
  23. package/dist/checks/deployment/trace.d.ts.map +1 -0
  24. package/dist/checks/deployment/trace.js +30 -0
  25. package/dist/checks/deployment/trace.js.map +1 -0
  26. package/dist/checks/headers/clickjacking.d.ts +5 -0
  27. package/dist/checks/headers/clickjacking.d.ts.map +1 -0
  28. package/dist/checks/headers/clickjacking.js +57 -0
  29. package/dist/checks/headers/clickjacking.js.map +1 -0
  30. package/dist/checks/headers/content-type-options.d.ts +3 -0
  31. package/dist/checks/headers/content-type-options.d.ts.map +1 -0
  32. package/dist/checks/headers/content-type-options.js +17 -0
  33. package/dist/checks/headers/content-type-options.js.map +1 -0
  34. package/dist/checks/headers/cors.d.ts +4 -0
  35. package/dist/checks/headers/cors.d.ts.map +1 -0
  36. package/dist/checks/headers/cors.js +38 -0
  37. package/dist/checks/headers/cors.js.map +1 -0
  38. package/dist/checks/html.d.ts +11 -0
  39. package/dist/checks/html.d.ts.map +1 -0
  40. package/dist/checks/html.js +30 -0
  41. package/dist/checks/html.js.map +1 -0
  42. package/dist/checks/index.d.ts +7 -0
  43. package/dist/checks/index.d.ts.map +1 -0
  44. package/dist/checks/index.js +48 -0
  45. package/dist/checks/index.js.map +1 -0
  46. package/dist/checks/info-disclosure/directory-listing.d.ts +6 -0
  47. package/dist/checks/info-disclosure/directory-listing.d.ts.map +1 -0
  48. package/dist/checks/info-disclosure/directory-listing.js +60 -0
  49. package/dist/checks/info-disclosure/directory-listing.js.map +1 -0
  50. package/dist/checks/info-disclosure/exposed-files.d.ts +4 -0
  51. package/dist/checks/info-disclosure/exposed-files.d.ts.map +1 -0
  52. package/dist/checks/info-disclosure/exposed-files.js +56 -0
  53. package/dist/checks/info-disclosure/exposed-files.js.map +1 -0
  54. package/dist/checks/info-disclosure/more.d.ts +8 -0
  55. package/dist/checks/info-disclosure/more.d.ts.map +1 -0
  56. package/dist/checks/info-disclosure/more.js +186 -0
  57. package/dist/checks/info-disclosure/more.js.map +1 -0
  58. package/dist/checks/tls/certificate.d.ts +3 -0
  59. package/dist/checks/tls/certificate.d.ts.map +1 -0
  60. package/dist/checks/tls/certificate.js +49 -0
  61. package/dist/checks/tls/certificate.js.map +1 -0
  62. package/dist/checks/tls/hsts.d.ts +5 -0
  63. package/dist/checks/tls/hsts.d.ts.map +1 -0
  64. package/dist/checks/tls/hsts.js +35 -0
  65. package/dist/checks/tls/hsts.js.map +1 -0
  66. package/dist/checks/tls/https-redirect.d.ts +3 -0
  67. package/dist/checks/tls/https-redirect.d.ts.map +1 -0
  68. package/dist/checks/tls/https-redirect.js +46 -0
  69. package/dist/checks/tls/https-redirect.js.map +1 -0
  70. package/dist/checks/tls/legacy-protocols.d.ts +3 -0
  71. package/dist/checks/tls/legacy-protocols.d.ts.map +1 -0
  72. package/dist/checks/tls/legacy-protocols.js +27 -0
  73. package/dist/checks/tls/legacy-protocols.js.map +1 -0
  74. package/dist/checks/util.d.ts +22 -0
  75. package/dist/checks/util.d.ts.map +1 -0
  76. package/dist/checks/util.js +63 -0
  77. package/dist/checks/util.js.map +1 -0
  78. package/dist/code/checks/crypto.d.ts +5 -0
  79. package/dist/code/checks/crypto.d.ts.map +1 -0
  80. package/dist/code/checks/crypto.js +100 -0
  81. package/dist/code/checks/crypto.js.map +1 -0
  82. package/dist/code/checks/django.d.ts +14 -0
  83. package/dist/code/checks/django.d.ts.map +1 -0
  84. package/dist/code/checks/django.js +313 -0
  85. package/dist/code/checks/django.js.map +1 -0
  86. package/dist/code/checks/flask.d.ts +6 -0
  87. package/dist/code/checks/flask.d.ts.map +1 -0
  88. package/dist/code/checks/flask.js +100 -0
  89. package/dist/code/checks/flask.js.map +1 -0
  90. package/dist/code/checks/index.d.ts +9 -0
  91. package/dist/code/checks/index.d.ts.map +1 -0
  92. package/dist/code/checks/index.js +126 -0
  93. package/dist/code/checks/index.js.map +1 -0
  94. package/dist/code/checks/injection.d.ts +27 -0
  95. package/dist/code/checks/injection.d.ts.map +1 -0
  96. package/dist/code/checks/injection.js +189 -0
  97. package/dist/code/checks/injection.js.map +1 -0
  98. package/dist/code/checks/javascript-config.d.ts +14 -0
  99. package/dist/code/checks/javascript-config.d.ts.map +1 -0
  100. package/dist/code/checks/javascript-config.js +251 -0
  101. package/dist/code/checks/javascript-config.js.map +1 -0
  102. package/dist/code/checks/javascript.d.ts +34 -0
  103. package/dist/code/checks/javascript.d.ts.map +1 -0
  104. package/dist/code/checks/javascript.js +333 -0
  105. package/dist/code/checks/javascript.js.map +1 -0
  106. package/dist/code/checks/php.d.ts +27 -0
  107. package/dist/code/checks/php.d.ts.map +1 -0
  108. package/dist/code/checks/php.js +433 -0
  109. package/dist/code/checks/php.js.map +1 -0
  110. package/dist/code/checks/secrets.d.ts +10 -0
  111. package/dist/code/checks/secrets.d.ts.map +1 -0
  112. package/dist/code/checks/secrets.js +140 -0
  113. package/dist/code/checks/secrets.js.map +1 -0
  114. package/dist/code/checks/shared.d.ts +25 -0
  115. package/dist/code/checks/shared.d.ts.map +1 -0
  116. package/dist/code/checks/shared.js +57 -0
  117. package/dist/code/checks/shared.js.map +1 -0
  118. package/dist/code/checks/treesitter.d.ts +15 -0
  119. package/dist/code/checks/treesitter.d.ts.map +1 -0
  120. package/dist/code/checks/treesitter.js +322 -0
  121. package/dist/code/checks/treesitter.js.map +1 -0
  122. package/dist/code/checks/xml.d.ts +9 -0
  123. package/dist/code/checks/xml.d.ts.map +1 -0
  124. package/dist/code/checks/xml.js +78 -0
  125. package/dist/code/checks/xml.js.map +1 -0
  126. package/dist/code/context.d.ts +6 -0
  127. package/dist/code/context.d.ts.map +1 -0
  128. package/dist/code/context.js +92 -0
  129. package/dist/code/context.js.map +1 -0
  130. package/dist/code/detect.d.ts +3 -0
  131. package/dist/code/detect.d.ts.map +1 -0
  132. package/dist/code/detect.js +118 -0
  133. package/dist/code/detect.js.map +1 -0
  134. package/dist/code/django/settings.d.ts +46 -0
  135. package/dist/code/django/settings.d.ts.map +1 -0
  136. package/dist/code/django/settings.js +154 -0
  137. package/dist/code/django/settings.js.map +1 -0
  138. package/dist/code/findings.d.ts +18 -0
  139. package/dist/code/findings.d.ts.map +1 -0
  140. package/dist/code/findings.js +63 -0
  141. package/dist/code/findings.js.map +1 -0
  142. package/dist/code/javascript/ast.d.ts +46 -0
  143. package/dist/code/javascript/ast.d.ts.map +1 -0
  144. package/dist/code/javascript/ast.js +166 -0
  145. package/dist/code/javascript/ast.js.map +1 -0
  146. package/dist/code/javascript/index.d.ts +3 -0
  147. package/dist/code/javascript/index.d.ts.map +1 -0
  148. package/dist/code/javascript/index.js +3 -0
  149. package/dist/code/javascript/index.js.map +1 -0
  150. package/dist/code/javascript/module.d.ts +59 -0
  151. package/dist/code/javascript/module.d.ts.map +1 -0
  152. package/dist/code/javascript/module.js +250 -0
  153. package/dist/code/javascript/module.js.map +1 -0
  154. package/dist/code/php/index.d.ts +92 -0
  155. package/dist/code/php/index.d.ts.map +1 -0
  156. package/dist/code/php/index.js +316 -0
  157. package/dist/code/php/index.js.map +1 -0
  158. package/dist/code/project.d.ts +13 -0
  159. package/dist/code/project.d.ts.map +1 -0
  160. package/dist/code/project.js +69 -0
  161. package/dist/code/project.js.map +1 -0
  162. package/dist/code/python/ast.d.ts +47 -0
  163. package/dist/code/python/ast.d.ts.map +1 -0
  164. package/dist/code/python/ast.js +193 -0
  165. package/dist/code/python/ast.js.map +1 -0
  166. package/dist/code/python/index.d.ts +3 -0
  167. package/dist/code/python/index.d.ts.map +1 -0
  168. package/dist/code/python/index.js +3 -0
  169. package/dist/code/python/index.js.map +1 -0
  170. package/dist/code/python/module.d.ts +55 -0
  171. package/dist/code/python/module.d.ts.map +1 -0
  172. package/dist/code/python/module.js +215 -0
  173. package/dist/code/python/module.js.map +1 -0
  174. package/dist/code/scan.d.ts +24 -0
  175. package/dist/code/scan.d.ts.map +1 -0
  176. package/dist/code/scan.js +159 -0
  177. package/dist/code/scan.js.map +1 -0
  178. package/dist/code/treesitter/index.d.ts +83 -0
  179. package/dist/code/treesitter/index.d.ts.map +1 -0
  180. package/dist/code/treesitter/index.js +243 -0
  181. package/dist/code/treesitter/index.js.map +1 -0
  182. package/dist/code/types.d.ts +48 -0
  183. package/dist/code/types.d.ts.map +1 -0
  184. package/dist/code/types.js +2 -0
  185. package/dist/code/types.js.map +1 -0
  186. package/dist/content/en.d.ts +3 -0
  187. package/dist/content/en.d.ts.map +1 -0
  188. package/dist/content/en.js +722 -0
  189. package/dist/content/en.js.map +1 -0
  190. package/dist/content/index.d.ts +15 -0
  191. package/dist/content/index.d.ts.map +1 -0
  192. package/dist/content/index.js +21 -0
  193. package/dist/content/index.js.map +1 -0
  194. package/dist/content/types.d.ts +87 -0
  195. package/dist/content/types.d.ts.map +1 -0
  196. package/dist/content/types.js +2 -0
  197. package/dist/content/types.js.map +1 -0
  198. package/dist/engine.d.ts +52 -0
  199. package/dist/engine.d.ts.map +1 -0
  200. package/dist/engine.js +120 -0
  201. package/dist/engine.js.map +1 -0
  202. package/dist/index.d.ts +12 -0
  203. package/dist/index.d.ts.map +1 -0
  204. package/dist/index.js +11 -0
  205. package/dist/index.js.map +1 -0
  206. package/dist/meta.d.ts +4 -0
  207. package/dist/meta.d.ts.map +1 -0
  208. package/dist/meta.js +4 -0
  209. package/dist/meta.js.map +1 -0
  210. package/dist/net/context.d.ts +9 -0
  211. package/dist/net/context.d.ts.map +1 -0
  212. package/dist/net/context.js +62 -0
  213. package/dist/net/context.js.map +1 -0
  214. package/dist/net/guard.d.ts +16 -0
  215. package/dist/net/guard.d.ts.map +1 -0
  216. package/dist/net/guard.js +70 -0
  217. package/dist/net/guard.js.map +1 -0
  218. package/dist/net/http.d.ts +22 -0
  219. package/dist/net/http.d.ts.map +1 -0
  220. package/dist/net/http.js +114 -0
  221. package/dist/net/http.js.map +1 -0
  222. package/dist/net/tls.d.ts +15 -0
  223. package/dist/net/tls.d.ts.map +1 -0
  224. package/dist/net/tls.js +103 -0
  225. package/dist/net/tls.js.map +1 -0
  226. package/dist/report/html.d.ts +14 -0
  227. package/dist/report/html.d.ts.map +1 -0
  228. package/dist/report/html.js +210 -0
  229. package/dist/report/html.js.map +1 -0
  230. package/dist/report/index.d.ts +10 -0
  231. package/dist/report/index.d.ts.map +1 -0
  232. package/dist/report/index.js +10 -0
  233. package/dist/report/index.js.map +1 -0
  234. package/dist/report/manual.d.ts +62 -0
  235. package/dist/report/manual.d.ts.map +1 -0
  236. package/dist/report/manual.js +190 -0
  237. package/dist/report/manual.js.map +1 -0
  238. package/dist/report/merge.d.ts +8 -0
  239. package/dist/report/merge.d.ts.map +1 -0
  240. package/dist/report/merge.js +135 -0
  241. package/dist/report/merge.js.map +1 -0
  242. package/dist/report/summary.d.ts +10 -0
  243. package/dist/report/summary.d.ts.map +1 -0
  244. package/dist/report/summary.js +27 -0
  245. package/dist/report/summary.js.map +1 -0
  246. package/dist/report/validate.d.ts +3 -0
  247. package/dist/report/validate.d.ts.map +1 -0
  248. package/dist/report/validate.js +78 -0
  249. package/dist/report/validate.js.map +1 -0
  250. package/dist/types.d.ts +244 -0
  251. package/dist/types.d.ts.map +1 -0
  252. package/dist/types.js +2 -0
  253. package/dist/types.js.map +1 -0
  254. package/dist/validate.d.ts +4 -0
  255. package/dist/validate.d.ts.map +1 -0
  256. package/dist/validate.js +24 -0
  257. package/dist/validate.js.map +1 -0
  258. package/package.json +40 -0
@@ -0,0 +1,18 @@
1
+ import type { CheckOutcome, CodeFinding, Confidence } from "../types.js";
2
+ import type { JsModule, JsNode } from "./javascript/index.js";
3
+ import type { PyModule, PyNode } from "./python/index.js";
4
+ /** Masks string literals that follow secret-looking names, so reports never repeat a hard-coded credential. */
5
+ export declare function redact(line: string): string;
6
+ export declare function snippetOf(line: string): string;
7
+ export declare function pyFinding(module: PyModule, node: PyNode, rule: string, confidence: Confidence, why: string): CodeFinding;
8
+ export declare function jsFinding(module: JsModule, node: JsNode, rule: string, confidence: Confidence, why: string): CodeFinding;
9
+ export declare function locations(findings: CodeFinding[], max?: number): string;
10
+ /**
11
+ * Standard verdict for pattern rules:
12
+ * - any high/medium finding -> fail
13
+ * - only low-confidence ones -> manual (needs review; never a definitive fail)
14
+ * - none -> pass ("no risky pattern found"; static analysis cannot prove absence)
15
+ */
16
+ export declare function outcomeFromFindings(raw: CodeFinding[], passDetail: string): CheckOutcome;
17
+ export declare const NO_PATTERN: (what: string, files: number, language?: string) => string;
18
+ //# sourceMappingURL=findings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.d.ts","sourceRoot":"","sources":["../../src/code/findings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAK1D,+GAA+G;AAC/G,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED,wBAAgB,SAAS,CACvB,MAAM,EAAE,QAAQ,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,UAAU,EACtB,GAAG,EAAE,MAAM,GACV,WAAW,CAEb;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,GAAG,WAAW,CAGxH;AAgBD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,GAAG,SAAI,GAAG,MAAM,CAGlE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,YAAY,CAoBxF;AAED,eAAO,MAAM,UAAU,SAAU,MAAM,SAAS,MAAM,8BACgE,CAAC"}
@@ -0,0 +1,63 @@
1
+ const SECRET_NAME = String.raw `[\w.\-]*(?:password|passwd|pwd|secret|token|api[_-]?key|apikey|private[_-]?key|access[_-]?key|credential)[\w.\-]*`;
2
+ const SECRET_LITERAL = new RegExp(String.raw `(${SECRET_NAME}["']?\s*(?:=>|[:=]|,)\s*[rbuf]*)(["'])((?:(?!\2).){1,})\2`, "gi");
3
+ /** Masks string literals that follow secret-looking names, so reports never repeat a hard-coded credential. */
4
+ export function redact(line) {
5
+ return line.replace(SECRET_LITERAL, (_m, prefix, q) => `${prefix}${q}****${q}`);
6
+ }
7
+ export function snippetOf(line) {
8
+ const trimmed = redact(line.trim());
9
+ return trimmed.length > 200 ? `${trimmed.slice(0, 197)}...` : trimmed;
10
+ }
11
+ export function pyFinding(module, node, rule, confidence, why) {
12
+ return { file: module.path, line: node._l ?? 1, snippet: snippetOf(module.line(node._l)), why, confidence, method: "ast", rule };
13
+ }
14
+ export function jsFinding(module, node, rule, confidence, why) {
15
+ const line = module.lineOf(node);
16
+ return { file: module.path, line, snippet: snippetOf(module.line(line)), why, confidence, method: "ast", rule };
17
+ }
18
+ const RANK = { high: 0, medium: 1, low: 2 };
19
+ function dedupe(findings) {
20
+ const seen = new Set();
21
+ return findings
22
+ .filter((f) => {
23
+ const k = `${f.file}:${f.line}:${f.rule}`;
24
+ if (seen.has(k))
25
+ return false;
26
+ seen.add(k);
27
+ return true;
28
+ })
29
+ .sort((a, b) => RANK[a.confidence] - RANK[b.confidence] || a.file.localeCompare(b.file) || a.line - b.line);
30
+ }
31
+ export function locations(findings, max = 3) {
32
+ const locs = findings.slice(0, max).map((f) => `${f.file}:${f.line}`);
33
+ return findings.length > max ? `${locs.join(", ")} (+${findings.length - max} more)` : locs.join(", ");
34
+ }
35
+ /**
36
+ * Standard verdict for pattern rules:
37
+ * - any high/medium finding -> fail
38
+ * - only low-confidence ones -> manual (needs review; never a definitive fail)
39
+ * - none -> pass ("no risky pattern found"; static analysis cannot prove absence)
40
+ */
41
+ export function outcomeFromFindings(raw, passDetail) {
42
+ const findings = dedupe(raw);
43
+ const decisive = findings.filter((f) => f.confidence !== "low");
44
+ const regexNote = findings.some((f) => f.method === "regex") ? " Includes text-pattern (regex) matches, which have a higher false-positive rate." : "";
45
+ if (decisive.length > 0) {
46
+ const low = findings.length - decisive.length;
47
+ return {
48
+ status: "fail",
49
+ detail: `${decisive.length} finding(s): ${locations(decisive)}.${low ? ` Plus ${low} low-confidence match(es) to review.` : ""}${regexNote}`,
50
+ findings,
51
+ };
52
+ }
53
+ if (findings.length > 0) {
54
+ return {
55
+ status: "manual",
56
+ detail: `${findings.length} low-confidence match(es) need review: ${locations(findings)}.${regexNote}`,
57
+ findings,
58
+ };
59
+ }
60
+ return { status: "pass", detail: passDetail };
61
+ }
62
+ export const NO_PATTERN = (what, files, language = "Python") => `No ${what} found in ${files} ${language} file(s). Static analysis cannot prove absence; review dynamic code paths.`;
63
+ //# sourceMappingURL=findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.js","sourceRoot":"","sources":["../../src/code/findings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * JavaScript / TypeScript syntax trees come from @babel/parser (handles JS, JSX, TS, TSX).
3
+ * Rules are written against the Babel AST, loosely typed like the Python bridge.
4
+ */
5
+ export interface JsNode {
6
+ type: string;
7
+ loc?: {
8
+ start: {
9
+ line: number;
10
+ column: number;
11
+ };
12
+ end: {
13
+ line: number;
14
+ column: number;
15
+ };
16
+ } | null;
17
+ [field: string]: unknown;
18
+ }
19
+ export interface JsParseResult {
20
+ ast?: JsNode;
21
+ error?: string;
22
+ }
23
+ /** Parses one file. Syntax errors are returned, not thrown, so one bad file never stops a scan. */
24
+ export declare function parseJs(source: string, filePath: string): JsParseResult;
25
+ export declare function isJsNode(x: unknown): x is JsNode;
26
+ export declare function childJsNodes(node: JsNode): JsNode[];
27
+ /** Depth-first, source order. `skip` prunes a subtree (e.g. nested functions). */
28
+ export declare function walkJs(root: JsNode, skip?: (n: JsNode) => boolean): Generator<JsNode>;
29
+ export declare const isJsFunction: (n: JsNode) => boolean;
30
+ /** Strips TypeScript wrappers and parentheses that don't change the value: `x as T`, `x!`, `<T>x`, `(x)`. */
31
+ export declare function unwrap(node: unknown): JsNode | undefined;
32
+ /** "a.b.c" for identifier / member chains; calls and computed access become "()" and "[]". */
33
+ export declare function jsDotted(node: unknown): string | undefined;
34
+ /** Value of a string literal or a template literal without placeholders. */
35
+ export declare function jsString(node: unknown): string | undefined;
36
+ export declare function isJsLiteral(node: unknown): boolean;
37
+ /** Template literal with placeholders, or "+" concatenation involving a string. */
38
+ export declare function isJsDynamicString(node: unknown): boolean;
39
+ export declare function jsArgs(call: JsNode): JsNode[];
40
+ /** Value of `key` in an object literal argument, e.g. { shell: true }. */
41
+ export declare function objectProp(node: unknown, key: string): JsNode | undefined;
42
+ export declare function isJsTrue(node: unknown): boolean;
43
+ export declare function isJsFalse(node: unknown): boolean;
44
+ /** Identifier and property names used in an expression (including string keys like obj["password"]). */
45
+ export declare function jsIdentifiers(node: JsNode): string[];
46
+ //# sourceMappingURL=ast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../../src/code/javascript/ast.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE;QAAE,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,GAAG,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAChG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,mGAAmG;AACnG,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAkBvE;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAEhD;AAID,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAQnD;AAED,kFAAkF;AAClF,wBAAiB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAQtF;AAKD,eAAO,MAAM,YAAY,MAAO,MAAM,YAA+B,CAAC;AAEtE,6GAA6G;AAC7G,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAMxD;AAED,8FAA8F;AAC9F,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAyB1D;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAQ1D;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAGlD;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAWxD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7C;AAED,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUzE;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAG/C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAGhD;AAED,wGAAwG;AACxG,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAUpD"}
@@ -0,0 +1,166 @@
1
+ import { parse } from "@babel/parser";
2
+ /** Parses one file. Syntax errors are returned, not thrown, so one bad file never stops a scan. */
3
+ export function parseJs(source, filePath) {
4
+ const isTs = /\.(ts|tsx|mts|cts)$/.test(filePath);
5
+ // In .ts files `<T>x` is a type assertion, so JSX is only enabled for .tsx and non-TS files.
6
+ const plugins = isTs
7
+ ? ["typescript", "decorators-legacy", ...(filePath.endsWith(".tsx") ? ["jsx"] : [])]
8
+ : ["jsx"];
9
+ try {
10
+ const file = parse(source, {
11
+ sourceType: "unambiguous",
12
+ plugins,
13
+ errorRecovery: true,
14
+ allowReturnOutsideFunction: true,
15
+ });
16
+ return { ast: file.program };
17
+ }
18
+ catch (err) {
19
+ const e = err;
20
+ return { error: `${e.message ?? "parse error"}${e.loc ? ` (line ${e.loc.line})` : ""}` };
21
+ }
22
+ }
23
+ export function isJsNode(x) {
24
+ return typeof x === "object" && x !== null && typeof x.type === "string";
25
+ }
26
+ const SKIP_KEYS = new Set(["loc", "start", "end", "range", "extra", "leadingComments", "trailingComments", "innerComments", "tokens"]);
27
+ export function childJsNodes(node) {
28
+ const out = [];
29
+ for (const [k, v] of Object.entries(node)) {
30
+ if (SKIP_KEYS.has(k))
31
+ continue;
32
+ if (isJsNode(v))
33
+ out.push(v);
34
+ else if (Array.isArray(v))
35
+ for (const x of v)
36
+ if (isJsNode(x))
37
+ out.push(x);
38
+ }
39
+ return out;
40
+ }
41
+ /** Depth-first, source order. `skip` prunes a subtree (e.g. nested functions). */
42
+ export function* walkJs(root, skip) {
43
+ const stack = [root];
44
+ while (stack.length) {
45
+ const node = stack.pop();
46
+ yield node;
47
+ const kids = childJsNodes(node);
48
+ for (let i = kids.length - 1; i >= 0; i--)
49
+ if (!skip?.(kids[i]))
50
+ stack.push(kids[i]);
51
+ }
52
+ }
53
+ const FUNCTION_TYPES = new Set([
54
+ "FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression", "ObjectMethod", "ClassMethod", "ClassPrivateMethod",
55
+ ]);
56
+ export const isJsFunction = (n) => FUNCTION_TYPES.has(n.type);
57
+ /** Strips TypeScript wrappers and parentheses that don't change the value: `x as T`, `x!`, `<T>x`, `(x)`. */
58
+ export function unwrap(node) {
59
+ let n = node;
60
+ while (isJsNode(n) && ["TSAsExpression", "TSNonNullExpression", "TSTypeAssertion", "TSSatisfiesExpression", "ParenthesizedExpression", "AwaitExpression"].includes(n.type)) {
61
+ n = n["expression"] ?? n["argument"];
62
+ }
63
+ return isJsNode(n) ? n : undefined;
64
+ }
65
+ /** "a.b.c" for identifier / member chains; calls and computed access become "()" and "[]". */
66
+ export function jsDotted(node) {
67
+ const n = unwrap(node);
68
+ if (!n)
69
+ return undefined;
70
+ switch (n.type) {
71
+ case "Identifier":
72
+ return n["name"];
73
+ case "ThisExpression":
74
+ return "this";
75
+ case "MemberExpression":
76
+ case "OptionalMemberExpression": {
77
+ const base = jsDotted(n["object"]);
78
+ if (base === undefined)
79
+ return undefined;
80
+ const prop = n["property"];
81
+ if (!n["computed"] && prop.type === "Identifier")
82
+ return `${base}.${prop["name"]}`;
83
+ const key = jsString(prop);
84
+ return key !== undefined ? `${base}.${key}` : `${base}[]`;
85
+ }
86
+ case "CallExpression":
87
+ case "OptionalCallExpression": {
88
+ const base = jsDotted(n["callee"]);
89
+ return base === undefined ? undefined : `${base}()`;
90
+ }
91
+ default:
92
+ return undefined;
93
+ }
94
+ }
95
+ /** Value of a string literal or a template literal without placeholders. */
96
+ export function jsString(node) {
97
+ const n = unwrap(node);
98
+ if (!n)
99
+ return undefined;
100
+ if (n.type === "StringLiteral")
101
+ return n["value"];
102
+ if (n.type === "TemplateLiteral" && n["expressions"].length === 0) {
103
+ return n["quasis"][0]?.["value"]?.cooked ?? "";
104
+ }
105
+ return undefined;
106
+ }
107
+ export function isJsLiteral(node) {
108
+ const n = unwrap(node);
109
+ return !!n && (jsString(n) !== undefined || ["NumericLiteral", "BooleanLiteral", "NullLiteral", "RegExpLiteral", "BigIntLiteral"].includes(n.type));
110
+ }
111
+ /** Template literal with placeholders, or "+" concatenation involving a string. */
112
+ export function isJsDynamicString(node) {
113
+ const n = unwrap(node);
114
+ if (!n)
115
+ return false;
116
+ if (n.type === "TemplateLiteral")
117
+ return n["expressions"].length > 0;
118
+ if (n.type === "BinaryExpression" && n["operator"] === "+") {
119
+ const stringy = (x) => jsString(x) !== undefined || isJsDynamicString(x);
120
+ const l = n["left"];
121
+ const r = n["right"];
122
+ return (stringy(l) || stringy(r)) && !(jsString(l) !== undefined && jsString(r) !== undefined);
123
+ }
124
+ return false;
125
+ }
126
+ export function jsArgs(call) {
127
+ return (call["arguments"] ?? []).filter(isJsNode);
128
+ }
129
+ /** Value of `key` in an object literal argument, e.g. { shell: true }. */
130
+ export function objectProp(node, key) {
131
+ const n = unwrap(node);
132
+ if (n?.type !== "ObjectExpression")
133
+ return undefined;
134
+ for (const p of n["properties"]) {
135
+ if (p.type !== "ObjectProperty")
136
+ continue;
137
+ const k = p["key"];
138
+ const name = k.type === "Identifier" ? k["name"] : jsString(k);
139
+ if (name === key)
140
+ return p["value"];
141
+ }
142
+ return undefined;
143
+ }
144
+ export function isJsTrue(node) {
145
+ const n = unwrap(node);
146
+ return n?.type === "BooleanLiteral" && n["value"] === true;
147
+ }
148
+ export function isJsFalse(node) {
149
+ const n = unwrap(node);
150
+ return n?.type === "BooleanLiteral" && n["value"] === false;
151
+ }
152
+ /** Identifier and property names used in an expression (including string keys like obj["password"]). */
153
+ export function jsIdentifiers(node) {
154
+ const out = [];
155
+ for (const n of walkJs(node)) {
156
+ if (n.type === "Identifier")
157
+ out.push(n["name"]);
158
+ else if ((n.type === "MemberExpression" || n.type === "OptionalMemberExpression") && n["computed"]) {
159
+ const key = jsString(n["property"]);
160
+ if (key)
161
+ out.push(key);
162
+ }
163
+ }
164
+ return out;
165
+ }
166
+ //# sourceMappingURL=ast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast.js","sourceRoot":"","sources":["../../../src/code/javascript/ast.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export * from "./ast.js";
2
+ export * from "./module.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/code/javascript/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC"}
@@ -0,0 +1,3 @@
1
+ export * from "./ast.js";
2
+ export * from "./module.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/code/javascript/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC"}
@@ -0,0 +1,59 @@
1
+ import { type JsNode } from "./ast.js";
2
+ export interface JsFunctionScope {
3
+ /** Names holding client-controlled data (request data and values derived from it). */
4
+ tainted: Set<string>;
5
+ /** Names assigned a dynamically built string (template literal with placeholders, + concatenation). */
6
+ dynamicStrings: Set<string>;
7
+ /** Qualified names of every call made in the function. */
8
+ calls: Set<string>;
9
+ }
10
+ export interface JsCallSite {
11
+ module: JsModule;
12
+ node: JsNode;
13
+ /** Qualified dotted callee with imports resolved, e.g. "child_process.exec", "crypto.createHash". */
14
+ name: string | undefined;
15
+ /** Last segment: method or function name. */
16
+ method: string | undefined;
17
+ /** Innermost enclosing function, if any. */
18
+ fn: JsNode | undefined;
19
+ /** True for `new X(...)`. */
20
+ isNew: boolean;
21
+ }
22
+ export declare class JsModule {
23
+ readonly path: string;
24
+ readonly tree: JsNode;
25
+ readonly lines: string[];
26
+ /** Local name -> module or "module.export", from import statements and require() calls. */
27
+ readonly imports: Map<string, string>;
28
+ private readonly scopes;
29
+ constructor(path: string, tree: JsNode, source: string);
30
+ /** "m" for require("m"), "m.y" for require("m").y; undefined otherwise. */
31
+ private requiredModule;
32
+ /** Resolves the first segment of a dotted name through this file's imports. */
33
+ qualify(name: string | undefined): string | undefined;
34
+ line(n: number | undefined): string;
35
+ lineOf(node: JsNode): number;
36
+ /** Exact source text of a node. */
37
+ text(node: JsNode): string;
38
+ /** True when the expression contains client-controlled data, given the scope's tainted names. */
39
+ isRequestDerived(node: unknown, scope?: JsFunctionScope): boolean;
40
+ /** Lightweight intra-procedural taint: request data and names assigned from it. */
41
+ scope(fn: JsNode | undefined): JsFunctionScope | undefined;
42
+ }
43
+ export declare class JsIndex {
44
+ readonly modules: JsModule[];
45
+ readonly parseErrors: {
46
+ file: string;
47
+ error: string;
48
+ }[];
49
+ private callSites?;
50
+ constructor(modules: JsModule[], parseErrors: {
51
+ file: string;
52
+ error: string;
53
+ }[]);
54
+ /** Every call and `new` expression with its resolved name and enclosing function. Computed once. */
55
+ calls(): JsCallSite[];
56
+ /** Whether any module imports the given package (or a subpath of it). */
57
+ imports(pkg: string): boolean;
58
+ }
59
+ //# sourceMappingURL=module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../src/code/javascript/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiF,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAMtH,MAAM,WAAW,eAAe;IAC9B,sFAAsF;IACtF,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,uGAAuG;IACvG,cAAc,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5B,0DAA0D;IAC1D,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,QAAQ,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,qGAAqG;IACrG,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,4CAA4C;IAC5C,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,6BAA6B;IAC7B,KAAK,EAAE,OAAO,CAAC;CAChB;AAgDD,qBAAa,QAAQ;IAOjB,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM;IAPvB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IACzB,2FAA2F;IAC3F,QAAQ,CAAC,OAAO,sBAA6B;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0C;IAEjE,YACW,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EAmCf;IAED,2EAA2E;IAC3E,OAAO,CAAC,cAAc;IActB,+EAA+E;IAC/E,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAKpD;IAED,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAElC;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3B;IAED,mCAAmC;IACnC,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CASzB;IAED,iGAAiG;IACjG,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,eAAe,GAAG,OAAO,CAOhE;IAED,mFAAmF;IACnF,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,CA8BzD;CACF;AAED,qBAAa,OAAO;IAIhB,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE;IAC5B,QAAQ,CAAC,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE;IAJzD,OAAO,CAAC,SAAS,CAAC,CAAe;IAEjC,YACW,OAAO,EAAE,QAAQ,EAAE,EACnB,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,EACrD;IAEJ,oGAAoG;IACpG,KAAK,IAAI,UAAU,EAAE,CA6BpB;IAED,yEAAyE;IACzE,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE5B;CACF"}