circle-ir 3.216.0 → 4.2.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 (49) hide show
  1. package/README.md +15 -1
  2. package/dist/analysis/config-loader.d.ts.map +1 -1
  3. package/dist/analysis/config-loader.js +68 -0
  4. package/dist/analysis/config-loader.js.map +1 -1
  5. package/dist/analysis/findings.d.ts.map +1 -1
  6. package/dist/analysis/findings.js +15 -9
  7. package/dist/analysis/findings.js.map +1 -1
  8. package/dist/analysis/note-coalescer.d.ts +0 -4
  9. package/dist/analysis/note-coalescer.d.ts.map +1 -1
  10. package/dist/analysis/note-coalescer.js +36 -1
  11. package/dist/analysis/note-coalescer.js.map +1 -1
  12. package/dist/analysis/passes/language-sources-pass.d.ts.map +1 -1
  13. package/dist/analysis/passes/language-sources-pass.js +54 -1
  14. package/dist/analysis/passes/language-sources-pass.js.map +1 -1
  15. package/dist/analysis/passes/sink-filter-pass.d.ts.map +1 -1
  16. package/dist/analysis/passes/sink-filter-pass.js +178 -0
  17. package/dist/analysis/passes/sink-filter-pass.js.map +1 -1
  18. package/dist/analysis/passes/taint-propagation-pass.js +1 -1
  19. package/dist/analysis/passes/taint-propagation-pass.js.map +1 -1
  20. package/dist/analysis/taint-matcher.d.ts.map +1 -1
  21. package/dist/analysis/taint-matcher.js +18 -3
  22. package/dist/analysis/taint-matcher.js.map +1 -1
  23. package/dist/browser/circle-ir.js +573 -17
  24. package/dist/core/circle-ir-core.cjs +338 -4
  25. package/dist/core/circle-ir-core.js +338 -4
  26. package/dist/core/extractors/calls.d.ts.map +1 -1
  27. package/dist/core/extractors/calls.js +133 -0
  28. package/dist/core/extractors/calls.js.map +1 -1
  29. package/dist/core/extractors/dfg.d.ts.map +1 -1
  30. package/dist/core/extractors/dfg.js +86 -1
  31. package/dist/core/extractors/dfg.js.map +1 -1
  32. package/dist/core/extractors/types.d.ts.map +1 -1
  33. package/dist/core/extractors/types.js +89 -0
  34. package/dist/core/extractors/types.js.map +1 -1
  35. package/dist/languages/plugins/csharp.d.ts +35 -0
  36. package/dist/languages/plugins/csharp.d.ts.map +1 -0
  37. package/dist/languages/plugins/csharp.js +72 -0
  38. package/dist/languages/plugins/csharp.js.map +1 -0
  39. package/dist/languages/plugins/index.d.ts +1 -0
  40. package/dist/languages/plugins/index.d.ts.map +1 -1
  41. package/dist/languages/plugins/index.js +3 -0
  42. package/dist/languages/plugins/index.js.map +1 -1
  43. package/dist/languages/types.d.ts +1 -1
  44. package/dist/languages/types.d.ts.map +1 -1
  45. package/dist/types/index.d.ts +1 -1
  46. package/dist/types/index.d.ts.map +1 -1
  47. package/dist/wasm/tree-sitter-csharp.wasm +0 -0
  48. package/docs/SPEC.md +1 -1
  49. package/package.json +1 -1
package/README.md CHANGED
@@ -8,7 +8,7 @@ A high-performance Static Application Security Testing (SAST) library for detect
8
8
  ## Features
9
9
 
10
10
  - **Taint Analysis**: Track data flow from sources (user input) to sinks (dangerous operations)
11
- - **Multi-language Support**: Java, JavaScript/TypeScript, Python, Go, Rust, Bash/Shell, HTML
11
+ - **Multi-language Support**: Java, JavaScript/TypeScript, Python, Go, Rust, Bash/Shell, HTML, and **C#/.NET (experimental)**
12
12
  - **High Accuracy**: 100% on OWASP Benchmark, 100% on Juliet Test Suite, 97.7% TPR on SecuriBench Micro
13
13
  - **36-Pass Pipeline**: 19 security taint passes + 17 reliability/performance/maintainability/architecture quality passes
14
14
  - **Metrics Engine**: 24 software quality metrics (cyclomatic complexity, Halstead, CBO, RFC, LCOM, DIT, and 4 composite scores)
@@ -209,6 +209,17 @@ const response = await analyzeForAPI(code, 'File.java', 'java');
209
209
  | **Rust** | tree-sitter-rust | Actix-web, Rocket, Axum |
210
210
  | **Bash/Shell** | tree-sitter-bash | Shell scripts (.sh, .bash, .zsh, .ksh) |
211
211
  | **HTML** | tree-sitter-html | Web extraction preprocessor (.html, .htm, .xhtml) |
212
+ | **C#/.NET** _(experimental)_ | tree-sitter-c-sharp | ASP.NET Core, ADO.NET, EF Core |
213
+
214
+ **C#/.NET support is experimental / preview** (since 4.0.0). It performs
215
+ straight-line taint analysis across 10 CWE families — SQL injection, command
216
+ injection, path traversal, SSRF, code injection, XSS, insecure deserialization,
217
+ LDAP, XPath, XXE — on ASP.NET Core / ADO.NET / EF Core / BCL, handling string
218
+ concatenation and `$"…{tainted}…"` interpolation, with sink-type-aware
219
+ sanitizer recognition (`HtmlEncode`, `Path.GetFileName`). It is **not yet
220
+ benchmark-verified** (no published TPR/FPR); expect gaps in branch/alias
221
+ precision and detector breadth. See `docs/PASSES.md` and the CHANGELOG for
222
+ scope.
212
223
 
213
224
  HTML is handled as a preprocessor: `<script>` blocks are extracted and analyzed as JavaScript, inline event handlers are analyzed as JS snippets, and 8 attribute-level security checks (missing noopener, javascript: URIs, missing sandbox/SRI, mixed content, etc.) run directly on the HTML AST.
214
225
 
@@ -227,6 +238,9 @@ const goResult = await analyze(goCode, 'main.go', 'go');
227
238
  // Analyze Rust
228
239
  const rsResult = await analyze(rsCode, 'main.rs', 'rust');
229
240
 
241
+ // Analyze C#/.NET (experimental)
242
+ const csResult = await analyze(csCode, 'Controller.cs', 'csharp');
243
+
230
244
  // Analyze HTML (extracts scripts, checks attributes)
231
245
  const htmlResult = await analyze(htmlCode, 'index.html', 'html');
232
246
  ```
@@ -1 +1 @@
1
- {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/analysis/config-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,UAAU,EACX,MAAM,oBAAoB,CAAC;AAE5B;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,CAEjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,aAAa,EAAE,CAiB1E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG;IACtD,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC,CAcA;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,mBAAmB,EAAE,GAC7B,kBAAkB,EAAE,CAQtB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,MAAM,EAAE,EACxB,YAAY,EAAE,MAAM,EAAE,EACtB,qBAAqB,GAAE,MAAM,EAAO,GACnC,WAAW,CAYb;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,aAAa,EAuwB1C,CAAC;AA+KF,eAAO,MAAM,aAAa,EAAE,WAAW,EA81DtC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,gBAAgB,EA+hBhD,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,EAAE,kBAAkB,EAiDtD,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAO9C;AAMD;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,EAAE,UAAU,EA8F5C,CAAC"}
1
+ {"version":3,"file":"config-loader.d.ts","sourceRoot":"","sources":["../../src/analysis/config-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,YAAY,EACZ,UAAU,EACV,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,UAAU,EACX,MAAM,oBAAoB,CAAC;AAE5B;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,CAEjD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,aAAa,EAAE,CAiB1E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG;IACtD,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC,CAcA;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,mBAAmB,EAAE,GAC7B,kBAAkB,EAAE,CAQtB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,MAAM,EAAE,EACxB,YAAY,EAAE,MAAM,EAAE,EACtB,qBAAqB,GAAE,MAAM,EAAO,GACnC,WAAW,CAYb;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,aAAa,EAuwB1C,CAAC;AA+KF,eAAO,MAAM,aAAa,EAAE,WAAW,EAq6DtC,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,gBAAgB,EAuiBhD,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,EAAE,kBAAkB,EAiDtD,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAO9C;AAMD;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,EAAE,UAAU,EA8F5C,CAAC"}
@@ -2599,6 +2599,67 @@ export const DEFAULT_SINKS = [
2599
2599
  { method: 'put', class: 'httpx', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0] },
2600
2600
  { method: 'patch', class: 'httpx', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0] },
2601
2601
  { method: 'head', class: 'httpx', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0] },
2602
+ // C# SQLi (Phase-0 spike — ADO.NET). `new SqlCommand(sql, conn)` builds the
2603
+ // command from a raw string; the tainted SQL is arg[0] of the constructor.
2604
+ { method: 'SqlCommand', type: 'sql_injection', cwe: 'CWE-89', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2605
+ { method: 'NpgsqlCommand', type: 'sql_injection', cwe: 'CWE-89', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2606
+ { method: 'MySqlCommand', type: 'sql_injection', cwe: 'CWE-89', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2607
+ { method: 'SqliteCommand', type: 'sql_injection', cwe: 'CWE-89', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2608
+ { method: 'OracleCommand', type: 'sql_injection', cwe: 'CWE-89', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2609
+ { method: 'ExecuteSqlRaw', type: 'sql_injection', cwe: 'CWE-89', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2610
+ { method: 'ExecuteSqlRawAsync', type: 'sql_injection', cwe: 'CWE-89', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2611
+ { method: 'FromSqlRaw', type: 'sql_injection', cwe: 'CWE-89', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2612
+ { method: 'FromSqlRawAsync', type: 'sql_injection', cwe: 'CWE-89', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2613
+ // C# command injection — Process.Start / ProcessStartInfo (CWE-78).
2614
+ { method: 'Start', class: 'Process', type: 'command_injection', cwe: 'CWE-78', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2615
+ { method: 'ProcessStartInfo', type: 'command_injection', cwe: 'CWE-78', severity: 'critical', arg_positions: [0, 1], languages: ['csharp'] },
2616
+ // C# path traversal — System.IO file APIs (CWE-22). Distinctive method names.
2617
+ { method: 'ReadAllText', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2618
+ { method: 'ReadAllBytes', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2619
+ { method: 'ReadAllLines', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2620
+ { method: 'WriteAllText', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2621
+ { method: 'WriteAllBytes', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2622
+ { method: 'AppendAllText', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2623
+ { method: 'OpenRead', class: 'File', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2624
+ { method: 'OpenWrite', class: 'File', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2625
+ { method: 'FileStream', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2626
+ { method: 'StreamReader', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2627
+ { method: 'StreamWriter', type: 'path_traversal', cwe: 'CWE-22', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2628
+ // C# SSRF — HttpClient / WebClient / WebRequest (CWE-918).
2629
+ { method: 'GetAsync', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2630
+ { method: 'PostAsync', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2631
+ { method: 'PutAsync', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2632
+ { method: 'DeleteAsync', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2633
+ { method: 'GetStringAsync', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2634
+ { method: 'GetByteArrayAsync', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2635
+ { method: 'GetStreamAsync', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2636
+ { method: 'SendAsync', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2637
+ { method: 'DownloadString', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2638
+ { method: 'DownloadData', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2639
+ { method: 'DownloadFile', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [1], languages: ['csharp'] },
2640
+ { method: 'Create', class: 'WebRequest', type: 'ssrf', cwe: 'CWE-918', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2641
+ // C# code injection — dynamic script/assembly loading (CWE-94).
2642
+ { method: 'EvaluateAsync', type: 'code_injection', cwe: 'CWE-94', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2643
+ { method: 'RunAsync', class: 'CSharpScript', type: 'code_injection', cwe: 'CWE-94', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2644
+ // C# insecure deserialization — BinaryFormatter et al. (CWE-502).
2645
+ { method: 'Deserialize', class: 'BinaryFormatter', type: 'deserialization', cwe: 'CWE-502', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2646
+ { method: 'Deserialize', class: 'NetDataContractSerializer', type: 'deserialization', cwe: 'CWE-502', severity: 'critical', arg_positions: [0], languages: ['csharp'] },
2647
+ // C# XSS — raw HTML output (CWE-79).
2648
+ { method: 'Raw', class: 'Html', type: 'xss', cwe: 'CWE-79', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2649
+ { method: 'Write', class: 'Response', type: 'xss', cwe: 'CWE-79', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2650
+ { method: 'HtmlString', type: 'xss', cwe: 'CWE-79', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2651
+ // C# LDAP injection — System.DirectoryServices (CWE-90). The user-built
2652
+ // filter is the constructor argument.
2653
+ { method: 'DirectorySearcher', type: 'ldap_injection', cwe: 'CWE-90', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2654
+ { method: 'DirectoryEntry', type: 'ldap_injection', cwe: 'CWE-90', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2655
+ // C# XPath injection — System.Xml.XPath (CWE-643). Distinctive selector methods.
2656
+ { method: 'SelectSingleNode', type: 'xpath_injection', cwe: 'CWE-643', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2657
+ { method: 'SelectNodes', type: 'xpath_injection', cwe: 'CWE-643', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2658
+ { method: 'Compile', class: 'XPathExpression', type: 'xpath_injection', cwe: 'CWE-643', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2659
+ // C# XXE — untrusted XML into a parser without DTD hardening (CWE-611).
2660
+ { method: 'LoadXml', type: 'xxe', cwe: 'CWE-611', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2661
+ { method: 'Load', class: 'XmlDocument', type: 'xxe', cwe: 'CWE-611', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2662
+ { method: 'Load', class: 'XDocument', type: 'xxe', cwe: 'CWE-611', severity: 'high', arg_positions: [0], languages: ['csharp'] },
2602
2663
  // Python SQLi — asyncpg Connection.*
2603
2664
  { method: 'execute', class: 'Connection', type: 'sql_injection', cwe: 'CWE-89', severity: 'critical', arg_positions: [0] },
2604
2665
  { method: 'fetch', class: 'Connection', type: 'sql_injection', cwe: 'CWE-89', severity: 'critical', arg_positions: [0] },
@@ -2798,6 +2859,13 @@ export const DEFAULT_SANITIZERS = [
2798
2859
  { method: 'escapeCsv', removes: ['xss'] },
2799
2860
  // OWASP HTML sanitizer (`com.googlecode.owasp-java-html-sanitizer`).
2800
2861
  { method: 'sanitize', class: 'PolicyFactory', removes: ['xss'] },
2862
+ // C# sanitizers (Phase-1). HTML encoders neutralise XSS; Path.GetFileName
2863
+ // strips any directory component (basename) so a traversal payload cannot
2864
+ // escape the target directory. Method names are C#-distinctive.
2865
+ { method: 'HtmlEncode', removes: ['xss'] }, // HttpUtility / WebUtility
2866
+ { method: 'JavaScriptStringEncode', removes: ['xss'] }, // HttpUtility
2867
+ { method: 'Encode', class: 'HtmlEncoder', removes: ['xss'] },
2868
+ { method: 'GetFileName', class: 'Path', removes: ['path_traversal'] },
2801
2869
  // Java Base64 / Hex / MessageDigest — encoded output is binary-safe
2802
2870
  // (cognium-dev #213 seventh slice). None of these carry attacker
2803
2871
  // shell/SQL/HTML metacharacters through the encoding — Base64 emits