blitzstrike 1.0.34 → 1.0.38

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 (72) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/bench/corpus/java-cmd-vuln.md +8 -0
  3. package/bench/corpus/java-deser-vuln.md +8 -0
  4. package/bench/corpus/java-sqli-prep.md +9 -0
  5. package/bench/corpus/java-sqli-vuln.md +9 -0
  6. package/bench/corpus/java-ssrf-vuln.md +9 -0
  7. package/bench/corpus/java-xss-vuln.md +8 -0
  8. package/bench/corpus/java-xxe-vuln.md +10 -0
  9. package/bench/corpus/js-cmd-spawn.md +8 -0
  10. package/bench/corpus/js-cmd-vuln.md +8 -0
  11. package/bench/corpus/js-eval-vuln.md +8 -0
  12. package/bench/corpus/js-pathtraversal-vuln.md +8 -0
  13. package/bench/corpus/js-redirect-vuln.md +8 -0
  14. package/bench/corpus/js-sqli-param.md +8 -0
  15. package/bench/corpus/js-ssrf-vuln.md +8 -0
  16. package/bench/corpus/{js-xss-sanitized.md → js-xss-escape.md} +1 -1
  17. package/bench/corpus/js-xss-vuln.md +8 -0
  18. package/bench/corpus/php-cmd-authgated.md +8 -0
  19. package/bench/corpus/php-cmd-byref.md +11 -0
  20. package/bench/corpus/php-cmd-escaped.md +9 -0
  21. package/bench/corpus/php-cmd-escapeshellcmd.md +9 -0
  22. package/bench/corpus/php-cmd-intval.md +9 -0
  23. package/bench/corpus/php-cmd-passthru.md +9 -0
  24. package/bench/corpus/php-cmd-shell-exec.md +9 -0
  25. package/bench/corpus/php-cmd-transitive.md +10 -0
  26. package/bench/corpus/{php-command-injection-vuln.md → php-cmd-vuln.md} +1 -1
  27. package/bench/corpus/php-codeexec-assert.md +9 -0
  28. package/bench/corpus/php-codeexec-vuln.md +9 -0
  29. package/bench/corpus/php-fileupload-name.md +9 -0
  30. package/bench/corpus/php-fileupload-sanitized.md +9 -0
  31. package/bench/corpus/php-fileupload-vuln.md +9 -0
  32. package/bench/corpus/php-filewrite-vuln.md +9 -0
  33. package/bench/corpus/php-include-intval.md +9 -0
  34. package/bench/corpus/php-include-require.md +9 -0
  35. package/bench/corpus/php-include-vuln.md +9 -0
  36. package/bench/corpus/php-include-whitelist.md +10 -0
  37. package/bench/corpus/php-redirect-safe.md +9 -0
  38. package/bench/corpus/php-redirect-vuln.md +9 -0
  39. package/bench/corpus/php-sqli-authgated.md +9 -0
  40. package/bench/corpus/php-sqli-esc.md +9 -0
  41. package/bench/corpus/php-sqli-filter.md +9 -0
  42. package/bench/corpus/php-sqli-getvar.md +9 -0
  43. package/bench/corpus/php-sqli-interproc.md +10 -0
  44. package/bench/corpus/php-sqli-whereraw.md +9 -0
  45. package/bench/corpus/php-ssrf-curl.md +11 -0
  46. package/bench/corpus/php-ssrf-vuln.md +9 -0
  47. package/bench/corpus/php-ssrf-wpremote.md +9 -0
  48. package/bench/corpus/php-unserialize-vuln.md +9 -0
  49. package/bench/corpus/php-xss-attr.md +9 -0
  50. package/bench/corpus/php-xss-authgated.md +8 -0
  51. package/bench/corpus/php-xss-eschtml.md +9 -0
  52. package/bench/corpus/php-xss-htmlentities.md +9 -0
  53. package/bench/corpus/php-xss-return.md +9 -0
  54. package/bench/corpus/php-xss-ternary.md +9 -0
  55. package/bench/corpus/php-xss-vuln.md +9 -0
  56. package/bench/corpus/php-xxe-vuln.md +9 -0
  57. package/bench/corpus/php-zipslip-vuln.md +10 -0
  58. package/bench/corpus/py-cmd-subprocess.md +9 -0
  59. package/bench/corpus/{py-command-injection-vuln.md → py-cmd-vuln.md} +3 -3
  60. package/bench/corpus/py-deser-json.md +9 -0
  61. package/bench/corpus/py-deser-vuln.md +9 -0
  62. package/bench/corpus/py-eval-vuln.md +8 -0
  63. package/bench/corpus/py-pathtraversal-vuln.md +8 -0
  64. package/bench/corpus/py-sqli-param.md +9 -0
  65. package/bench/corpus/py-sqli-vuln.md +9 -0
  66. package/bench/corpus/py-ssrf-vuln.md +9 -0
  67. package/bench/corpus/py-xss-vuln.md +8 -0
  68. package/dist/index.js +1124 -86
  69. package/package.json +1 -1
  70. package/bench/corpus/java-command-injection-vuln.md +0 -7
  71. package/bench/corpus/php-file-upload-vuln.md +0 -9
  72. package/bench/corpus/py-command-injection-sanitized.md +0 -9
package/dist/index.js CHANGED
@@ -14820,8 +14820,8 @@ var require_src = __commonJS(function(exports, module) {
14820
14820
  });
14821
14821
 
14822
14822
  // src/sync.ts
14823
- import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3, readFileSync as readFileSync12, readdirSync as readdirSync5, statSync as statSync3, rmSync as rmSync2 } from "node:fs";
14824
- import { join as join10 } from "node:path";
14823
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4, readFileSync as readFileSync15, readdirSync as readdirSync5, statSync as statSync3, rmSync as rmSync3 } from "node:fs";
14824
+ import { join as join11 } from "node:path";
14825
14825
  import { homedir as homedir4 } from "node:os";
14826
14826
  import { fileURLToPath as fileURLToPath7 } from "node:url";
14827
14827
  import { spawnSync as spawnSync2 } from "node:child_process";
@@ -14838,7 +14838,7 @@ function countFiles(dir) {
14838
14838
  const walk = (d) => {
14839
14839
  for (const e of readdirSync5(d, { withFileTypes: true })) {
14840
14840
  if (e.isDirectory())
14841
- walk(join10(d, e.name));
14841
+ walk(join11(d, e.name));
14842
14842
  else
14843
14843
  n++;
14844
14844
  }
@@ -14852,8 +14852,8 @@ function countFiles(dir) {
14852
14852
  function syncData() {
14853
14853
  if (!dirExists(DATA_ROOT2))
14854
14854
  mkdirSync3(DATA_ROOT2, { recursive: true });
14855
- const payloadsPath = join10(DATA_ROOT2, "payloads");
14856
- const templatesPath = join10(DATA_ROOT2, "templates");
14855
+ const payloadsPath = join11(DATA_ROOT2, "payloads");
14856
+ const templatesPath = join11(DATA_ROOT2, "templates");
14857
14857
  const hasPayloads = dirExists(payloadsPath) && countFiles(payloadsPath) > 0;
14858
14858
  const hasTemplates = dirExists(templatesPath) && countFiles(templatesPath) > 0;
14859
14859
  if (hasPayloads && hasTemplates) {
@@ -14863,8 +14863,8 @@ function syncData() {
14863
14863
  data_root: DATA_ROOT2
14864
14864
  };
14865
14865
  }
14866
- const localPayloads = join10(ROOT5, "payloads");
14867
- const localTemplates = join10(ROOT5, "templates");
14866
+ const localPayloads = join11(ROOT5, "payloads");
14867
+ const localTemplates = join11(ROOT5, "templates");
14868
14868
  let payloadsSynced = false;
14869
14869
  let templatesSynced = false;
14870
14870
  if (!hasPayloads && dirExists(localPayloads)) {
@@ -14877,23 +14877,23 @@ function syncData() {
14877
14877
  }
14878
14878
  const gitOk = spawnSync2("git", ["--version"]).status === 0;
14879
14879
  if (gitOk && (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0 || !dirExists(templatesPath) || countFiles(templatesPath) === 0)) {
14880
- const tmp = join10(DATA_ROOT2, ".tmp-clone");
14880
+ const tmp = join11(DATA_ROOT2, ".tmp-clone");
14881
14881
  if (dirExists(tmp))
14882
- rmSync2(tmp, { recursive: true, force: true });
14882
+ rmSync3(tmp, { recursive: true, force: true });
14883
14883
  const r = spawnSync2("git", ["clone", "--depth", "1", "--filter=blob:none", "--sparse", GITHUB_REPO, tmp], { timeout: 120000 });
14884
14884
  if (r.status === 0) {
14885
14885
  const sparse = spawnSync2("git", ["-C", tmp, "sparse-checkout", "set", "payloads", "templates"], { timeout: 120000 });
14886
14886
  if (sparse.status === 0) {
14887
14887
  if (!dirExists(payloadsPath) || countFiles(payloadsPath) === 0) {
14888
- copyDir(join10(tmp, "payloads"), payloadsPath);
14888
+ copyDir(join11(tmp, "payloads"), payloadsPath);
14889
14889
  payloadsSynced = true;
14890
14890
  }
14891
14891
  if (!dirExists(templatesPath) || countFiles(templatesPath) === 0) {
14892
- copyDir(join10(tmp, "templates"), templatesPath);
14892
+ copyDir(join11(tmp, "templates"), templatesPath);
14893
14893
  templatesSynced = true;
14894
14894
  }
14895
14895
  }
14896
- rmSync2(tmp, { recursive: true, force: true });
14896
+ rmSync3(tmp, { recursive: true, force: true });
14897
14897
  }
14898
14898
  }
14899
14899
  return {
@@ -14911,18 +14911,18 @@ function copyDir(src, dst) {
14911
14911
  function manualCopy(src, dst) {
14912
14912
  mkdirSync3(dst, { recursive: true });
14913
14913
  for (const e of readdirSync5(src, { withFileTypes: true })) {
14914
- const s = join10(src, e.name);
14915
- const d = join10(dst, e.name);
14914
+ const s = join11(src, e.name);
14915
+ const d = join11(dst, e.name);
14916
14916
  if (e.isDirectory())
14917
14917
  manualCopy(s, d);
14918
14918
  else
14919
- writeFileSync3(d, readFileSync12(s));
14919
+ writeFileSync4(d, readFileSync15(s));
14920
14920
  }
14921
14921
  }
14922
14922
  var ROOT5, DATA_ROOT2, GITHUB_REPO = "https://github.com/shinthink/blitzstrike.git";
14923
14923
  var init_sync = __esm(() => {
14924
- ROOT5 = join10(fileURLToPath7(new URL(".", import.meta.url)), "..");
14925
- DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join10(homedir4(), ".blitzstrike", "data");
14924
+ ROOT5 = join11(fileURLToPath7(new URL(".", import.meta.url)), "..");
14925
+ DATA_ROOT2 = process.env.BLITZSTRIKE_DATA ?? join11(homedir4(), ".blitzstrike", "data");
14926
14926
  });
14927
14927
 
14928
14928
  // src/update.ts
@@ -31067,16 +31067,16 @@ function classifySource(line) {
31067
31067
  }
31068
31068
  var SINK_CLASS_MAP = [
31069
31069
  [/->query\(|\$wpdb->query|\$wpdb->get_var|\$wpdb->get_results|->whereRaw|->selectRaw/, { id: "sql_execution", category: "SQL execution", cwe: "CWE-89" }],
31070
- [/eval\(|assert\(|create_function\(|call_user_func\(|preg_replace\(/, { id: "code_execution", category: "Dynamic evaluation / code execution", cwe: "CWE-94" }],
31071
- [/system\(|exec\(|shell_exec\(|passthru\(|proc_open\(|popen\(/, { id: "command_execution", category: "Command execution", cwe: "CWE-78" }],
31072
- [/move_uploaded_file\(|file_put_contents\(|fwrite\(|fopen\(|unlink\(/, { id: "file_operations", category: "File operations", cwe: "CWE-434" }],
31073
- [/include\(|require\(|include_once\(|require_once\(/, { id: "file_inclusion", category: "File inclusion", cwe: "CWE-98" }],
31074
- [/unserialize\(|maybe_unserialize\(/, { id: "deserialization", category: "Deserialization", cwe: "CWE-502" }],
31075
- [/wp_remote_get\(|wp_remote_post\(|file_get_contents\(|curl_exec\(/, { id: "http_request", category: "HTTP request (SSRF)", cwe: "CWE-918" }],
31076
- [/header\(|wp_redirect\(|wp_safe_redirect\(/, { id: "redirect", category: "Redirect handling", cwe: "CWE-601" }],
31077
- [/echo\s|print\s|printf\(/, { id: "html_render", category: "HTML rendering (XSS)", cwe: "CWE-79" }],
31078
- [/simplexml_load_string\(|new SimpleXMLElement|DOMDocument/, { id: "xml_processing", category: "XML processing (XXE)", cwe: "CWE-611" }],
31079
- [/ZipArchive|PharData|->extractTo\(/, { id: "archive_extraction", category: "Archive extraction (zip slip)", cwe: "CWE-22" }]
31070
+ [/\beval\(|\bassert\(|\bcreate_function\(|\bcall_user_func\(|\bpreg_replace\(/, { id: "code_execution", category: "Dynamic evaluation / code execution", cwe: "CWE-94" }],
31071
+ [/\bsystem\(|\bexec\(|\bshell_exec\(|\bpassthru\(|\bproc_open\(|\bpopen\(/, { id: "command_execution", category: "Command execution", cwe: "CWE-78" }],
31072
+ [/\bmove_uploaded_file\(|\bfile_put_contents\(|\bfwrite\(|\bfopen\(|\bunlink\(/, { id: "file_operations", category: "File operations", cwe: "CWE-434" }],
31073
+ [/\binclude\(|\brequire\(|\binclude_once\(|\brequire_once\(/, { id: "file_inclusion", category: "File inclusion", cwe: "CWE-98" }],
31074
+ [/\bunserialize\(|\bmaybe_unserialize\(/, { id: "deserialization", category: "Deserialization", cwe: "CWE-502" }],
31075
+ [/\bwp_remote_get\(|\bwp_remote_post\(|\bfile_get_contents\(|\bcurl_exec\(|\bcurl_setopt\(/, { id: "http_request", category: "HTTP request (SSRF)", cwe: "CWE-918" }],
31076
+ [/\bheader\(|\bwp_redirect\(/, { id: "redirect", category: "Redirect handling", cwe: "CWE-601" }],
31077
+ [/echo\s|print\s|\bprintf\(/, { id: "html_render", category: "HTML rendering (XSS)", cwe: "CWE-79" }],
31078
+ [/\bsimplexml_load_string\(|new SimpleXMLElement|DOMDocument/, { id: "xml_processing", category: "XML processing (XXE)", cwe: "CWE-611" }],
31079
+ [/\bZipArchive|\bPharData|->extractTo\(/, { id: "archive_extraction", category: "Archive extraction (zip slip)", cwe: "CWE-22" }]
31080
31080
  ];
31081
31081
  function classifySink2(sink) {
31082
31082
  for (const [re, cls] of SINK_CLASS_MAP) {
@@ -31593,6 +31593,775 @@ function taintTree(root, maxFiles = 2000) {
31593
31593
  return files.map((f) => analyzeTaint(f));
31594
31594
  }
31595
31595
 
31596
+ // src/eagle2.ts
31597
+ var import_php_parser3 = __toESM(require_src(), 1);
31598
+ import { readFileSync as readFileSync12 } from "node:fs";
31599
+ init_scanner();
31600
+
31601
+ // src/callgraph.ts
31602
+ var import_php_parser2 = __toESM(require_src(), 1);
31603
+ import { readFileSync as readFileSync11 } from "node:fs";
31604
+ var parser2 = new import_php_parser2.Engine({
31605
+ parser: { extractDoc: false, php7: true },
31606
+ ast: { withPositions: true, withSource: false }
31607
+ });
31608
+ function isNode2(v) {
31609
+ return !!v && typeof v === "object" && typeof v.kind === "string";
31610
+ }
31611
+ function children2(node) {
31612
+ const out = [];
31613
+ for (const k of Object.keys(node)) {
31614
+ if (k === "loc")
31615
+ continue;
31616
+ const v = node[k];
31617
+ if (Array.isArray(v)) {
31618
+ for (const c of v)
31619
+ if (isNode2(c))
31620
+ out.push(c);
31621
+ } else if (isNode2(v)) {
31622
+ out.push(v);
31623
+ }
31624
+ }
31625
+ return out;
31626
+ }
31627
+ function nameOf(node) {
31628
+ if (!isNode2(node))
31629
+ return null;
31630
+ if (typeof node.name === "string")
31631
+ return node.name;
31632
+ if (isNode2(node.name))
31633
+ return nameOf(node.name);
31634
+ return null;
31635
+ }
31636
+ function nodeId(kind, name, cls) {
31637
+ if (kind === "function")
31638
+ return `func:${name}`;
31639
+ if (kind === "method")
31640
+ return `method:${cls ?? "?"}::${name}`;
31641
+ return "main";
31642
+ }
31643
+ function ensureNode(g, id, name, kind, file, line, cls) {
31644
+ let n = g.nodes.get(id);
31645
+ if (!n) {
31646
+ n = { id, name, kind, class: cls, file, line, callees: new Set, callers: new Set };
31647
+ g.nodes.set(id, n);
31648
+ }
31649
+ return n;
31650
+ }
31651
+ function addEdge(g, caller, callee, name, line, file) {
31652
+ g.edges.push({ caller, callee, name, line, file });
31653
+ const c = g.nodes.get(caller);
31654
+ const t = g.nodes.get(callee);
31655
+ if (c)
31656
+ c.callees.add(callee);
31657
+ if (t)
31658
+ t.callers.add(caller);
31659
+ }
31660
+ function buildCallGraph(path) {
31661
+ const g = { nodes: new Map, edges: [] };
31662
+ let code;
31663
+ try {
31664
+ code = readFileSync11(path, "utf8");
31665
+ } catch {
31666
+ return g;
31667
+ }
31668
+ let ast;
31669
+ try {
31670
+ ast = parser2.parseCode(code, path);
31671
+ } catch {
31672
+ return g;
31673
+ }
31674
+ const mainId = nodeId("main", "main");
31675
+ ensureNode(g, mainId, "<main>", "main", path, 0);
31676
+ const funcs = [];
31677
+ const methods = [];
31678
+ walk(ast, path, (n, ctx) => {
31679
+ if (n.kind === "function") {
31680
+ const name = nameOf(n.name);
31681
+ if (name)
31682
+ funcs.push({ name, node: n });
31683
+ } else if (n.kind === "method" && ctx.className) {
31684
+ const mname = nameOf(n.name);
31685
+ if (mname)
31686
+ methods.push({ cls: ctx.className, name: mname, node: n });
31687
+ }
31688
+ });
31689
+ for (const f of funcs) {
31690
+ const id = nodeId("function", f.name);
31691
+ ensureNode(g, id, f.name, "function", path, f.node.loc?.start?.line ?? 0);
31692
+ }
31693
+ for (const m of methods) {
31694
+ const id = nodeId("method", m.name, m.cls);
31695
+ ensureNode(g, id, m.name, "method", path, m.node.loc?.start?.line ?? 0, m.cls);
31696
+ }
31697
+ walk(ast, path, (n, ctx) => {
31698
+ if (n.kind !== "call")
31699
+ return;
31700
+ const line = n.loc?.start?.line ?? 0;
31701
+ const callerId = ctx.enclosing ?? mainId;
31702
+ resolveCall(g, n, callerId, ctx, path, line);
31703
+ });
31704
+ return g;
31705
+ }
31706
+ function walk(node, file, visit, ctx = {}) {
31707
+ if (!isNode2(node))
31708
+ return;
31709
+ let childCtx = ctx;
31710
+ if (node.kind === "class") {
31711
+ childCtx = { ...ctx, className: nameOf(node.name) ?? undefined };
31712
+ } else if (node.kind === "function") {
31713
+ const name = nameOf(node.name);
31714
+ childCtx = { ...ctx, enclosing: name ? nodeId("function", name) : ctx.enclosing };
31715
+ } else if (node.kind === "method") {
31716
+ const name = nameOf(node.name);
31717
+ childCtx = { ...ctx, enclosing: name ? nodeId("method", name, ctx.className) : ctx.enclosing };
31718
+ }
31719
+ visit(node, ctx);
31720
+ for (const c of children2(node))
31721
+ walk(c, file, visit, childCtx);
31722
+ }
31723
+ function resolveCall(g, call, callerId, ctx, file, line) {
31724
+ const what = call.what;
31725
+ if (!isNode2(what))
31726
+ return;
31727
+ if (what.kind === "name") {
31728
+ const fn = nameOf(what);
31729
+ if (!fn)
31730
+ return;
31731
+ const id = nodeId("function", fn);
31732
+ if (g.nodes.has(id)) {
31733
+ addEdge(g, callerId, id, fn, line, file);
31734
+ } else {
31735
+ addEdge(g, callerId, `unknown:${fn}`, fn, line, file);
31736
+ }
31737
+ return;
31738
+ }
31739
+ if (what.kind === "staticlookup") {
31740
+ const base = what.what;
31741
+ const baseName = nameOf(base) ?? (isNode2(base) && base.kind === "variable" ? base.name : null);
31742
+ const method = nameOf(what.offset);
31743
+ if (!method)
31744
+ return;
31745
+ let cls = baseName;
31746
+ if (cls === "self" || cls === "static")
31747
+ cls = ctx.className ?? "?";
31748
+ if (cls && cls !== "?") {
31749
+ const id = nodeId("method", method, cls);
31750
+ if (g.nodes.has(id))
31751
+ addEdge(g, callerId, id, method, line, file);
31752
+ }
31753
+ return;
31754
+ }
31755
+ if (what.kind === "propertylookup") {
31756
+ const base = what.what;
31757
+ const method = nameOf(what.offset);
31758
+ if (!method)
31759
+ return;
31760
+ if (isNode2(base) && base.kind === "variable" && base.name === "this") {
31761
+ if (ctx.className) {
31762
+ const id = nodeId("method", method, ctx.className);
31763
+ if (g.nodes.has(id))
31764
+ addEdge(g, callerId, id, method, line, file);
31765
+ }
31766
+ return;
31767
+ }
31768
+ let matched = false;
31769
+ for (const [id, n] of g.nodes) {
31770
+ if (n.kind === "method" && n.name === method) {
31771
+ addEdge(g, callerId, id, method, line, file);
31772
+ matched = true;
31773
+ }
31774
+ }
31775
+ if (!matched)
31776
+ addEdge(g, callerId, `unknown:${method}`, method, line, file);
31777
+ return;
31778
+ }
31779
+ }
31780
+ function reachableFrom(g, entry) {
31781
+ const seen = new Set;
31782
+ const stack = [entry];
31783
+ while (stack.length) {
31784
+ const cur = stack.pop();
31785
+ if (seen.has(cur))
31786
+ continue;
31787
+ seen.add(cur);
31788
+ const n = g.nodes.get(cur);
31789
+ if (!n)
31790
+ continue;
31791
+ for (const c of n.callees)
31792
+ stack.push(c);
31793
+ }
31794
+ return seen;
31795
+ }
31796
+ function entryPoints(g) {
31797
+ const entries = [];
31798
+ for (const [id, n] of g.nodes) {
31799
+ if (n.callers.size === 0)
31800
+ entries.push(id);
31801
+ }
31802
+ return entries;
31803
+ }
31804
+
31805
+ // src/eagle2.ts
31806
+ var parser3 = new import_php_parser3.Engine({
31807
+ parser: { extractDoc: false, php7: true },
31808
+ ast: { withPositions: true, withSource: false }
31809
+ });
31810
+ function isNode3(v) {
31811
+ return !!v && typeof v === "object" && typeof v.kind === "string";
31812
+ }
31813
+ function children3(node) {
31814
+ const out = [];
31815
+ for (const k of Object.keys(node)) {
31816
+ if (k === "loc")
31817
+ continue;
31818
+ const v = node[k];
31819
+ if (Array.isArray(v)) {
31820
+ for (const c of v)
31821
+ if (isNode3(c))
31822
+ out.push(c);
31823
+ } else if (isNode3(v)) {
31824
+ out.push(v);
31825
+ }
31826
+ }
31827
+ return out;
31828
+ }
31829
+ function findKind2(node, kind, out = []) {
31830
+ if (!isNode3(node))
31831
+ return out;
31832
+ if (node.kind === kind)
31833
+ out.push(node);
31834
+ for (const c of children3(node))
31835
+ findKind2(c, kind, out);
31836
+ return out;
31837
+ }
31838
+ function nameOf2(node) {
31839
+ if (!isNode3(node))
31840
+ return null;
31841
+ if (typeof node.name === "string")
31842
+ return node.name;
31843
+ if (isNode3(node.name))
31844
+ return nameOf2(node.name);
31845
+ return null;
31846
+ }
31847
+ function rootVarName2(node) {
31848
+ if (!isNode3(node))
31849
+ return null;
31850
+ if (node.kind === "variable")
31851
+ return node.name ?? null;
31852
+ if (node.kind === "name")
31853
+ return typeof node.name === "string" ? node.name : node.name?.name ?? null;
31854
+ if (node.kind === "offsetlookup" || node.kind === "propertylookup")
31855
+ return rootVarName2(node.what);
31856
+ return null;
31857
+ }
31858
+ function sourceOf2(node) {
31859
+ if (!isNode3(node))
31860
+ return null;
31861
+ if (node.kind === "offsetlookup" && node.what?.kind === "variable") {
31862
+ const n = node.what.name;
31863
+ if (["_GET", "_POST", "_REQUEST", "_COOKIE", "_FILES", "_SERVER"].includes(n))
31864
+ return "$" + n;
31865
+ }
31866
+ if (node.kind === "variable") {
31867
+ const n = node.name;
31868
+ if (["_GET", "_POST", "_REQUEST", "_COOKIE", "_FILES", "_SERVER"].includes(n))
31869
+ return "$" + n;
31870
+ }
31871
+ if (node.kind === "call") {
31872
+ const n = rootVarName2(node.what);
31873
+ if (n === "getallheaders")
31874
+ return "getallheaders";
31875
+ if (n === "file_get_contents" && JSON.stringify(node).includes("php://input"))
31876
+ return "php://input";
31877
+ }
31878
+ return null;
31879
+ }
31880
+ function sinkClassOf2(call) {
31881
+ const what = call.what;
31882
+ if (!isNode3(what))
31883
+ return null;
31884
+ let token = "";
31885
+ if (what.kind === "propertylookup") {
31886
+ const baseNode = what.what;
31887
+ const base = rootVarName2(baseNode);
31888
+ const method = what.offset?.name ?? what.offset?.value;
31889
+ const baseStr = isNode3(baseNode) && (baseNode.kind === "variable" || baseNode.kind === "offsetlookup") ? `$${base}` : base;
31890
+ token = `${baseStr}->${method}(`;
31891
+ } else if (what.kind === "name") {
31892
+ token = `${what.name}(`;
31893
+ }
31894
+ if (!token)
31895
+ return null;
31896
+ const cls = classifySink2(token) ?? classifySink2(what.name ?? "");
31897
+ if (!cls)
31898
+ return null;
31899
+ return { token, cls };
31900
+ }
31901
+ var CLEAN = { tainted: false, sources: [], sanitizers: [] };
31902
+ function mergeTaint(...states) {
31903
+ const taintedStates = states.filter((s) => s.tainted);
31904
+ if (taintedStates.length === 0)
31905
+ return CLEAN;
31906
+ const sources = [...new Set(taintedStates.flatMap((s) => s.sources))];
31907
+ let sanitizers = taintedStates[0].sanitizers;
31908
+ for (const s of taintedStates.slice(1)) {
31909
+ sanitizers = sanitizers.filter((san) => s.sanitizers.some((x) => x.id === san.id));
31910
+ }
31911
+ return {
31912
+ tainted: true,
31913
+ sources,
31914
+ sanitizers,
31915
+ sourceLine: taintedStates.find((s) => s.sourceLine !== undefined)?.sourceLine
31916
+ };
31917
+ }
31918
+ function summarizeFunction(fn, id, name, summaries) {
31919
+ const params = (fn.arguments ?? []).map((a) => nameOf2(a) ?? "?");
31920
+ const byrefParams = new Set;
31921
+ (fn.arguments ?? []).forEach((a, i) => {
31922
+ if (a.byref === true)
31923
+ byrefParams.add(params[i]);
31924
+ });
31925
+ const summary = { id, name, params, byrefParams, paramSinks: new Map, paramReturns: new Set, paramCalls: new Map, paramWrites: new Map };
31926
+ const bodyStmts = fn.body?.kind === "block" ? fn.body.children ?? [] : [fn.body];
31927
+ for (const p of params) {
31928
+ const env = new Map;
31929
+ for (const q of params)
31930
+ env.set(q, CLEAN);
31931
+ env.set(p, { tainted: true, sources: [`arg:${p}`], sanitizers: [] });
31932
+ const ctx = { sinks: [], returnsTainted: false, calls: [] };
31933
+ analyzeBody(bodyStmts, env, summary, ctx, p, new Map, [], summaries);
31934
+ summary.paramSinks.set(p, ctx.sinks);
31935
+ if (ctx.returnsTainted)
31936
+ summary.paramReturns.add(p);
31937
+ summary.paramCalls.set(p, ctx.calls);
31938
+ if (byrefParams.has(p)) {
31939
+ const finalTaint = env.get(p);
31940
+ const written = finalTaint?.sources.filter((s) => !s.startsWith("arg:")) ?? [];
31941
+ if (written.length > 0)
31942
+ summary.paramWrites.set(p, written);
31943
+ }
31944
+ }
31945
+ return summary;
31946
+ }
31947
+ function analyzeBody(statements, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating = false) {
31948
+ for (const stmt of statements) {
31949
+ if (!isNode3(stmt))
31950
+ continue;
31951
+ const kind = stmt.kind;
31952
+ if (kind === "expressionstatement") {
31953
+ analyzeExpr(stmt.expression, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
31954
+ } else if (kind === "if") {
31955
+ const condGates = authGatesOf(stmt.test);
31956
+ const branchAuth = [...activeAuth, ...condGates];
31957
+ const condValidating = validationGatesOf(stmt.test);
31958
+ const thenStmts = stmt.body?.kind === "block" ? stmt.body.children ?? [] : [stmt.body];
31959
+ const thenEnv = cloneEnv(env);
31960
+ const thenCtx = { sinks: [], returnsTainted: false, calls: [] };
31961
+ analyzeBody(thenStmts, thenEnv, summary, thenCtx, taintedParam, cloneProps(props), branchAuth, summaries, validating || condValidating);
31962
+ mergeCtx(ctx, thenCtx);
31963
+ if (stmt.alternate) {
31964
+ const altStmts = stmt.alternate.kind === "block" ? stmt.alternate.children ?? [] : [stmt.alternate];
31965
+ const altEnv = cloneEnv(env);
31966
+ const altCtx = { sinks: [], returnsTainted: false, calls: [] };
31967
+ analyzeBody(altStmts, altEnv, summary, altCtx, taintedParam, cloneProps(props), activeAuth, summaries, validating);
31968
+ mergeCtx(ctx, altCtx);
31969
+ for (const [k, v] of thenEnv) {
31970
+ const alt = altEnv.get(k);
31971
+ env.set(k, alt ? mergeTaint(v, alt) : v);
31972
+ }
31973
+ } else {
31974
+ for (const [k, v] of thenEnv)
31975
+ env.set(k, v);
31976
+ }
31977
+ } else if (kind === "block") {
31978
+ analyzeBody(stmt.children ?? [], env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
31979
+ } else if (kind === "return") {
31980
+ const t = analyzeExpr(stmt.expr, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
31981
+ if (t.tainted)
31982
+ ctx.returnsTainted = true;
31983
+ } else if (kind === "echo" || kind === "print") {
31984
+ analyzeExpr(stmt, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
31985
+ } else {
31986
+ for (const c of children3(stmt)) {
31987
+ if (c.kind === "block" || c.kind === "if") {
31988
+ analyzeBody([c], env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
31989
+ } else {
31990
+ analyzeExpr(c, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
31991
+ }
31992
+ }
31993
+ }
31994
+ }
31995
+ }
31996
+ function analyzeExpr(node, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating = false) {
31997
+ if (!isNode3(node))
31998
+ return CLEAN;
31999
+ const src = sourceOf2(node);
32000
+ if (src)
32001
+ return { tainted: true, sources: [src], sanitizers: [], sourceLine: node.loc?.start?.line };
32002
+ if (node.kind === "assign") {
32003
+ const byref = node.operator === "=&";
32004
+ const rhs = analyzeExpr(node.right, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
32005
+ const lhs = node.left;
32006
+ if (isNode3(lhs) && lhs.kind === "variable") {
32007
+ const varName = lhs.name;
32008
+ if (byref) {
32009
+ const refVar = rootVarName2(node.right);
32010
+ if (refVar) {
32011
+ const refTaint = env.get(refVar) ?? rhs;
32012
+ env.set(varName, refTaint);
32013
+ env.set(refVar, refTaint);
32014
+ } else {
32015
+ env.set(varName, rhs);
32016
+ }
32017
+ } else {
32018
+ env.set(varName, rhs);
32019
+ }
32020
+ } else if (isNode3(lhs) && lhs.kind === "propertylookup") {
32021
+ const objName = rootVarName2(lhs.what);
32022
+ const propName = lhs.offset?.name ?? "?";
32023
+ if (objName) {
32024
+ let oprops = props.get(objName);
32025
+ if (!oprops) {
32026
+ oprops = new Map;
32027
+ props.set(objName, oprops);
32028
+ }
32029
+ oprops.set(propName, rhs);
32030
+ }
32031
+ }
32032
+ return rhs;
32033
+ }
32034
+ if (node.kind === "call") {
32035
+ const sink = sinkClassOf2(node);
32036
+ const argTaints = node.arguments.map((a) => analyzeExpr(a, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating));
32037
+ const taintedArgs = argTaints.filter((t) => t.tainted);
32038
+ if (sink) {
32039
+ if (taintedArgs.length > 0) {
32040
+ const san = [...taintedArgs.flatMap((t) => t.sanitizers), ...findSanitizers(JSON.stringify(node))];
32041
+ const sanitized = isSanitized(san, sink.cls.id);
32042
+ const gates = activeAuth;
32043
+ ctx.sinks.push({ sink: sink.token, line: node.loc?.start?.line ?? 0, sanitized, authGated: gates.length > 0, authGates: gates });
32044
+ }
32045
+ for (const a of node.arguments)
32046
+ analyzeExpr(a, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
32047
+ return taintedArgs.length > 0 ? mergeTaint(...taintedArgs) : CLEAN;
32048
+ }
32049
+ const fnName = rootVarName2(node.what);
32050
+ if (fnName) {
32051
+ const san = findSanitizers(fnName + "(");
32052
+ if (san.length > 0) {
32053
+ if (taintedArgs.length > 0) {
32054
+ return mergeTaint(...taintedArgs.map((t) => ({ ...t, sanitizers: [...t.sanitizers, ...san] })));
32055
+ }
32056
+ return CLEAN;
32057
+ }
32058
+ for (let i = 0;i < node.arguments.length; i++) {
32059
+ const argVar = rootVarName2(node.arguments[i]);
32060
+ if (argVar === taintedParam) {
32061
+ ctx.calls.push({ callee: fnName, argIndex: i, line: node.loc?.start?.line ?? 0 });
32062
+ }
32063
+ }
32064
+ const helperId = resolveFuncId(fnName, summaries);
32065
+ const helperSum = helperId ? summaries.get(helperId) : undefined;
32066
+ if (helperSum && taintedArgs.length > 0) {
32067
+ for (let i = 0;i < node.arguments.length; i++) {
32068
+ if (argTaints[i]?.tainted) {
32069
+ const paramName = helperSum.params[i];
32070
+ if (paramName && helperSum.paramReturns.has(paramName)) {
32071
+ return mergeTaint(...taintedArgs);
32072
+ }
32073
+ }
32074
+ }
32075
+ }
32076
+ if (helperSum && helperSum.paramWrites.size > 0) {
32077
+ for (let i = 0;i < node.arguments.length; i++) {
32078
+ const paramName = helperSum.params[i];
32079
+ if (!paramName || !helperSum.paramWrites.has(paramName))
32080
+ continue;
32081
+ const argVar = rootVarName2(node.arguments[i]);
32082
+ const written = helperSum.paramWrites.get(paramName);
32083
+ if (argVar) {
32084
+ env.set(argVar, { tainted: true, sources: written, sanitizers: [] });
32085
+ }
32086
+ }
32087
+ }
32088
+ }
32089
+ if (isNode3(node.what) && node.what.kind === "propertylookup") {
32090
+ analyzeExpr(node.what, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
32091
+ }
32092
+ return CLEAN;
32093
+ }
32094
+ if (node.kind === "variable") {
32095
+ const t = env.get(node.name);
32096
+ return t ? { ...t } : CLEAN;
32097
+ }
32098
+ if (node.kind === "offsetlookup") {
32099
+ const root = rootVarName2(node);
32100
+ if (root) {
32101
+ const t = env.get(root);
32102
+ if (t)
32103
+ return { ...t };
32104
+ }
32105
+ return analyzeExpr(node.what, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
32106
+ }
32107
+ if (node.kind === "propertylookup") {
32108
+ const objName = rootVarName2(node.what);
32109
+ const propName = node.offset?.name ?? "?";
32110
+ if (objName) {
32111
+ const pt = props.get(objName)?.get(propName);
32112
+ if (pt)
32113
+ return { ...pt };
32114
+ }
32115
+ return analyzeExpr(node.what, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
32116
+ }
32117
+ if (node.kind === "retif") {
32118
+ const t = analyzeExpr(node.trueExpr ?? node.test, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
32119
+ const f = node.falseExpr ? analyzeExpr(node.falseExpr, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating) : CLEAN;
32120
+ return mergeTaint(t, f);
32121
+ }
32122
+ if (node.kind === "bin" || node.kind === "concat" || node.kind === "encapsed") {
32123
+ const parts = children3(node);
32124
+ const taints = parts.map((p) => analyzeExpr(p, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating));
32125
+ return mergeTaint(...taints);
32126
+ }
32127
+ if (node.kind === "encapsedpart") {
32128
+ return analyzeExpr(node.expression, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
32129
+ }
32130
+ if (node.kind === "echo" || node.kind === "print") {
32131
+ const exprs = node.expressions ?? [node.expression];
32132
+ const cls = classifySink2(node.kind === "echo" ? "echo " : "print ");
32133
+ let ret = CLEAN;
32134
+ for (const e of exprs) {
32135
+ const t = analyzeExpr(e, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
32136
+ if (t.tainted && cls) {
32137
+ const san = [...t.sanitizers, ...findSanitizers(JSON.stringify(e))];
32138
+ ctx.sinks.push({ sink: node.kind + " ", line: node.loc?.start?.line ?? 0, sanitized: isSanitized(san, cls.id) || validating, authGated: activeAuth.length > 0, authGates: activeAuth });
32139
+ }
32140
+ ret = mergeTaint(ret, t);
32141
+ }
32142
+ return ret;
32143
+ }
32144
+ if (node.kind === "include") {
32145
+ const base = node.require ? "require" : "include";
32146
+ const suffix = node.once ? "_once" : "";
32147
+ const sinkToken = base + suffix + "(";
32148
+ const cls = classifySink2(sinkToken);
32149
+ const t = analyzeExpr(node.target, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
32150
+ if (t.tainted && cls) {
32151
+ const san = [...t.sanitizers, ...findSanitizers(JSON.stringify(node))];
32152
+ ctx.sinks.push({ sink: sinkToken, line: node.loc?.start?.line ?? 0, sanitized: isSanitized(san, cls.id) || validating, authGated: activeAuth.length > 0, authGates: activeAuth });
32153
+ }
32154
+ return t;
32155
+ }
32156
+ if (node.kind === "eval") {
32157
+ const cls = classifySink2("eval(");
32158
+ const t = analyzeExpr(node.source, env, summary, ctx, taintedParam, props, activeAuth, summaries, validating);
32159
+ if (t.tainted && cls) {
32160
+ ctx.sinks.push({ sink: "eval(", line: node.loc?.start?.line ?? 0, sanitized: false, authGated: activeAuth.length > 0, authGates: activeAuth });
32161
+ }
32162
+ return t;
32163
+ }
32164
+ return CLEAN;
32165
+ }
32166
+ function cloneEnv(env) {
32167
+ return new Map([...env.entries()].map(([k, v]) => [k, { ...v, sources: [...v.sources], sanitizers: [...v.sanitizers] }]));
32168
+ }
32169
+ function cloneProps(props) {
32170
+ const out = new Map;
32171
+ for (const [k, v] of props)
32172
+ out.set(k, new Map(v));
32173
+ return out;
32174
+ }
32175
+ function mergeCtx(ctx, other) {
32176
+ ctx.sinks.push(...other.sinks);
32177
+ if (other.returnsTainted)
32178
+ ctx.returnsTainted = true;
32179
+ ctx.calls.push(...other.calls);
32180
+ }
32181
+ function authGatesOf(node) {
32182
+ if (!isNode3(node))
32183
+ return [];
32184
+ return AUTH_GATES.filter((g) => JSON.stringify(node).includes(g));
32185
+ }
32186
+ var VALIDATION_GATES = ["in_array", "preg_match", "ctype_digit", "ctype_alnum", "is_numeric"];
32187
+ function validationGatesOf(node) {
32188
+ if (!isNode3(node))
32189
+ return false;
32190
+ const text = JSON.stringify(node);
32191
+ return VALIDATION_GATES.some((g) => text.includes(g));
32192
+ }
32193
+ function collectDecls(ast, out) {
32194
+ walkDecls(ast, out);
32195
+ }
32196
+ function walkDecls(node, out, className) {
32197
+ if (!isNode3(node))
32198
+ return;
32199
+ if (node.kind === "function") {
32200
+ const name = nameOf2(node.name);
32201
+ if (name)
32202
+ out.push({ id: `func:${name}`, name, node, kind: "function" });
32203
+ } else if (node.kind === "class") {
32204
+ const cn = nameOf2(node.name);
32205
+ for (const c of children3(node)) {
32206
+ if (c.kind === "method") {
32207
+ const mn = nameOf2(c.name);
32208
+ if (mn && cn)
32209
+ out.push({ id: `method:${cn}::${mn}`, name: mn, node: c, kind: "method" });
32210
+ }
32211
+ }
32212
+ return;
32213
+ } else if (node.kind === "method") {
32214
+ const mn = nameOf2(node.name);
32215
+ if (mn && className)
32216
+ out.push({ id: `method:${className}::${mn}`, name: mn, node, kind: "method" });
32217
+ }
32218
+ const childCtx = node.kind === "class" ? nameOf2(node.name) ?? className : className;
32219
+ for (const c of children3(node))
32220
+ walkDecls(c, out, childCtx);
32221
+ }
32222
+ function resolveFuncId(name, summaries) {
32223
+ if (summaries.has(`func:${name}`))
32224
+ return `func:${name}`;
32225
+ for (const [id, s] of summaries) {
32226
+ if (s.name === name && id.startsWith("method:"))
32227
+ return id;
32228
+ }
32229
+ return null;
32230
+ }
32231
+ function analyzeDataFlow2(path) {
32232
+ const cg = buildCallGraph(path);
32233
+ const entries = entryPoints(cg);
32234
+ const reachable = new Set;
32235
+ for (const e of entries)
32236
+ for (const n of reachableFrom(cg, e))
32237
+ reachable.add(n);
32238
+ const unreachable = [...cg.nodes.keys()].filter((id) => !reachable.has(id));
32239
+ const result = {
32240
+ file: path,
32241
+ findings: [],
32242
+ suppressed: 0,
32243
+ summary: { functions: 0, methods: 0, edges: cg.edges.length, entry_points: entries, unreachable }
32244
+ };
32245
+ let code;
32246
+ try {
32247
+ code = readFileSync12(path, "utf8");
32248
+ } catch {
32249
+ return result;
32250
+ }
32251
+ let ast;
32252
+ try {
32253
+ ast = parser3.parseCode(code, path);
32254
+ } catch {
32255
+ return result;
32256
+ }
32257
+ const summaries = new Map;
32258
+ const decls = [];
32259
+ collectDecls(ast, decls);
32260
+ for (const d of decls) {
32261
+ summaries.set(d.id, summarizeFunction(d.node, d.id, d.name, summaries));
32262
+ if (d.kind === "function")
32263
+ result.summary.functions += 1;
32264
+ else
32265
+ result.summary.methods += 1;
32266
+ }
32267
+ const topStmts = [];
32268
+ for (const s of ast.children ?? []) {
32269
+ if (isNode3(s) && s.kind !== "function" && s.kind !== "class")
32270
+ topStmts.push(s);
32271
+ }
32272
+ const mainSummary = { id: "main", name: "main", params: [], byrefParams: new Set, paramSinks: new Map, paramReturns: new Set, paramCalls: new Map, paramWrites: new Map };
32273
+ const mainEnv = new Map;
32274
+ const mainCtx = { sinks: [], returnsTainted: false, calls: [] };
32275
+ const mainProps = new Map;
32276
+ analyzeBody(topStmts, mainEnv, mainSummary, mainCtx, "", mainProps, [], summaries);
32277
+ for (const hit of mainCtx.sinks) {
32278
+ const cls = classifySink2(hit.sink);
32279
+ if (!cls)
32280
+ continue;
32281
+ if (hit.sanitized) {
32282
+ result.suppressed += 1;
32283
+ continue;
32284
+ }
32285
+ result.findings.push({
32286
+ sink: hit.sink,
32287
+ sink_line: hit.line,
32288
+ category: cls.category,
32289
+ cwe: cls.cwe,
32290
+ sanitized: false,
32291
+ auth_gated: hit.authGated,
32292
+ auth_gates: hit.authGates,
32293
+ interprocedural: false,
32294
+ via_return: false
32295
+ });
32296
+ }
32297
+ const queue = [];
32298
+ const seen = new Set;
32299
+ const mainCalls = topStmts.flatMap((s) => findKind2(s, "call"));
32300
+ for (const call of mainCalls) {
32301
+ const fnName = rootVarName2(call.what);
32302
+ if (!fnName || sinkClassOf2(call))
32303
+ continue;
32304
+ const target = resolveFuncId(fnName, summaries);
32305
+ if (!target)
32306
+ continue;
32307
+ for (let i = 0;i < call.arguments.length; i++) {
32308
+ const argTaint = analyzeExpr(call.arguments[i], mainEnv, mainSummary, mainCtx, "", mainProps, [], summaries);
32309
+ if (argTaint.tainted) {
32310
+ const param = summaries.get(target).params[i];
32311
+ if (param)
32312
+ queue.push({ funcId: target, param, source: argTaint.sources[0], sourceLine: argTaint.sourceLine, viaReturn: false });
32313
+ }
32314
+ }
32315
+ }
32316
+ while (queue.length) {
32317
+ const item = queue.shift();
32318
+ const key = `${item.funcId}:${item.param}`;
32319
+ if (seen.has(key))
32320
+ continue;
32321
+ seen.add(key);
32322
+ const sum = summaries.get(item.funcId);
32323
+ if (!sum)
32324
+ continue;
32325
+ for (const hit of sum.paramSinks.get(item.param) ?? []) {
32326
+ const cls = classifySink2(hit.sink);
32327
+ if (!cls)
32328
+ continue;
32329
+ if (hit.sanitized) {
32330
+ result.suppressed += 1;
32331
+ continue;
32332
+ }
32333
+ result.findings.push({
32334
+ sink: hit.sink,
32335
+ sink_line: hit.line,
32336
+ category: cls.category,
32337
+ cwe: cls.cwe,
32338
+ source: item.source,
32339
+ source_line: item.sourceLine,
32340
+ sanitized: false,
32341
+ auth_gated: hit.authGated,
32342
+ auth_gates: hit.authGates,
32343
+ interprocedural: true,
32344
+ via_return: item.viaReturn
32345
+ });
32346
+ }
32347
+ for (const c of sum.paramCalls.get(item.param) ?? []) {
32348
+ const calleeId = resolveFuncId(c.callee, summaries);
32349
+ if (!calleeId)
32350
+ continue;
32351
+ const calleeParam = summaries.get(calleeId).params[c.argIndex];
32352
+ if (calleeParam)
32353
+ queue.push({ funcId: calleeId, param: calleeParam, source: item.source, sourceLine: item.sourceLine, viaReturn: false });
32354
+ }
32355
+ }
32356
+ return result;
32357
+ }
32358
+
32359
+ // src/differential.ts
32360
+ import { writeFileSync as writeFileSync2, rmSync, mkdtempSync, readFileSync as readFileSync13 } from "node:fs";
32361
+ import { join as join9 } from "node:path";
32362
+ import { tmpdir } from "node:os";
32363
+ import { execSync } from "node:child_process";
32364
+
31596
32365
  // src/universal-taint.ts
31597
32366
  function runTaintEngine(adapter, code, file) {
31598
32367
  const result = { file, language: adapter.language, findings: [], suppressed: 0 };
@@ -31694,7 +32463,7 @@ function analyzeTaintUniversal(code, file) {
31694
32463
  }
31695
32464
 
31696
32465
  // src/adapters.ts
31697
- var import_php_parser2 = __toESM(require_src(), 1);
32466
+ var import_php_parser4 = __toESM(require_src(), 1);
31698
32467
 
31699
32468
  // node_modules/@babel/parser/lib/index.js
31700
32469
  class Position {
@@ -49473,7 +50242,7 @@ var pythonHighlighting = styleTags({
49473
50242
  ", ;": tags.separator
49474
50243
  });
49475
50244
  var spec_identifier = { __proto__: null, await: 44, or: 54, and: 56, in: 60, not: 62, is: 64, if: 70, else: 72, lambda: 76, yield: 94, from: 96, async: 102, for: 104, None: 162, True: 164, False: 164, del: 178, pass: 182, break: 186, continue: 190, return: 194, raise: 202, import: 206, as: 208, global: 212, nonlocal: 214, assert: 218, type: 223, elif: 236, while: 240, try: 246, except: 248, finally: 250, with: 254, def: 258, class: 268, match: 279, case: 285 };
49476
- var parser2 = LRParser.deserialize({
50245
+ var parser4 = LRParser.deserialize({
49477
50246
  version: 14,
49478
50247
  states: "##jQ`QeOOP$}OSOOO&WQtO'#HUOOQS'#Co'#CoOOQS'#Cp'#CpO'vQdO'#CnO*UQtO'#HTOOQS'#HU'#HUOOQS'#DU'#DUOOQS'#HT'#HTO*rQdO'#D_O+VQdO'#DfO+gQdO'#DjO+zOWO'#DuO,VOWO'#DvO.[QtO'#GuOOQS'#Gu'#GuO'vQdO'#GtO0ZQtO'#GtOOQS'#Eb'#EbO0rQdO'#EcOOQS'#Gs'#GsO0|QdO'#GrOOQV'#Gr'#GrO1XQdO'#FYOOQS'#G^'#G^O1^QdO'#FXOOQV'#IS'#ISOOQV'#Gq'#GqOOQV'#Fq'#FqQ`QeOOO'vQdO'#CqO1lQdO'#C}O1sQdO'#DRO2RQdO'#HYO2cQtO'#EVO'vQdO'#EWOOQS'#EY'#EYOOQS'#E['#E[OOQS'#E^'#E^O2wQdO'#E`O3_QdO'#EdO3rQdO'#EfO3zQtO'#EfO1XQdO'#EiO0rQdO'#ElO1XQdO'#EnO0rQdO'#EtO0rQdO'#EwO4VQdO'#EyO4^QdO'#FOO4iQdO'#EzO0rQdO'#FOO1XQdO'#FQO1XQdO'#FVO4nQdO'#F[P4uOdO'#GpPOOO)CBd)CBdOOQS'#Ce'#CeOOQS'#Cf'#CfOOQS'#Cg'#CgOOQS'#Ch'#ChOOQS'#Ci'#CiOOQS'#Cj'#CjOOQS'#Cl'#ClO'vQdO,59OO'vQdO,59OO'vQdO,59OO'vQdO,59OO'vQdO,59OO'vQdO,59OO5TQdO'#DoOOQS,5:Y,5:YO5hQdO'#HdOOQS,5:],5:]O5uQ!fO,5:]O5zQtO,59YO1lQdO,59bO1lQdO,59bO1lQdO,59bO8jQdO,59bO8oQdO,59bO8vQdO,59jO8}QdO'#HTO:TQdO'#HSOOQS'#HS'#HSOOQS'#D['#D[O:lQdO,59aO'vQdO,59aO:zQdO,59aOOQS,59y,59yO;PQdO,5:RO'vQdO,5:ROOQS,5:Q,5:QO;_QdO,5:QO;dQdO,5:XO'vQdO,5:XO'vQdO,5:VOOQS,5:U,5:UO;uQdO,5:UO;zQdO,5:WOOOW'#Fy'#FyO<POWO,5:aOOQS,5:a,5:aO<[QdO'#HwOOOW'#Dw'#DwOOOW'#Fz'#FzO<lOWO,5:bOOQS,5:b,5:bOOQS'#F}'#F}O<zQtO,5:iO?lQtO,5=`O@VQ#xO,5=`O@vQtO,5=`OOQS,5:},5:}OA_QeO'#GWOBqQdO,5;^OOQV,5=^,5=^OB|QtO'#IPOCkQdO,5;tOOQS-E:[-E:[OOQV,5;s,5;sO4dQdO'#FQOOQV-E9o-E9oOCsQtO,59]OEzQtO,59iOFeQdO'#HVOFpQdO'#HVO1XQdO'#HVOF{QdO'#DTOGTQdO,59mOGYQdO'#HZO'vQdO'#HZO0rQdO,5=tOOQS,5=t,5=tO0rQdO'#EROOQS'#ES'#ESOGwQdO'#GPOHXQdO,58|OHXQdO,58|O*xQdO,5:oOHgQtO'#H]OOQS,5:r,5:rOOQS,5:z,5:zOHzQdO,5;OOI]QdO'#IOO1XQdO'#H}OOQS,5;Q,5;QOOQS'#GT'#GTOIqQtO,5;QOJPQdO,5;QOJUQdO'#IQOOQS,5;T,5;TOJdQdO'#H|OOQS,5;W,5;WOJuQdO,5;YO4iQdO,5;`O4iQdO,5;cOJ}QtO'#ITO'vQdO'#ITOKXQdO,5;eO4VQdO,5;eO0rQdO,5;jO1XQdO,5;lOK^QeO'#EuOLjQgO,5;fO!!kQdO'#IUO4iQdO,5;jO!!vQdO,5;lO!#OQdO,5;qO!#ZQtO,5;vO'vQdO,5;vPOOO,5=[,5=[P!#bOSO,5=[P!#jOdO,5=[O!&bQtO1G.jO!&iQtO1G.jO!)YQtO1G.jO!)dQtO1G.jO!+}QtO1G.jO!,bQtO1G.jO!,uQdO'#HcO!-TQtO'#GuO0rQdO'#HcO!-_QdO'#HbOOQS,5:Z,5:ZO!-gQdO,5:ZO!-lQdO'#HeO!-wQdO'#HeO!.[QdO,5>OOOQS'#Ds'#DsOOQS1G/w1G/wOOQS1G.|1G.|O!/[QtO1G.|O!/cQtO1G.|O1lQdO1G.|O!0OQdO1G/UOOQS'#DZ'#DZO0rQdO,59tOOQS1G.{1G.{O!0VQdO1G/eO!0gQdO1G/eO!0oQdO1G/fO'vQdO'#H[O!0tQdO'#H[O!0yQtO1G.{O!1ZQdO,59iO!2aQdO,5=zO!2qQdO,5=zO!2yQdO1G/mO!3OQtO1G/mOOQS1G/l1G/lO!3`QdO,5=uO!4VQdO,5=uO0rQdO1G/qO!4tQdO1G/sO!4yQtO1G/sO!5ZQtO1G/qOOQS1G/p1G/pOOQS1G/r1G/rOOOW-E9w-E9wOOQS1G/{1G/{O!5kQdO'#HxO0rQdO'#HxO!5|QdO,5>cOOOW-E9x-E9xOOQS1G/|1G/|OOQS-E9{-E9{O!6[Q#xO1G2zO!6{QtO1G2zO'vQdO,5<jOOQS,5<j,5<jOOQS-E9|-E9|OOQS,5<r,5<rOOQS-E:U-E:UOOQV1G0x1G0xO1XQdO'#GRO!7dQtO,5>kOOQS1G1`1G1`O!8RQdO1G1`OOQS'#DV'#DVO0rQdO,5=qOOQS,5=q,5=qO!8WQdO'#FrO!8cQdO,59oO!8kQdO1G/XO!8uQtO,5=uOOQS1G3`1G3`OOQS,5:m,5:mO!9fQdO'#GtOOQS,5<k,5<kOOQS-E9}-E9}O!9wQdO1G.hOOQS1G0Z1G0ZO!:VQdO,5=wO!:gQdO,5=wO0rQdO1G0jO0rQdO1G0jO!:xQdO,5>jO!;ZQdO,5>jO1XQdO,5>jO!;lQdO,5>iOOQS-E:R-E:RO!;qQdO1G0lO!;|QdO1G0lO!<RQdO,5>lO!<aQdO,5>lO!<oQdO,5>hO!=VQdO,5>hO!=hQdO'#EpO0rQdO1G0tO!=sQdO1G0tO!=xQgO1G0zO!AvQgO1G0}O!EqQdO,5>oO!E{QdO,5>oO!FTQtO,5>oO0rQdO1G1PO!F_QdO1G1PO4iQdO1G1UO!!vQdO1G1WOOQV,5;a,5;aO!FdQfO,5;aO!FiQgO1G1QO!JjQdO'#GZO4iQdO1G1QO4iQdO1G1QO!JzQdO,5>pO!KXQdO,5>pO1XQdO,5>pOOQV1G1U1G1UO!KaQdO'#FSO!KrQ!fO1G1WO!KzQdO1G1WOOQV1G1]1G1]O4iQdO1G1]O!LPQdO1G1]O!LXQdO'#F^OOQV1G1b1G1bO!#ZQtO1G1bPOOO1G2v1G2vP!L^OSO1G2vOOQS,5=},5=}OOQS'#Dp'#DpO0rQdO,5=}O!LfQdO,5=|O!LyQdO,5=|OOQS1G/u1G/uO!MRQdO,5>PO!McQdO,5>PO!MkQdO,5>PO!NOQdO,5>PO!N`QdO,5>POOQS1G3j1G3jOOQS7+$h7+$hO!8kQdO7+$pO#!RQdO1G.|O#!YQdO1G.|OOQS1G/`1G/`OOQS,5<`,5<`O'vQdO,5<`OOQS7+%P7+%PO#!aQdO7+%POOQS-E9r-E9rOOQS7+%Q7+%QO#!qQdO,5=vO'vQdO,5=vOOQS7+$g7+$gO#!vQdO7+%PO##OQdO7+%QO##TQdO1G3fOOQS7+%X7+%XO##eQdO1G3fO##mQdO7+%XOOQS,5<_,5<_O'vQdO,5<_O##rQdO1G3aOOQS-E9q-E9qO#$iQdO7+%]OOQS7+%_7+%_O#$wQdO1G3aO#%fQdO7+%_O#%kQdO1G3gO#%{QdO1G3gO#&TQdO7+%]O#&YQdO,5>dO#&sQdO,5>dO#&sQdO,5>dOOQS'#Dx'#DxO#'UO&jO'#DzO#'aO`O'#HyOOOW1G3}1G3}O#'fQdO1G3}O#'nQdO1G3}O#'yQ#xO7+(fO#(jQtO1G2UP#)TQdO'#GOOOQS,5<m,5<mOOQS-E:P-E:POOQS7+&z7+&zOOQS1G3]1G3]OOQS,5<^,5<^OOQS-E9p-E9pOOQS7+$s7+$sO#)bQdO,5=`O#){QdO,5=`O#*^QtO,5<aO#*qQdO1G3cOOQS-E9s-E9sOOQS7+&U7+&UO#+RQdO7+&UO#+aQdO,5<nO#+uQdO1G4UOOQS-E:Q-E:QO#,WQdO1G4UOOQS1G4T1G4TOOQS7+&W7+&WO#,iQdO7+&WOOQS,5<p,5<pO#,tQdO1G4WOOQS-E:S-E:SOOQS,5<l,5<lO#-SQdO1G4SOOQS-E:O-E:OO1XQdO'#EqO#-jQdO'#EqO#-uQdO'#IRO#-}QdO,5;[OOQS7+&`7+&`O0rQdO7+&`O#.SQgO7+&fO!JmQdO'#GXO4iQdO7+&fO4iQdO7+&iO#2QQtO,5<tO'vQdO,5<tO#2[QdO1G4ZOOQS-E:W-E:WO#2fQdO1G4ZO4iQdO7+&kO0rQdO7+&kOOQV7+&p7+&pO!KrQ!fO7+&rO!KzQdO7+&rO`QeO1G0{OOQV-E:X-E:XO4iQdO7+&lO4iQdO7+&lOOQV,5<u,5<uO#2nQdO,5<uO!JmQdO,5<uOOQV7+&l7+&lO#2yQgO7+&lO#6tQdO,5<vO#7PQdO1G4[OOQS-E:Y-E:YO#7^QdO1G4[O#7fQdO'#IWO#7tQdO'#IWO1XQdO'#IWOOQS'#IW'#IWO#8PQdO'#IVOOQS,5;n,5;nO#8XQdO,5;nO0rQdO'#FUOOQV7+&r7+&rO4iQdO7+&rOOQV7+&w7+&wO4iQdO7+&wO#8^QfO,5;xOOQV7+&|7+&|POOO7+(b7+(bO#8cQdO1G3iOOQS,5<c,5<cO#8qQdO1G3hOOQS-E9u-E9uO#9UQdO,5<dO#9aQdO,5<dO#9tQdO1G3kOOQS-E9v-E9vO#:UQdO1G3kO#:^QdO1G3kO#:nQdO1G3kO#:UQdO1G3kOOQS<<H[<<H[O#:yQtO1G1zOOQS<<Hk<<HkP#;WQdO'#FtO8vQdO1G3bO#;eQdO1G3bO#;jQdO<<HkOOQS<<Hl<<HlO#;zQdO7+)QOOQS<<Hs<<HsO#<[QtO1G1yP#<{QdO'#FsO#=YQdO7+)RO#=jQdO7+)RO#=rQdO<<HwO#=wQdO7+({OOQS<<Hy<<HyO#>nQdO,5<bO'vQdO,5<bOOQS-E9t-E9tOOQS<<Hw<<HwOOQS,5<g,5<gO0rQdO,5<gO#>sQdO1G4OOOQS-E9y-E9yO#?^QdO1G4OO<[QdO'#H{OOOO'#D{'#D{OOOO'#F|'#F|O#?oO&jO,5:fOOOW,5>e,5>eOOOW7+)i7+)iO#?zQdO7+)iO#@SQdO1G2zO#@mQdO1G2zP'vQdO'#FuO0rQdO<<IpO1XQdO1G2YP1XQdO'#GSO#AOQdO7+)pO#AaQdO7+)pOOQS<<Ir<<IrP1XQdO'#GUP0rQdO'#GQOOQS,5;],5;]O#ArQdO,5>mO#BQQdO,5>mOOQS1G0v1G0vOOQS<<Iz<<IzOOQV-E:V-E:VO4iQdO<<JQOOQV,5<s,5<sO4iQdO,5<sOOQV<<JQ<<JQOOQV<<JT<<JTO#BYQtO1G2`P#BdQdO'#GYO#BkQdO7+)uO#BuQgO<<JVO4iQdO<<JVOOQV<<J^<<J^O4iQdO<<J^O!KrQ!fO<<J^O#FpQgO7+&gOOQV<<JW<<JWO#FzQgO<<JWOOQV1G2a1G2aO1XQdO1G2aO#JuQdO1G2aO4iQdO<<JWO1XQdO1G2bP0rQdO'#G[O#KQQdO7+)vO#K_QdO7+)vOOQS'#FT'#FTO0rQdO,5>rO#KgQdO,5>rO#KrQdO,5>rO#K}QdO,5>qO#L`QdO,5>qOOQS1G1Y1G1YOOQS,5;p,5;pOOQV<<Jc<<JcO#LhQdO1G1dOOQS7+)T7+)TP#LmQdO'#FwO#L}QdO1G2OO#MbQdO1G2OO#MrQdO1G2OP#M}QdO'#FxO#N[QdO7+)VO#NlQdO7+)VO#NlQdO7+)VO#NtQdO7+)VO$ UQdO7+(|O8vQdO7+(|OOQSAN>VAN>VO$ oQdO<<LmOOQSAN>cAN>cO0rQdO1G1|O$!PQtO1G1|P$!ZQdO'#FvOOQS1G2R1G2RP$!hQdO'#F{O$!uQdO7+)jO$#`QdO,5>gOOOO-E9z-E9zOOOW<<MT<<MTO$#nQdO7+(fOOQSAN?[AN?[OOQS7+'t7+'tO$$XQdO<<M[OOQS,5<q,5<qO$$jQdO1G4XOOQS-E:T-E:TOOQVAN?lAN?lOOQV1G2_1G2_O4iQdOAN?qO$$xQgOAN?qOOQVAN?xAN?xO4iQdOAN?xOOQV<<JR<<JRO4iQdOAN?rO4iQdO7+'{OOQV7+'{7+'{O1XQdO7+'{OOQVAN?rAN?rOOQS7+'|7+'|O$(sQdO<<MbOOQS1G4^1G4^O0rQdO1G4^OOQS,5<w,5<wO$)QQdO1G4]OOQS-E:Z-E:ZOOQU'#G_'#G_O$)cQfO7+'OO$)nQdO'#F_O$*uQdO7+'jO$+VQdO7+'jOOQS7+'j7+'jO$+bQdO<<LqO$+rQdO<<LqO$+rQdO<<LqO$+zQdO'#H^OOQS<<Lh<<LhO$,UQdO<<LhOOQS7+'h7+'hOOQS'#D|'#D|OOOO1G4R1G4RO$,oQdO1G4RO$,wQdO1G4RP!=hQdO'#GVOOQVG25]G25]O4iQdOG25]OOQVG25dG25dOOQVG25^G25^OOQV<<Kg<<KgO4iQdO<<KgOOQS7+)x7+)xP$-SQdO'#G]OOQU-E:]-E:]OOQV<<Jj<<JjO$-vQtO'#FaOOQS'#Fc'#FcO$.WQdO'#FbO$.xQdO'#FbOOQS'#Fb'#FbO$.}QdO'#IYO$)nQdO'#FiO$)nQdO'#FiO$/fQdO'#FjO$)nQdO'#FkO$/mQdO'#IZOOQS'#IZ'#IZO$0[QdO,5;yOOQS<<KU<<KUO$0dQdO<<KUO$0tQdOANB]O$1UQdOANB]O$1^QdO'#H_OOQS'#H_'#H_O1sQdO'#DcO$1wQdO,5=xOOQSANBSANBSOOOO7+)m7+)mO$2`QdO7+)mOOQVLD*wLD*wOOQVANARANARO5uQ!fO'#GaO$2hQtO,5<SO$)nQdO'#FmOOQS,5<W,5<WOOQS'#Fd'#FdO$3YQdO,5;|O$3_QdO,5;|OOQS'#Fg'#FgO$)nQdO'#G`O$4PQdO,5<QO$4kQdO,5>tO$4{QdO,5>tO1XQdO,5<PO$5^QdO,5<TO$5cQdO,5<TO$)nQdO'#I[O$5hQdO'#I[O$5mQdO,5<UOOQS,5<V,5<VO0rQdO'#FpOOQU1G1e1G1eO4iQdO1G1eOOQSAN@pAN@pO$5rQdOG27wO$6SQdO,59}OOQS1G3d1G3dOOOO<<MX<<MXOOQS,5<{,5<{OOQS-E:_-E:_O$6XQtO'#FaO$6`QdO'#I]O$6nQdO'#I]O$6vQdO,5<XOOQS1G1h1G1hO$6{QdO1G1hO$7QQdO,5<zOOQS-E:^-E:^O$7lQdO,5=OO$8TQdO1G4`OOQS-E:b-E:bOOQS1G1k1G1kOOQS1G1o1G1oO$8eQdO,5>vO$)nQdO,5>vOOQS1G1p1G1pOOQS,5<[,5<[OOQU7+'P7+'PO$+zQdO1G/iO$)nQdO,5<YO$8sQdO,5>wO$8zQdO,5>wOOQS1G1s1G1sOOQS7+'S7+'SP$)nQdO'#GdO$9SQdO1G4bO$9^QdO1G4bO$9fQdO1G4bOOQS7+%T7+%TO$9tQdO1G1tO$:SQtO'#FaO$:ZQdO,5<}OOQS,5<},5<}O$:iQdO1G4cOOQS-E:a-E:aO$)nQdO,5<|O$:pQdO,5<|O$:uQdO7+)|OOQS-E:`-E:`O$;PQdO7+)|O$)nQdO,5<ZP$)nQdO'#GcO$;XQdO1G2hO$)nQdO1G2hP$;gQdO'#GbO$;nQdO<<MhO$;xQdO1G1uO$<WQdO7+(SO8vQdO'#C}O8vQdO,59bO8vQdO,59bO8vQdO,59bO$<fQtO,5=`O8vQdO1G.|O0rQdO1G/XO0rQdO7+$pP$<yQdO'#GOO'vQdO'#GtO$=WQdO,59bO$=]QdO,59bO$=dQdO,59mO$=iQdO1G/UO1sQdO'#DRO8vQdO,59j",
49479
50248
  stateData: "$>S~O%cOS%^OSSOS%]PQ~OPdOVaOfoOhYOopOs!POvqO!PrO!Q{O!T!SO!U!RO!XZO!][O!h`O!r`O!s`O!t`O!{tO!}uO#PvO#RwO#TxO#XyO#ZzO#^|O#_|O#a}O#c!OO#l!QO#o!TO#s!UO#u!VO#z!WO#}hO$P!XO%oRO%pRO%tSO%uWO&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O&c^O&d^O&e^O&f^O&g^O&h^O&i^O&j^O~O%]!YO~OV!aO_!aOa!bOh!iO!X!kO!f!mO%j![O%k!]O%l!^O%m!_O%n!_O%o!`O%p!`O%q!aO%r!aO%s!aO~Ok%xXl%xXm%xXn%xXo%xXp%xXs%xXz%xX{%xX!x%xX#g%xX%[%xX%_%xX%z%xXg%xX!T%xX!U%xX%{%xX!W%xX![%xX!Q%xX#[%xXt%xX!m%xX~P%SOfoOhYO!XZO!][O!h`O!r`O!s`O!t`O%oRO%pRO%tSO%uWO&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O&c^O&d^O&e^O&f^O&g^O&h^O&i^O&j^O~Oz%wX{%wX#g%wX%[%wX%_%wX%z%wX~Ok!pOl!qOm!oOn!oOo!rOp!sOs!tO!x%wX~P)pOV!zOg!|Oo0cOv0qO!PrO~P'vOV#OOo0cOv0qO!W#PO~P'vOV#SOa#TOo0cOv0qO![#UO~P'vOQ#XO%`#XO%a#ZO~OQ#^OR#[O%`#^O%a#`O~OV%iX_%iXa%iXh%iXk%iXl%iXm%iXn%iXo%iXp%iXs%iXz%iX!X%iX!f%iX%j%iX%k%iX%l%iX%m%iX%n%iX%o%iX%p%iX%q%iX%r%iX%s%iXg%iX!T%iX!U%iX~O&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O&c^O&d^O&e^O&f^O&g^O&h^O&i^O&j^O{%iX!x%iX#g%iX%[%iX%_%iX%z%iX%{%iX!W%iX![%iX!Q%iX#[%iXt%iX!m%iX~P,eOz#dO{%hX!x%hX#g%hX%[%hX%_%hX%z%hX~Oo0cOv0qO~P'vO#g#gO%[#iO%_#iO~O%uWO~O!T#nO#u!VO#z!WO#}hO~OopO~P'vOV#sOa#tO%uWO{wP~OV#xOo0cOv0qO!Q#yO~P'vO{#{O!x$QO%z#|O#g!yX%[!yX%_!yX~OV#xOo0cOv0qO#g#SX%[#SX%_#SX~P'vOo0cOv0qO#g#WX%[#WX%_#WX~P'vOh$WO%uWO~O!f$YO!r$YO%uWO~OV$eO~P'vO!U$gO#s$hO#u$iO~O{$jO~OV$qO~P'vOS$sO%[$rO%_$rO%c$tO~OV$}Oa$}Og%POo0cOv0qO~P'vOo0cOv0qO{%SO~P'vO&Y%UO~Oa!bOh!iO!X!kO!f!mOVba_bakbalbambanbaobapbasbazba{ba!xba#gba%[ba%_ba%jba%kba%lba%mba%nba%oba%pba%qba%rba%sba%zbagba!Tba!Uba%{ba!Wba![ba!Qba#[batba!mba~On%ZO~Oo%ZO~P'vOo0cO~P'vOk0eOl0fOm0dOn0dOo0mOp0nOs0rOg%wX!T%wX!U%wX%{%wX!W%wX![%wX!Q%wX#[%wX!m%wX~P)pO%{%]Og%vXz%vX!T%vX!U%vX!W%vX{%vX~Og%_Oz%`O!T%dO!U%cO~Og%_O~Oz%gO!T%dO!U%cO!W&SX~O!W%kO~Oz%lO{%nO!T%dO!U%cO![%}X~O![%rO~O![%sO~OQ#XO%`#XO%a%uO~OV%wOo0cOv0qO!PrO~P'vOQ#^OR#[O%`#^O%a%zO~OV!qa_!qaa!qah!qak!qal!qam!qan!qao!qap!qas!qaz!qa{!qa!X!qa!f!qa!x!qa#g!qa%[!qa%_!qa%j!qa%k!qa%l!qa%m!qa%n!qa%o!qa%p!qa%q!qa%r!qa%s!qa%z!qag!qa!T!qa!U!qa%{!qa!W!qa![!qa!Q!qa#[!qat!qa!m!qa~P#yOz%|O{%ha!x%ha#g%ha%[%ha%_%ha%z%ha~P%SOV&OOopOvqO{%ha!x%ha#g%ha%[%ha%_%ha%z%ha~P'vOz%|O{%ha!x%ha#g%ha%[%ha%_%ha%z%ha~OPdOVaOopOvqO!PrO!Q{O!{tO!}uO#PvO#RwO#TxO#XyO#ZzO#^|O#_|O#a}O#c!OO#g$zX%[$zX%_$zX~P'vO#g#gO%[&TO%_&TO~O!f&UOh&sX%[&sXz&sX#[&sX#g&sX%_&sX#Z&sXg&sX~Oh!iO%[&WO~Okealeameaneaoeapeaseazea{ea!xea#gea%[ea%_ea%zeagea!Tea!Uea%{ea!Wea![ea!Qea#[eatea!mea~P%SOsqazqa{qa#gqa%[qa%_qa%zqa~Ok!pOl!qOm!oOn!oOo!rOp!sO!xqa~PEcO%z&YOz%yX{%yX~O%uWOz%yX{%yX~Oz&]O{wX~O{&_O~Oz%lO#g%}X%[%}X%_%}Xg%}X{%}X![%}X!m%}X%z%}X~OV0lOo0cOv0qO!PrO~P'vO%z#|O#gUa%[Ua%_Ua~Oz&hO#g&PX%[&PX%_&PXn&PX~P%SOz&kO!Q&jO#g#Wa%[#Wa%_#Wa~Oz&lO#[&nO#g&rX%[&rX%_&rXg&rX~O!f$YO!r$YO#Z&qO%uWO~O#Z&qO~Oz&sO#g&tX%[&tX%_&tX~Oz&uO#g&pX%[&pX%_&pX{&pX~O!X&wO%z&xO~Oz&|On&wX~P%SOn'PO~OPdOVaOopOvqO!PrO!Q{O!{tO!}uO#PvO#RwO#TxO#XyO#ZzO#^|O#_|O#a}O#c!OO%['UO~P'vOt'YO#p'WO#q'XOP#naV#naf#nah#nao#nas#nav#na!P#na!Q#na!T#na!U#na!X#na!]#na!h#na!r#na!s#na!t#na!{#na!}#na#P#na#R#na#T#na#X#na#Z#na#^#na#_#na#a#na#c#na#l#na#o#na#s#na#u#na#z#na#}#na$P#na%X#na%o#na%p#na%t#na%u#na&Z#na&[#na&]#na&^#na&_#na&`#na&a#na&b#na&c#na&d#na&e#na&f#na&g#na&h#na&i#na&j#na%Z#na%_#na~Oz'ZO#[']O{&xX~Oh'_O!X&wO~Oh!iO{$jO!X&wO~O{'eO~P%SO%['hO%_'hO~OS'iO%['hO%_'hO~OV!aO_!aOa!bOh!iO!X!kO!f!mO%l!^O%m!_O%n!_O%o!`O%p!`O%q!aO%r!aO%s!aOkWilWimWinWioWipWisWizWi{Wi!xWi#gWi%[Wi%_Wi%jWi%zWigWi!TWi!UWi%{Wi!WWi![Wi!QWi#[WitWi!mWi~O%k!]O~P!#uO%kWi~P!#uOV!aO_!aOa!bOh!iO!X!kO!f!mO%o!`O%p!`O%q!aO%r!aO%s!aOkWilWimWinWioWipWisWizWi{Wi!xWi#gWi%[Wi%_Wi%jWi%kWi%lWi%zWigWi!TWi!UWi%{Wi!WWi![Wi!QWi#[WitWi!mWi~O%m!_O%n!_O~P!&pO%mWi%nWi~P!&pOa!bOh!iO!X!kO!f!mOkWilWimWinWioWipWisWizWi{Wi!xWi#gWi%[Wi%_Wi%jWi%kWi%lWi%mWi%nWi%oWi%pWi%zWigWi!TWi!UWi%{Wi!WWi![Wi!QWi#[WitWi!mWi~OV!aO_!aO%q!aO%r!aO%s!aO~P!)nOVWi_Wi%qWi%rWi%sWi~P!)nO!T%dO!U%cOg&VXz&VX~O%z'kO%{'kO~P,eOz'mOg&UX~Og'oO~Oz'pO{'rO!W&XX~Oo0cOv0qOz'pO{'sO!W&XX~P'vO!W'uO~Om!oOn!oOo!rOp!sOkjisjizji{ji!xji#gji%[ji%_ji%zji~Ol!qO~P!.aOlji~P!.aOk0eOl0fOm0dOn0dOo0mOp0nO~Ot'wO~P!/jOV'|Og'}Oo0cOv0qO~P'vOg'}Oz(OO~Og(QO~O!U(SO~Og(TOz(OO!T%dO!U%cO~P%SOk0eOl0fOm0dOn0dOo0mOp0nOgqa!Tqa!Uqa%{qa!Wqa![qa!Qqa#[qatqa!mqa~PEcOV'|Oo0cOv0qO!W&Sa~P'vOz(WO!W&Sa~O!W(XO~Oz(WO!T%dO!U%cO!W&Sa~P%SOV(]Oo0cOv0qO![%}a#g%}a%[%}a%_%}ag%}a{%}a!m%}a%z%}a~P'vOz(^O![%}a#g%}a%[%}a%_%}ag%}a{%}a!m%}a%z%}a~O![(aO~Oz(^O!T%dO!U%cO![%}a~P%SOz(dO!T%dO!U%cO![&Ta~P%SOz(gO{&lX![&lX!m&lX%z&lX~O{(kO![(mO!m(nO%z(jO~OV&OOopOvqO{%hi!x%hi#g%hi%[%hi%_%hi%z%hi~P'vOz(pO{%hi!x%hi#g%hi%[%hi%_%hi%z%hi~O!f&UOh&sa%[&saz&sa#[&sa#g&sa%_&sa#Z&sag&sa~O%[(uO~OV#sOa#tO%uWO~Oz&]O{wa~OopOvqO~P'vOz(^O#g%}a%[%}a%_%}ag%}a{%}a![%}a!m%}a%z%}a~P%SOz(zO#g%hX%[%hX%_%hX%z%hX~O%z#|O#gUi%[Ui%_Ui~O#g&Pa%[&Pa%_&Pan&Pa~P'vOz(}O#g&Pa%[&Pa%_&Pan&Pa~O%uWO#g&ra%[&ra%_&rag&ra~Oz)SO#g&ra%[&ra%_&rag&ra~Og)VO~OV)WOh$WO%uWO~O#Z)XO~O%uWO#g&ta%[&ta%_&ta~Oz)ZO#g&ta%[&ta%_&ta~Oo0cOv0qO#g&pa%[&pa%_&pa{&pa~P'vOz)^O#g&pa%[&pa%_&pa{&pa~OV)`Oa)`O%uWO~O%z)eO~Ot)hO#j)gOP#hiV#hif#hih#hio#his#hiv#hi!P#hi!Q#hi!T#hi!U#hi!X#hi!]#hi!h#hi!r#hi!s#hi!t#hi!{#hi!}#hi#P#hi#R#hi#T#hi#X#hi#Z#hi#^#hi#_#hi#a#hi#c#hi#l#hi#o#hi#s#hi#u#hi#z#hi#}#hi$P#hi%X#hi%o#hi%p#hi%t#hi%u#hi&Z#hi&[#hi&]#hi&^#hi&_#hi&`#hi&a#hi&b#hi&c#hi&d#hi&e#hi&f#hi&g#hi&h#hi&i#hi&j#hi%Z#hi%_#hi~Ot)iOP#kiV#kif#kih#kio#kis#kiv#ki!P#ki!Q#ki!T#ki!U#ki!X#ki!]#ki!h#ki!r#ki!s#ki!t#ki!{#ki!}#ki#P#ki#R#ki#T#ki#X#ki#Z#ki#^#ki#_#ki#a#ki#c#ki#l#ki#o#ki#s#ki#u#ki#z#ki#}#ki$P#ki%X#ki%o#ki%p#ki%t#ki%u#ki&Z#ki&[#ki&]#ki&^#ki&_#ki&`#ki&a#ki&b#ki&c#ki&d#ki&e#ki&f#ki&g#ki&h#ki&i#ki&j#ki%Z#ki%_#ki~OV)kOn&wa~P'vOz)lOn&wa~Oz)lOn&wa~P%SOn)pO~O%Y)tO~Ot)wO#p'WO#q)vOP#niV#nif#nih#nio#nis#niv#ni!P#ni!Q#ni!T#ni!U#ni!X#ni!]#ni!h#ni!r#ni!s#ni!t#ni!{#ni!}#ni#P#ni#R#ni#T#ni#X#ni#Z#ni#^#ni#_#ni#a#ni#c#ni#l#ni#o#ni#s#ni#u#ni#z#ni#}#ni$P#ni%X#ni%o#ni%p#ni%t#ni%u#ni&Z#ni&[#ni&]#ni&^#ni&_#ni&`#ni&a#ni&b#ni&c#ni&d#ni&e#ni&f#ni&g#ni&h#ni&i#ni&j#ni%Z#ni%_#ni~OV)zOo0cOv0qO{$jO~P'vOo0cOv0qO{&xa~P'vOz*OO{&xa~OV*SOa*TOg*WO%q*UO%uWO~O{$jO&{*YO~Oh'_O~Oh!iO{$jO~O%[*_O~O%[*aO%_*aO~OV$}Oa$}Oo0cOv0qOg&Ua~P'vOz*dOg&Ua~Oo0cOv0qO{*gO!W&Xa~P'vOz*hO!W&Xa~Oo0cOv0qOz*hO{*kO!W&Xa~P'vOo0cOv0qOz*hO!W&Xa~P'vOz*hO{*kO!W&Xa~Om0dOn0dOo0mOp0nOgjikjisjizji!Tji!Uji%{ji!Wji{ji![ji#gji%[ji%_ji!Qji#[jitji!mji%zji~Ol0fO~P!NkOlji~P!NkOV'|Og*pOo0cOv0qO~P'vOn*rO~Og*pOz*tO~Og*uO~OV'|Oo0cOv0qO!W&Si~P'vOz*vO!W&Si~O!W*wO~OV(]Oo0cOv0qO![%}i#g%}i%[%}i%_%}ig%}i{%}i!m%}i%z%}i~P'vOz*zO!T%dO!U%cO![&Ti~Oz*}O![%}i#g%}i%[%}i%_%}ig%}i{%}i!m%}i%z%}i~O![+OO~Oa+QOo0cOv0qO![&Ti~P'vOz*zO![&Ti~O![+SO~OV+UOo0cOv0qO{&la![&la!m&la%z&la~P'vOz+VO{&la![&la!m&la%z&la~O!]+YO&n+[O![!nX~O![+^O~O{(kO![+_O~O{(kO![+_O!m+`O~OV&OOopOvqO{%hq!x%hq#g%hq%[%hq%_%hq%z%hq~P'vOz$ri{$ri!x$ri#g$ri%[$ri%_$ri%z$ri~P%SOV&OOopOvqO~P'vOV&OOo0cOv0qO#g%ha%[%ha%_%ha%z%ha~P'vOz+aO#g%ha%[%ha%_%ha%z%ha~Oz$ia#g$ia%[$ia%_$ian$ia~P%SO#g&Pi%[&Pi%_&Pin&Pi~P'vOz+dO#g#Wq%[#Wq%_#Wq~O#[+eOz$va#g$va%[$va%_$vag$va~O%uWO#g&ri%[&ri%_&rig&ri~Oz+gO#g&ri%[&ri%_&rig&ri~OV+iOh$WO%uWO~O%uWO#g&ti%[&ti%_&ti~Oo0cOv0qO#g&pi%[&pi%_&pi{&pi~P'vO{#{Oz#eX!W#eX~Oz+mO!W&uX~O!W+oO~Ot+rO#j)gOP#hqV#hqf#hqh#hqo#hqs#hqv#hq!P#hq!Q#hq!T#hq!U#hq!X#hq!]#hq!h#hq!r#hq!s#hq!t#hq!{#hq!}#hq#P#hq#R#hq#T#hq#X#hq#Z#hq#^#hq#_#hq#a#hq#c#hq#l#hq#o#hq#s#hq#u#hq#z#hq#}#hq$P#hq%X#hq%o#hq%p#hq%t#hq%u#hq&Z#hq&[#hq&]#hq&^#hq&_#hq&`#hq&a#hq&b#hq&c#hq&d#hq&e#hq&f#hq&g#hq&h#hq&i#hq&j#hq%Z#hq%_#hq~On$|az$|a~P%SOV)kOn&wi~P'vOz+yOn&wi~Oz,TO{$jO#[,TO~O#q,VOP#nqV#nqf#nqh#nqo#nqs#nqv#nq!P#nq!Q#nq!T#nq!U#nq!X#nq!]#nq!h#nq!r#nq!s#nq!t#nq!{#nq!}#nq#P#nq#R#nq#T#nq#X#nq#Z#nq#^#nq#_#nq#a#nq#c#nq#l#nq#o#nq#s#nq#u#nq#z#nq#}#nq$P#nq%X#nq%o#nq%p#nq%t#nq%u#nq&Z#nq&[#nq&]#nq&^#nq&_#nq&`#nq&a#nq&b#nq&c#nq&d#nq&e#nq&f#nq&g#nq&h#nq&i#nq&j#nq%Z#nq%_#nq~O#[,WOz%Oa{%Oa~Oo0cOv0qO{&xi~P'vOz,YO{&xi~O{#{O%z,[Og&zXz&zX~O%uWOg&zXz&zX~Oz,`Og&yX~Og,bO~O%Y,eO~O!T%dO!U%cOg&Viz&Vi~OV$}Oa$}Oo0cOv0qOg&Ui~P'vO{,hOz$la!W$la~Oo0cOv0qO{,iOz$la!W$la~P'vOo0cOv0qO{*gO!W&Xi~P'vOz,lO!W&Xi~Oo0cOv0qOz,lO!W&Xi~P'vOz,lO{,oO!W&Xi~Og$hiz$hi!W$hi~P%SOV'|Oo0cOv0qO~P'vOn,qO~OV'|Og,rOo0cOv0qO~P'vOV'|Oo0cOv0qO!W&Sq~P'vOz$gi![$gi#g$gi%[$gi%_$gig$gi{$gi!m$gi%z$gi~P%SOV(]Oo0cOv0qO~P'vOa+QOo0cOv0qO![&Tq~P'vOz,sO![&Tq~O![,tO~OV(]Oo0cOv0qO![%}q#g%}q%[%}q%_%}qg%}q{%}q!m%}q%z%}q~P'vO{,uO~OV+UOo0cOv0qO{&li![&li!m&li%z&li~P'vOz,zO{&li![&li!m&li%z&li~O!]+YO&n+[O![!na~O{(kO![,}O~OV&OOo0cOv0qO#g%hi%[%hi%_%hi%z%hi~P'vOz-OO#g%hi%[%hi%_%hi%z%hi~O%uWO#g&rq%[&rq%_&rqg&rq~Oz-RO#g&rq%[&rq%_&rqg&rq~OV)`Oa)`O%uWO!W&ua~Oz-TO!W&ua~On$|iz$|i~P%SOV)kO~P'vOV)kOn&wq~P'vOt-XOP#myV#myf#myh#myo#mys#myv#my!P#my!Q#my!T#my!U#my!X#my!]#my!h#my!r#my!s#my!t#my!{#my!}#my#P#my#R#my#T#my#X#my#Z#my#^#my#_#my#a#my#c#my#l#my#o#my#s#my#u#my#z#my#}#my$P#my%X#my%o#my%p#my%t#my%u#my&Z#my&[#my&]#my&^#my&_#my&`#my&a#my&b#my&c#my&d#my&e#my&f#my&g#my&h#my&i#my&j#my%Z#my%_#my~O%Z-]O%_-]O~P`O#q-^OP#nyV#nyf#nyh#nyo#nys#nyv#ny!P#ny!Q#ny!T#ny!U#ny!X#ny!]#ny!h#ny!r#ny!s#ny!t#ny!{#ny!}#ny#P#ny#R#ny#T#ny#X#ny#Z#ny#^#ny#_#ny#a#ny#c#ny#l#ny#o#ny#s#ny#u#ny#z#ny#}#ny$P#ny%X#ny%o#ny%p#ny%t#ny%u#ny&Z#ny&[#ny&]#ny&^#ny&_#ny&`#ny&a#ny&b#ny&c#ny&d#ny&e#ny&f#ny&g#ny&h#ny&i#ny&j#ny%Z#ny%_#ny~Oz-aO{$jO#[-aO~Oo0cOv0qO{&xq~P'vOz-dO{&xq~O%z,[Og&zaz&za~O{#{Og&zaz&za~OV*SOa*TO%q*UO%uWOg&ya~Oz-hOg&ya~O$S-lO~OV$}Oa$}Oo0cOv0qO~P'vOo0cOv0qO{-mOz$li!W$li~P'vOo0cOv0qOz$li!W$li~P'vO{-mOz$li!W$li~Oo0cOv0qO{*gO~P'vOo0cOv0qO{*gO!W&Xq~P'vOz-pO!W&Xq~Oo0cOv0qOz-pO!W&Xq~P'vOs-sO!T%dO!U%cOg&Oq!W&Oq![&Oqz&Oq~P!/jOa+QOo0cOv0qO![&Ty~P'vOz$ji![$ji~P%SOa+QOo0cOv0qO~P'vOV+UOo0cOv0qO~P'vOV+UOo0cOv0qO{&lq![&lq!m&lq%z&lq~P'vO{(kO![-xO!m-yO%z-wO~OV&OOo0cOv0qO#g%hq%[%hq%_%hq%z%hq~P'vO%uWO#g&ry%[&ry%_&ryg&ry~OV)`Oa)`O%uWO!W&ui~Ot-}OP#m!RV#m!Rf#m!Rh#m!Ro#m!Rs#m!Rv#m!R!P#m!R!Q#m!R!T#m!R!U#m!R!X#m!R!]#m!R!h#m!R!r#m!R!s#m!R!t#m!R!{#m!R!}#m!R#P#m!R#R#m!R#T#m!R#X#m!R#Z#m!R#^#m!R#_#m!R#a#m!R#c#m!R#l#m!R#o#m!R#s#m!R#u#m!R#z#m!R#}#m!R$P#m!R%X#m!R%o#m!R%p#m!R%t#m!R%u#m!R&Z#m!R&[#m!R&]#m!R&^#m!R&_#m!R&`#m!R&a#m!R&b#m!R&c#m!R&d#m!R&e#m!R&f#m!R&g#m!R&h#m!R&i#m!R&j#m!R%Z#m!R%_#m!R~Oo0cOv0qO{&xy~P'vOV*SOa*TO%q*UO%uWOg&yi~O$S-lO%Z.VO%_.VO~OV.aOh._O!X.^O!].`O!h.YO!s.[O!t.[O%p.XO%uWO&Z]O&[]O&]]O&^]O&_]O&`]O&a]O&b]O~Oo0cOv0qOz$lq!W$lq~P'vO{.fOz$lq!W$lq~Oo0cOv0qO{*gO!W&Xy~P'vOz.gO!W&Xy~Oo0cOv.kO~P'vOs-sO!T%dO!U%cOg&Oy!W&Oy![&Oyz&Oy~P!/jO{(kO![.nO~O{(kO![.nO!m.oO~OV*SOa*TO%q*UO%uWO~Oh.tO!f.rOz$TX#[$TX%j$TXg$TX~Os$TX{$TX!W$TX![$TX~P$-bO%o.vO%p.vOs$UXz$UX{$UX#[$UX%j$UX!W$UXg$UX![$UX~O!h.xO~Oz.|O#[/OO%j.yOs&|X{&|X!W&|Xg&|X~Oa/RO~P$)zOh.tOs&}Xz&}X{&}X#[&}X%j&}X!W&}Xg&}X![&}X~Os/VO{$jO~Oo0cOv0qOz$ly!W$ly~P'vOo0cOv0qO{*gO!W&X!R~P'vOz/ZO!W&X!R~Og&RXs&RX!T&RX!U&RX!W&RX![&RXz&RX~P!/jOs-sO!T%dO!U%cOg&Qa!W&Qa![&Qaz&Qa~O{(kO![/^O~O!f.rOh$[as$[az$[a{$[a#[$[a%j$[a!W$[ag$[a![$[a~O!h/eO~O%o.vO%p.vOs$Uaz$Ua{$Ua#[$Ua%j$Ua!W$Uag$Ua![$Ua~O%j.yOs$Yaz$Ya{$Ya#[$Ya!W$Yag$Ya![$Ya~Os&|a{&|a!W&|ag&|a~P$)nOz/jOs&|a{&|a!W&|ag&|a~O!W/mO~Og/mO~O{/oO~O![/pO~Oo0cOv0qO{*gO!W&X!Z~P'vO{/sO~O%z/tO~P$-bOz/uO#[/OO%j.yOg'PX~Oz/uOg'PX~Og/wO~O!h/xO~O#[/OOs%Saz%Sa{%Sa%j%Sa!W%Sag%Sa![%Sa~O#[/OO%j.yOs%Waz%Wa{%Wa!W%Wag%Wa~Os&|i{&|i!W&|ig&|i~P$)nOz/zO#[/OO%j.yO!['Oa~Og'Pa~P$)nOz0SOg'Pa~Oa0UO!['Oi~P$)zOz0WO!['Oi~Oz0WO#[/OO%j.yO!['Oi~O#[/OO%j.yOg$biz$bi~O%z0ZO~P$-bO#[/OO%j.yOg%Vaz%Va~Og'Pi~P$)nO{0^O~Oa0UO!['Oq~P$)zOz0`O!['Oq~O#[/OO%j.yOz%Ui![%Ui~Oa0UO~P$)zOa0UO!['Oy~P$)zO#[/OO%j.yOg$ciz$ci~O#[/OO%j.yOz%Uq![%Uq~Oz+aO#g%ha%[%ha%_%ha%z%ha~P%SOV&OOo0cOv0qO~P'vOn0hO~Oo0hO~P'vO{0iO~Ot0jO~P!/jO&]&Z&j&h&i&g&f&d&e&c&b&`&a&_&^&[%u~",
@@ -49498,7 +50267,7 @@ var parser2 = LRParser.deserialize({
49498
50267
  });
49499
50268
 
49500
50269
  // src/adapters.ts
49501
- var phpEngine = new import_php_parser2.Engine({ parser: { extractDoc: false, php7: true }, ast: { withPositions: true, withSource: false } });
50270
+ var phpEngine = new import_php_parser4.Engine({ parser: { extractDoc: false, php7: true }, ast: { withPositions: true, withSource: false } });
49502
50271
  var PHP_SOURCES = [
49503
50272
  ["_GET", "http_parameter"],
49504
50273
  ["_POST", "http_body"],
@@ -49646,8 +50415,13 @@ var JS_SINKS = [
49646
50415
  [/document\.write/i, "html_render", "CWE-79"],
49647
50416
  [/fs\.writeFile/i, "file_operations", "CWE-434"],
49648
50417
  [/fs\.appendFile/i, "file_operations", "CWE-434"],
50418
+ [/fs\.readFile/i, "path_traversal", "CWE-22"],
50419
+ [/fs\.readFileSync/i, "path_traversal", "CWE-22"],
50420
+ [/fs\.unlink/i, "file_operations", "CWE-434"],
49649
50421
  [/require\s*\(/i, "file_inclusion", "CWE-98"],
49650
50422
  [/fetch\s*\(/i, "http_request", "CWE-918"],
50423
+ [/http\.get|https\.get|axios/i, "http_request", "CWE-918"],
50424
+ [/http\.request|https\.request/i, "http_request", "CWE-918"],
49651
50425
  [/redirect\s*\(/i, "redirect", "CWE-601"],
49652
50426
  [/res\.redirect/i, "redirect", "CWE-601"]
49653
50427
  ];
@@ -49734,6 +50508,8 @@ var jsAdapter = {
49734
50508
  argVars.push(c.name);
49735
50509
  for (const [re, kind, cwe] of JS_SINKS) {
49736
50510
  if (re.test(fullCallText) || re.test(calleeText + "(")) {
50511
+ if (kind === "sql_execution" && /\?/.test(fullCallText) && /,\s*\[/.test(fullCallText))
50512
+ continue;
49737
50513
  for (const v of argVars)
49738
50514
  sinks.push({ variable: v, kind, line: n.loc?.start?.line ?? 0, cwe });
49739
50515
  }
@@ -49772,6 +50548,8 @@ var PY_SINKS = [
49772
50548
  [/\.save\s*\(/i, "file_operations", "CWE-434"],
49773
50549
  [/render_template/i, "html_render", "CWE-79"],
49774
50550
  [/redirect\s*\(/i, "redirect", "CWE-601"],
50551
+ [/requests\.(get|post|put|head|request)\s*\(/i, "http_request", "CWE-918"],
50552
+ [/urllib\.request/i, "http_request", "CWE-918"],
49775
50553
  [/pickle\.loads\s*\(/i, "deserialization", "CWE-502"],
49776
50554
  [/yaml\.load\s*\(/i, "deserialization", "CWE-502"],
49777
50555
  [/os\.popen\s*\(/i, "command_execution", "CWE-78"],
@@ -49791,7 +50569,7 @@ var pythonAdapter = {
49791
50569
  language: "python",
49792
50570
  extensions: [".py", ".pyw"],
49793
50571
  parse(code, _file) {
49794
- const tree = parser2.parse(code);
50572
+ const tree = parser4.parse(code);
49795
50573
  const sources = [];
49796
50574
  const sinks = [];
49797
50575
  const sanitizers = [];
@@ -49856,9 +50634,14 @@ var pythonAdapter = {
49856
50634
  if (m[1] !== callee.trim().split(".").pop())
49857
50635
  argVars.push(m[1]);
49858
50636
  for (const [re, kind, cwe] of PY_SINKS) {
49859
- if (re.test(full))
49860
- for (const v of argVars)
49861
- sinks.push({ variable: v, kind, line: lineOf(n), cwe });
50637
+ if (!re.test(full))
50638
+ continue;
50639
+ if (kind === "sql_execution" && /\?/.test(full) && /,\s*\(/.test(full))
50640
+ continue;
50641
+ if (kind === "command_execution" && /subprocess/.test(full) && /\[/.test(full))
50642
+ continue;
50643
+ for (const v of argVars)
50644
+ sinks.push({ variable: v, kind, line: lineOf(n), cwe });
49862
50645
  }
49863
50646
  for (const [re, kinds] of PY_SANITIZERS) {
49864
50647
  if (re.test(full))
@@ -49894,6 +50677,10 @@ var JAVA_SINKS = [
49894
50677
  [/readObject\s*\(/i, "deserialization", "CWE-502"],
49895
50678
  [/new File\s*\(/i, "file_operations", "CWE-434"],
49896
50679
  [/\.getInputStream\s*\(/i, "http_request", "CWE-918"],
50680
+ [/new URL\s*\(/i, "http_request", "CWE-918"],
50681
+ [/openConnection\s*\(/i, "http_request", "CWE-918"],
50682
+ [/DocumentBuilder|SAXParser|XMLReader/i, "xml_processing", "CWE-611"],
50683
+ [/\.parse\s*\(/i, "xml_processing", "CWE-611"],
49897
50684
  [/sendRedirect\s*\(/i, "redirect", "CWE-601"],
49898
50685
  [/\.forward\s*\(/i, "redirect", "CWE-601"]
49899
50686
  ];
@@ -49961,6 +50748,195 @@ registerLanguage(jsAdapter);
49961
50748
  registerLanguage(pythonAdapter);
49962
50749
  registerLanguage(javaAdapter);
49963
50750
 
50751
+ // src/differential.ts
50752
+ init_scanner();
50753
+ function runEngine(code, language, file) {
50754
+ if (language === "php") {
50755
+ const dir = mkdtempSync(join9(tmpdir(), "blitz-diff-"));
50756
+ const tmp = join9(dir, "old.php");
50757
+ writeFileSync2(tmp, code);
50758
+ try {
50759
+ const r = analyzeDataFlow2(tmp);
50760
+ return r.findings.map((f) => ({ sink: f.sink, sink_line: f.sink_line, category: f.category, source: f.source, cwe: f.cwe }));
50761
+ } finally {
50762
+ rmSync(dir, { recursive: true, force: true });
50763
+ }
50764
+ }
50765
+ const extMap = { javascript: ".js", typescript: ".ts", python: ".py", java: ".java" };
50766
+ const probe = file.includes(".") ? file : `target${extMap[language] ?? ""}`;
50767
+ const r = analyzeTaintUniversal(code, probe);
50768
+ return r.findings.map((f) => ({ sink: f.sink, sink_line: f.sink_line, category: f.sink, source: f.source_kind, cwe: f.cwe }));
50769
+ }
50770
+ function diffLines(oldText, newText) {
50771
+ const a = oldText.split(`
50772
+ `);
50773
+ const b = newText.split(`
50774
+ `);
50775
+ const m = a.length;
50776
+ const n = b.length;
50777
+ const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
50778
+ for (let i = m - 1;i >= 0; i--) {
50779
+ for (let j = n - 1;j >= 0; j--) {
50780
+ dp[i][j] = a[i] === b[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
50781
+ }
50782
+ }
50783
+ const added = [];
50784
+ const removed = [];
50785
+ let i = 0;
50786
+ let j = 0;
50787
+ while (i < m && j < n) {
50788
+ if (a[i] === b[j]) {
50789
+ i++;
50790
+ j++;
50791
+ } else if (dp[i + 1][j] >= dp[i][j + 1]) {
50792
+ removed.push({ line: i + 1, text: a[i] });
50793
+ i++;
50794
+ } else {
50795
+ added.push({ line: j + 1, text: b[j] });
50796
+ j++;
50797
+ }
50798
+ }
50799
+ while (i < m) {
50800
+ removed.push({ line: i + 1, text: a[i] });
50801
+ i++;
50802
+ }
50803
+ while (j < n) {
50804
+ added.push({ line: j + 1, text: b[j] });
50805
+ j++;
50806
+ }
50807
+ return { added, removed };
50808
+ }
50809
+ function analyzeDifferential(oldCode, newCode, language, file = "target") {
50810
+ const changes = [];
50811
+ const oldFindings = runEngine(oldCode, language, file);
50812
+ const newFindings = runEngine(newCode, language, file);
50813
+ const key = (f) => `${f.category}|${f.sink}|${f.sink_line}`;
50814
+ const oldKeys = new Set(oldFindings.map(key));
50815
+ const newKeys = new Set(newFindings.map(key));
50816
+ for (const f of newFindings) {
50817
+ if (!oldKeys.has(key(f))) {
50818
+ changes.push({
50819
+ kind: "new_vulnerability",
50820
+ severity: "high",
50821
+ sink: f.sink,
50822
+ category: f.category,
50823
+ source: f.source,
50824
+ cwe: f.cwe,
50825
+ line: f.sink_line,
50826
+ detail: `new ${f.category} at line ${f.sink_line} (${f.sink.trim()})`
50827
+ });
50828
+ }
50829
+ }
50830
+ for (const f of oldFindings) {
50831
+ if (!newKeys.has(key(f))) {
50832
+ changes.push({
50833
+ kind: "fixed_vulnerability",
50834
+ severity: "low",
50835
+ sink: f.sink,
50836
+ category: f.category,
50837
+ source: f.source,
50838
+ cwe: f.cwe,
50839
+ line: f.sink_line,
50840
+ detail: `removed ${f.category} at line ${f.sink_line} (${f.sink.trim()})`
50841
+ });
50842
+ }
50843
+ }
50844
+ const { added, removed } = diffLines(oldCode, newCode);
50845
+ for (const l of added) {
50846
+ const sink = classifySink2(l.text);
50847
+ if (sink) {
50848
+ changes.push({
50849
+ kind: "new_sink",
50850
+ severity: "medium",
50851
+ sink: l.text.trim(),
50852
+ category: sink.category,
50853
+ cwe: sink.cwe,
50854
+ line: l.line,
50855
+ detail: `added sink ${l.text.trim()} (${sink.category})`
50856
+ });
50857
+ }
50858
+ const source = classifySource(l.text);
50859
+ if (source) {
50860
+ changes.push({
50861
+ kind: "new_source",
50862
+ severity: source.attacker_controlled ? "medium" : "low",
50863
+ source: source.label,
50864
+ line: l.line,
50865
+ detail: `added source ${l.text.trim()} (${source.label})`
50866
+ });
50867
+ }
50868
+ }
50869
+ for (const l of removed) {
50870
+ const san = findSanitizers(l.text);
50871
+ if (san.length > 0) {
50872
+ changes.push({
50873
+ kind: "sanitizer_removed",
50874
+ severity: "high",
50875
+ line: l.line,
50876
+ detail: `removed sanitizer ${san.map((s) => s.label).join(", ")} (${l.text.trim()})`
50877
+ });
50878
+ }
50879
+ const gates = AUTH_GATES.filter((g) => l.text.includes(g));
50880
+ if (gates.length > 0) {
50881
+ changes.push({
50882
+ kind: "authorization_removed",
50883
+ severity: "high",
50884
+ line: l.line,
50885
+ detail: `removed authorization gate ${gates.join(", ")} (${l.text.trim()})`
50886
+ });
50887
+ }
50888
+ }
50889
+ const rank = { high: 0, medium: 1, low: 2 };
50890
+ changes.sort((x, y) => rank[x.severity] - rank[y.severity] || x.line - y.line);
50891
+ const count = (k) => changes.filter((c) => c.kind === k).length;
50892
+ return {
50893
+ language,
50894
+ changes,
50895
+ summary: {
50896
+ new_vulnerabilities: count("new_vulnerability"),
50897
+ fixed_vulnerabilities: count("fixed_vulnerability"),
50898
+ new_sinks: count("new_sink"),
50899
+ new_sources: count("new_source"),
50900
+ sanitizers_removed: count("sanitizer_removed"),
50901
+ authorizations_removed: count("authorization_removed")
50902
+ }
50903
+ };
50904
+ }
50905
+ function languageOf(file) {
50906
+ const adapter = detectLanguage(file);
50907
+ return adapter?.language ?? "php";
50908
+ }
50909
+ function analyzeDifferentialFiles(oldPath, newPath, language) {
50910
+ const oldCode = readFileSync13(oldPath, "utf8");
50911
+ const newCode = readFileSync13(newPath, "utf8");
50912
+ const lang = language ?? languageOf(newPath);
50913
+ return analyzeDifferential(oldCode, newCode, lang, newPath);
50914
+ }
50915
+ var SOURCE_EXTS = [".php", ".phtml", ".php5", ".js", ".mjs", ".ts", ".tsx", ".py", ".pyw", ".java"];
50916
+ function analyzeGitDiff(repo, base = "HEAD~1", head = "HEAD") {
50917
+ const git = (args) => {
50918
+ try {
50919
+ return execSync(`git ${args}`, { cwd: repo, encoding: "utf8", maxBuffer: 50 * 1024 * 1024 }).trim();
50920
+ } catch {
50921
+ return "";
50922
+ }
50923
+ };
50924
+ const changed = git(`diff --name-only ${base} ${head}`).split(`
50925
+ `).filter((f) => f && SOURCE_EXTS.some((e) => f.endsWith(e)));
50926
+ const files = [];
50927
+ for (const file of changed) {
50928
+ const oldCode = git(`show ${base}:${file}`);
50929
+ const newCode = git(`show ${head}:${file}`);
50930
+ if (!newCode)
50931
+ continue;
50932
+ const lang = languageOf(file);
50933
+ files.push({ file, result: analyzeDifferential(oldCode || "", newCode, lang, file) });
50934
+ }
50935
+ const total_changes = files.reduce((n, f) => n + f.result.changes.length, 0);
50936
+ const security_sensitive = files.reduce((n, f) => n + f.result.changes.filter((c) => c.severity === "high").length, 0);
50937
+ return { repo, base, head, files, total_changes, security_sensitive };
50938
+ }
50939
+
49964
50940
  // src/guidance.ts
49965
50941
  var SINK_DIRECTIVES = {
49966
50942
  sql_execution: "Validate the SQL injection live with strike_verify (use a unique MARKER and a NEGATIVE CONTROL that stays inert), or read_tool_manual for sqlmap. Only a reflected marker + inert control = confirmed.",
@@ -50774,16 +51750,16 @@ function reportJson(findings, opts = {}) {
50774
51750
  }
50775
51751
 
50776
51752
  // src/benchmark.ts
50777
- import { readFileSync as readFileSync11, readdirSync as readdirSync4, writeFileSync as writeFileSync2, rmSync } from "node:fs";
50778
- import { join as join9 } from "node:path";
51753
+ import { readFileSync as readFileSync14, readdirSync as readdirSync4, writeFileSync as writeFileSync3, rmSync as rmSync2 } from "node:fs";
51754
+ import { join as join10 } from "node:path";
50779
51755
  import { fileURLToPath as fileURLToPath6 } from "node:url";
50780
- import { tmpdir } from "node:os";
50781
- var ROOT4 = join9(fileURLToPath6(new URL(".", import.meta.url)), "..");
50782
- var CORPUS = join9(ROOT4, "bench", "corpus");
51756
+ import { tmpdir as tmpdir2 } from "node:os";
51757
+ var ROOT4 = join10(fileURLToPath6(new URL(".", import.meta.url)), "..");
51758
+ var CORPUS = join10(ROOT4, "bench", "corpus");
50783
51759
  function parseCorpusFile(path) {
50784
51760
  let text;
50785
51761
  try {
50786
- text = readFileSync11(path, "utf8");
51762
+ text = readFileSync14(path, "utf8");
50787
51763
  } catch {
50788
51764
  return null;
50789
51765
  }
@@ -50833,7 +51809,7 @@ function loadCorpus() {
50833
51809
  for (const f of readdirSync4(CORPUS)) {
50834
51810
  if (!f.endsWith(".md"))
50835
51811
  continue;
50836
- const e = parseCorpusFile(join9(CORPUS, f));
51812
+ const e = parseCorpusFile(join10(CORPUS, f));
50837
51813
  if (e)
50838
51814
  entries.push(e);
50839
51815
  }
@@ -50845,10 +51821,10 @@ function loadCorpus() {
50845
51821
  function detect(entry) {
50846
51822
  const lang = entry.language;
50847
51823
  if (lang === "php") {
50848
- const tmp = join9(tmpdir(), `blitzstrike-bench-${entry.id}-${process.pid}.php`);
50849
- writeFileSync2(tmp, entry.code);
50850
- const r = analyzeTaint(tmp);
50851
- rmSync(tmp, { force: true });
51824
+ const tmp = join10(tmpdir2(), `blitzstrike-bench-${entry.id}-${process.pid}.php`);
51825
+ writeFileSync3(tmp, entry.code);
51826
+ const r = analyzeDataFlow2(tmp);
51827
+ rmSync2(tmp, { force: true });
50852
51828
  if (r.findings.length > 0)
50853
51829
  return { detected: true, sinkKind: r.findings[0].sink };
50854
51830
  return { detected: false };
@@ -51631,6 +52607,68 @@ function createServer() {
51631
52607
  });
51632
52608
  return { content: [{ type: "text", text: JSON.stringify({ ...r, next_steps: guidance }) }] };
51633
52609
  });
52610
+ server.registerTool("eagle_eye2", {
52611
+ title: "Whole-program interprocedural taint (EAGLE-EYE 2.0)",
52612
+ description: "EAGLE-EYE 2.0: whole-program data-flow on a PHP AST — call-graph-aware interprocedural taint with return propagation, by-reference alias tracking, ternary/conditional merge, context-sensitive sanitizers, and authorization-gate detection. Prefer this over taint_scan for accurate cross-function reachability.",
52613
+ inputSchema: { path: string2().describe("Source file path (PHP)") }
52614
+ }, async ({ path }) => {
52615
+ const r = analyzeDataFlow2(path);
52616
+ const taintedSinks = [...new Set(r.findings.map((f) => f.sink))];
52617
+ const authGated = r.findings.filter((f) => f.auth_gated).length;
52618
+ const guidance = nextSteps({
52619
+ tier: "eagle-eye",
52620
+ hasFindings: r.findings.length > 0,
52621
+ sanitizedCount: r.suppressed,
52622
+ taintedSinks
52623
+ });
52624
+ return {
52625
+ content: [{
52626
+ type: "text",
52627
+ text: JSON.stringify({
52628
+ file: r.file,
52629
+ findings: r.findings.length,
52630
+ suppressed: r.suppressed,
52631
+ auth_gated: authGated,
52632
+ interprocedural: r.findings.filter((f) => f.interprocedural).length,
52633
+ functions: r.summary.functions,
52634
+ methods: r.summary.methods,
52635
+ call_edges: r.summary.edges,
52636
+ entry_points: r.summary.entry_points,
52637
+ unreachable: r.summary.unreachable,
52638
+ results: r.findings,
52639
+ next_steps: guidance
52640
+ })
52641
+ }]
52642
+ };
52643
+ });
52644
+ server.registerTool("diff_analyze", {
52645
+ title: "Differential security analysis",
52646
+ description: "PHASE 4: compare two versions of code (files or a git commit range) and surface only security-sensitive changes — new vulnerabilities, fixed vulnerabilities, new sinks/sources, removed sanitizers, and removed authorization gates.",
52647
+ inputSchema: {
52648
+ old_path: string2().optional().describe("Old file path"),
52649
+ new_path: string2().optional().describe("New file path"),
52650
+ old_code: string2().optional().describe("Old source code (when not using paths)"),
52651
+ new_code: string2().optional().describe("New source code (when not using paths)"),
52652
+ language: string2().optional().describe("Language (php/javascript/python/java); auto-detected from path if omitted"),
52653
+ repo: string2().optional().describe("Git repo path (for git-diff mode)"),
52654
+ base: string2().optional().describe("Git base ref (default HEAD~1)"),
52655
+ head: string2().optional().describe("Git head ref (default HEAD)")
52656
+ }
52657
+ }, async ({ old_path, new_path, old_code, new_code, language, repo, base, head }) => {
52658
+ if (repo) {
52659
+ const r = analyzeGitDiff(repo, base ?? "HEAD~1", head ?? "HEAD");
52660
+ return { content: [{ type: "text", text: JSON.stringify(r) }] };
52661
+ }
52662
+ let result;
52663
+ if (old_path && new_path) {
52664
+ result = analyzeDifferentialFiles(old_path, new_path, language);
52665
+ } else if (old_code !== undefined && new_code !== undefined) {
52666
+ result = analyzeDifferential(old_code, new_code, language ?? "php", new_path ?? "target");
52667
+ } else {
52668
+ return { content: [{ type: "text", text: JSON.stringify({ error: "provide (old_path+new_path), (old_code+new_code), or (repo)" }) }] };
52669
+ }
52670
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
52671
+ });
51634
52672
  server.registerTool("taint_tree", {
51635
52673
  title: "Whole-tree taint scan",
51636
52674
  description: "EAGLE-EYE: run inter-procedural taint analysis across an entire source tree.",
@@ -51784,12 +52822,12 @@ async function serve() {
51784
52822
  }
51785
52823
 
51786
52824
  // src/cli.ts
51787
- import { readFileSync as readFileSync13, existsSync as existsSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "node:fs";
51788
- import { join as join11, dirname as dirname2 } from "node:path";
52825
+ import { readFileSync as readFileSync16, existsSync as existsSync6, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4 } from "node:fs";
52826
+ import { join as join12, dirname as dirname2 } from "node:path";
51789
52827
  import { homedir as homedir5 } from "node:os";
51790
52828
  import { fileURLToPath as fileURLToPath8 } from "node:url";
51791
52829
  import { spawnSync as spawnSync3 } from "node:child_process";
51792
- var ROOT6 = join11(fileURLToPath8(new URL(".", import.meta.url)), "..");
52830
+ var ROOT6 = join12(fileURLToPath8(new URL(".", import.meta.url)), "..");
51793
52831
  function which(cmd) {
51794
52832
  return spawnSync3(`command -v ${cmd}`, { shell: true }).status === 0;
51795
52833
  }
@@ -51824,7 +52862,7 @@ function runDoctor() {
51824
52862
  detail: fofa ? "set" : "FOFA_EMAIL/FOFA_KEY not set",
51825
52863
  fix: fofa ? undefined : "export FOFA_EMAIL=... && export FOFA_KEY=... (enables fofa_search)"
51826
52864
  });
51827
- const dataOk = existsSync6(join11(ROOT6, "chains.json")) && existsSync6(join11(ROOT6, "tools-catalog.json"));
52865
+ const dataOk = existsSync6(join12(ROOT6, "chains.json")) && existsSync6(join12(ROOT6, "tools-catalog.json"));
51828
52866
  issues.push({
51829
52867
  name: "Data layers (chains + tools-catalog)",
51830
52868
  status: dataOk ? "ok" : "fail",
@@ -51852,21 +52890,21 @@ BlitzStrike — ${verdict}`);
51852
52890
  function resolveCommand() {
51853
52891
  if (which("blitzstrike"))
51854
52892
  return { command: "blitzstrike", args: ["serve", "--mcp"] };
51855
- const src = join11(ROOT6, "src", "index.ts");
52893
+ const src = join12(ROOT6, "src", "index.ts");
51856
52894
  if (which("bun") && existsSync6(src))
51857
52895
  return { command: "bun", args: ["run", src, "serve", "--mcp"] };
51858
52896
  if (which("npx"))
51859
52897
  return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
51860
52898
  if (which("bunx"))
51861
52899
  return { command: "bunx", args: ["blitzstrike", "serve", "--mcp"] };
51862
- const dist = join11(ROOT6, "dist", "index.js");
52900
+ const dist = join12(ROOT6, "dist", "index.js");
51863
52901
  if (existsSync6(dist))
51864
52902
  return { command: "bun", args: [dist, "serve", "--mcp"] };
51865
52903
  return { command: "npx", args: ["-y", "blitzstrike", "serve", "--mcp"] };
51866
52904
  }
51867
52905
  function readJson(p) {
51868
52906
  try {
51869
- return JSON.parse(readFileSync13(p, "utf8"));
52907
+ return JSON.parse(readFileSync16(p, "utf8"));
51870
52908
  } catch {
51871
52909
  return null;
51872
52910
  }
@@ -51881,7 +52919,7 @@ function jsonMcpServersWrite(p) {
51881
52919
  ...existing.mcpServers ?? {},
51882
52920
  blitzstrike: { command, args }
51883
52921
  };
51884
- writeFileSync4(p, JSON.stringify(existing, null, 2));
52922
+ writeFileSync5(p, JSON.stringify(existing, null, 2));
51885
52923
  };
51886
52924
  }
51887
52925
  function opencodeWrite(p) {
@@ -51894,22 +52932,22 @@ function opencodeWrite(p) {
51894
52932
  ...existing.mcp ?? {},
51895
52933
  blitzstrike: { type: "local", command: ["npx", "-y", "blitzstrike", "serve", "--mcp"], enabled: true }
51896
52934
  };
51897
- writeFileSync4(p, JSON.stringify(existing, null, 2));
52935
+ writeFileSync5(p, JSON.stringify(existing, null, 2));
51898
52936
  copyOpenCodeAgents();
51899
52937
  };
51900
52938
  }
51901
52939
  function copyOpenCodeAgents() {
51902
- const srcDir = join11(ROOT6, "opencode-agents");
51903
- const dstDir = join11(homedir5(), ".config", "opencode", "agents");
52940
+ const srcDir = join12(ROOT6, "opencode-agents");
52941
+ const dstDir = join12(homedir5(), ".config", "opencode", "agents");
51904
52942
  if (!existsSync6(srcDir))
51905
52943
  return;
51906
52944
  if (!existsSync6(dstDir))
51907
52945
  mkdirSync4(dstDir, { recursive: true });
51908
52946
  for (const f of ["Blitz Strike.md", "Blitz.md", "Eagle Eye.md", "Strike.md"]) {
51909
- const src = join11(srcDir, f);
51910
- const dst = join11(dstDir, f);
52947
+ const src = join12(srcDir, f);
52948
+ const dst = join12(dstDir, f);
51911
52949
  if (existsSync6(src)) {
51912
- writeFileSync4(dst, readFileSync13(src, "utf8"));
52950
+ writeFileSync5(dst, readFileSync16(src, "utf8"));
51913
52951
  }
51914
52952
  }
51915
52953
  }
@@ -51918,7 +52956,7 @@ function codexWrite(p) {
51918
52956
  const dir = dirname2(p);
51919
52957
  if (!existsSync6(dir))
51920
52958
  mkdirSync4(dir, { recursive: true });
51921
- let existing = existsSync6(p) ? readFileSync13(p, "utf8") : "";
52959
+ let existing = existsSync6(p) ? readFileSync16(p, "utf8") : "";
51922
52960
  if (!existing.trimEnd().endsWith(`
51923
52961
  `))
51924
52962
  existing += `
@@ -51929,7 +52967,7 @@ function codexWrite(p) {
51929
52967
  command = "${command}"
51930
52968
  args = ${JSON.stringify(args)}
51931
52969
  `;
51932
- writeFileSync4(p, existing);
52970
+ writeFileSync5(p, existing);
51933
52971
  };
51934
52972
  }
51935
52973
  function hermesWrite(p) {
@@ -51937,7 +52975,7 @@ function hermesWrite(p) {
51937
52975
  const dir = dirname2(p);
51938
52976
  if (!existsSync6(dir))
51939
52977
  mkdirSync4(dir, { recursive: true });
51940
- let existing = existsSync6(p) ? readFileSync13(p, "utf8") : "";
52978
+ let existing = existsSync6(p) ? readFileSync16(p, "utf8") : "";
51941
52979
  existing = existing.replace(/^ blitzstrike:\n(?: .*\n?)*/m, "");
51942
52980
  if (!existing.trimEnd().endsWith(`
51943
52981
  `))
@@ -51958,80 +52996,80 @@ mcp_servers:
51958
52996
  args: ${JSON.stringify(args)}
51959
52997
  `;
51960
52998
  }
51961
- writeFileSync4(p, existing);
52999
+ writeFileSync5(p, existing);
51962
53000
  };
51963
53001
  }
51964
53002
  function detectAgents() {
51965
53003
  const home = homedir5();
51966
53004
  const agents = [];
51967
- const claudeJson = join11(home, ".claude.json");
53005
+ const claudeJson = join12(home, ".claude.json");
51968
53006
  agents.push({
51969
53007
  name: "Claude Code",
51970
53008
  detectPath: claudeJson,
51971
53009
  installed: () => existsSync6(claudeJson) || which("claude"),
51972
53010
  write: jsonMcpServersWrite(claudeJson)
51973
53011
  });
51974
- const claudeDesktop = join11(home, ".config", "Claude", "claude_desktop_config.json");
53012
+ const claudeDesktop = join12(home, ".config", "Claude", "claude_desktop_config.json");
51975
53013
  agents.push({
51976
53014
  name: "Claude Desktop",
51977
53015
  detectPath: claudeDesktop,
51978
53016
  installed: () => existsSync6(claudeDesktop),
51979
53017
  write: jsonMcpServersWrite(claudeDesktop)
51980
53018
  });
51981
- const cursor = join11(home, ".cursor", "mcp.json");
53019
+ const cursor = join12(home, ".cursor", "mcp.json");
51982
53020
  agents.push({
51983
53021
  name: "Cursor",
51984
53022
  detectPath: cursor,
51985
- installed: () => existsSync6(join11(home, ".cursor")) || which("cursor"),
53023
+ installed: () => existsSync6(join12(home, ".cursor")) || which("cursor"),
51986
53024
  write: jsonMcpServersWrite(cursor)
51987
53025
  });
51988
- const opencode = join11(home, ".config", "opencode", "opencode.jsonc");
53026
+ const opencode = join12(home, ".config", "opencode", "opencode.jsonc");
51989
53027
  agents.push({
51990
53028
  name: "OpenCode",
51991
53029
  detectPath: opencode,
51992
- installed: () => existsSync6(join11(home, ".config", "opencode")) || which("opencode"),
53030
+ installed: () => existsSync6(join12(home, ".config", "opencode")) || which("opencode"),
51993
53031
  write: opencodeWrite(opencode)
51994
53032
  });
51995
- const codex = join11(home, ".codex", "config.toml");
53033
+ const codex = join12(home, ".codex", "config.toml");
51996
53034
  agents.push({
51997
53035
  name: "Codex",
51998
53036
  detectPath: codex,
51999
- installed: () => existsSync6(join11(home, ".codex")) || which("codex"),
53037
+ installed: () => existsSync6(join12(home, ".codex")) || which("codex"),
52000
53038
  write: codexWrite(codex)
52001
53039
  });
52002
- const hermes = join11(home, ".hermes", "config.yaml");
53040
+ const hermes = join12(home, ".hermes", "config.yaml");
52003
53041
  agents.push({
52004
53042
  name: "Hermes",
52005
53043
  detectPath: hermes,
52006
- installed: () => existsSync6(join11(home, ".hermes")) || which("hermes"),
53044
+ installed: () => existsSync6(join12(home, ".hermes")) || which("hermes"),
52007
53045
  write: hermesWrite(hermes)
52008
53046
  });
52009
- const gemini = join11(home, ".gemini", "settings.json");
53047
+ const gemini = join12(home, ".gemini", "settings.json");
52010
53048
  agents.push({
52011
53049
  name: "Gemini CLI",
52012
53050
  detectPath: gemini,
52013
- installed: () => existsSync6(join11(home, ".gemini")) || which("gemini"),
53051
+ installed: () => existsSync6(join12(home, ".gemini")) || which("gemini"),
52014
53052
  write: jsonMcpServersWrite(gemini)
52015
53053
  });
52016
- const windsurf = join11(home, ".codeium", "windsurf", "mcp_config.json");
53054
+ const windsurf = join12(home, ".codeium", "windsurf", "mcp_config.json");
52017
53055
  agents.push({
52018
53056
  name: "Windsurf",
52019
53057
  detectPath: windsurf,
52020
- installed: () => existsSync6(join11(home, ".codeium")) || which("windsurf"),
53058
+ installed: () => existsSync6(join12(home, ".codeium")) || which("windsurf"),
52021
53059
  write: jsonMcpServersWrite(windsurf)
52022
53060
  });
52023
- const copilot = join11(home, ".copilot", "mcp.json");
53061
+ const copilot = join12(home, ".copilot", "mcp.json");
52024
53062
  agents.push({
52025
53063
  name: "Copilot",
52026
53064
  detectPath: copilot,
52027
- installed: () => existsSync6(join11(home, ".copilot")),
53065
+ installed: () => existsSync6(join12(home, ".copilot")),
52028
53066
  write: jsonMcpServersWrite(copilot)
52029
53067
  });
52030
- const cline = join11(home, ".cline", "mcp_settings.json");
53068
+ const cline = join12(home, ".cline", "mcp_settings.json");
52031
53069
  agents.push({
52032
53070
  name: "Cline",
52033
53071
  detectPath: cline,
52034
- installed: () => existsSync6(join11(home, ".cline")),
53072
+ installed: () => existsSync6(join12(home, ".cline")),
52035
53073
  write: jsonMcpServersWrite(cline)
52036
53074
  });
52037
53075
  return agents;
@@ -52075,15 +53113,15 @@ Registered with ${ok}/${installed.length} agent(s).`);
52075
53113
  }
52076
53114
 
52077
53115
  // src/index.ts
52078
- import { readFileSync as readFileSync14, existsSync as existsSync7 } from "node:fs";
52079
- import { join as join12 } from "node:path";
53116
+ import { readFileSync as readFileSync17, existsSync as existsSync7 } from "node:fs";
53117
+ import { join as join13 } from "node:path";
52080
53118
  import { fileURLToPath as fileURLToPath9 } from "node:url";
52081
- var ROOT7 = join12(fileURLToPath9(new URL(".", import.meta.url)), "..");
53119
+ var ROOT7 = join13(fileURLToPath9(new URL(".", import.meta.url)), "..");
52082
53120
  function readVersion() {
52083
53121
  try {
52084
- const p = join12(ROOT7, "package.json");
53122
+ const p = join13(ROOT7, "package.json");
52085
53123
  if (existsSync7(p))
52086
- return JSON.parse(readFileSync14(p, "utf8")).version ?? "1.0.0";
53124
+ return JSON.parse(readFileSync17(p, "utf8")).version ?? "1.0.0";
52087
53125
  } catch {}
52088
53126
  return "1.0.0";
52089
53127
  }