circle-ir 3.51.0 → 3.53.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 (35) hide show
  1. package/configs/sinks/path.yaml +0 -16
  2. package/configs/sources/file_sources.yaml +32 -0
  3. package/dist/analysis/config-loader.d.ts.map +1 -1
  4. package/dist/analysis/config-loader.js +17 -20
  5. package/dist/analysis/config-loader.js.map +1 -1
  6. package/dist/analysis/passes/insecure-cookie-pass.d.ts +23 -23
  7. package/dist/analysis/passes/insecure-cookie-pass.d.ts.map +1 -1
  8. package/dist/analysis/passes/insecure-cookie-pass.js +169 -79
  9. package/dist/analysis/passes/insecure-cookie-pass.js.map +1 -1
  10. package/dist/analysis/passes/tls-verify-disabled-pass.d.ts +52 -0
  11. package/dist/analysis/passes/tls-verify-disabled-pass.d.ts.map +1 -0
  12. package/dist/analysis/passes/tls-verify-disabled-pass.js +247 -0
  13. package/dist/analysis/passes/tls-verify-disabled-pass.js.map +1 -0
  14. package/dist/analysis/passes/weak-crypto-pass.d.ts +59 -0
  15. package/dist/analysis/passes/weak-crypto-pass.d.ts.map +1 -0
  16. package/dist/analysis/passes/weak-crypto-pass.js +392 -0
  17. package/dist/analysis/passes/weak-crypto-pass.js.map +1 -0
  18. package/dist/analysis/passes/weak-hash-pass.d.ts +45 -0
  19. package/dist/analysis/passes/weak-hash-pass.d.ts.map +1 -0
  20. package/dist/analysis/passes/weak-hash-pass.js +150 -0
  21. package/dist/analysis/passes/weak-hash-pass.js.map +1 -0
  22. package/dist/analysis/passes/weak-random-pass.d.ts +53 -0
  23. package/dist/analysis/passes/weak-random-pass.d.ts.map +1 -0
  24. package/dist/analysis/passes/weak-random-pass.js +181 -0
  25. package/dist/analysis/passes/weak-random-pass.js.map +1 -0
  26. package/dist/analysis/taint-matcher.d.ts.map +1 -1
  27. package/dist/analysis/taint-matcher.js +28 -13
  28. package/dist/analysis/taint-matcher.js.map +1 -1
  29. package/dist/analyzer.d.ts.map +1 -1
  30. package/dist/analyzer.js +12 -0
  31. package/dist/analyzer.js.map +1 -1
  32. package/dist/browser/circle-ir.js +852 -57
  33. package/dist/core/circle-ir-core.cjs +25 -26
  34. package/dist/core/circle-ir-core.js +25 -26
  35. package/package.json +1 -1
@@ -10003,6 +10003,13 @@ var DEFAULT_SOURCES = [
10003
10003
  { method: "getFileName", class: "BodyPart", type: "file_input", severity: "high", return_tainted: true },
10004
10004
  { method: "getFileName", class: "MimeBodyPart", type: "file_input", severity: "high", return_tainted: true },
10005
10005
  { method: "getDisposition", class: "Part", type: "file_input", severity: "medium", return_tainted: true },
10006
+ // Archive entry names (Zip-Slip / Tar-Slip CWE-22, issue #52)
10007
+ // entry.getName() returns a path that may contain ../ — flowing into File()/FileOutputStream()
10008
+ // is a classic Zip-Slip vulnerability.
10009
+ { method: "getName", class: "ZipEntry", type: "file_input", severity: "high", return_tainted: true },
10010
+ { method: "getName", class: "ZipArchiveEntry", type: "file_input", severity: "high", return_tainted: true },
10011
+ { method: "getName", class: "TarArchiveEntry", type: "file_input", severity: "high", return_tainted: true },
10012
+ { method: "getName", class: "ArchiveEntry", type: "file_input", severity: "high", return_tainted: true },
10006
10013
  // Command line arguments
10007
10014
  { method: "getArgs", type: "io_input", severity: "high", return_tainted: true },
10008
10015
  { method: "getOptionValue", class: "CommandLine", type: "io_input", severity: "high", return_tainted: true },
@@ -10437,7 +10444,7 @@ var DEFAULT_SINKS = [
10437
10444
  { method: "staticFileLocation", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
10438
10445
  // Zip/archive handling
10439
10446
  { method: "getEntry", class: "ZipFile", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
10440
- { method: "getName", class: "ZipEntry", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [] },
10447
+ // ZipEntry.getName moved to file_sources.yaml as a taint SOURCE (type=archive_entry, issue #52)
10441
10448
  // Resource loading classes (various frameworks)
10442
10449
  { method: "ClassPathResource", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
10443
10450
  { method: "FileSystemResource", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
@@ -10914,26 +10921,16 @@ var DEFAULT_SINKS = [
10914
10921
  { method: "get", class: "WebClient", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [] },
10915
10922
  { method: "post", class: "WebClient", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [] },
10916
10923
  // =============================================================================
10917
- // Weak Cryptography Sinks (no taint flow required - presence alone is vulnerability)
10924
+ // Config / Absence Vulnerabilities (handled by dedicated pattern passes)
10918
10925
  // =============================================================================
10919
- // Weak Random (CWE-330) - java.util.Random is not cryptographically secure
10920
- { method: "Random", class: "constructor", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10921
- { method: "nextInt", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10922
- { method: "nextLong", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10923
- { method: "nextFloat", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10924
- { method: "nextDouble", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10925
- { method: "nextBoolean", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10926
- { method: "nextBytes", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10927
- // Weak Hash (CWE-328) - MD5/SHA1 are cryptographically broken
10928
- // Note: Detection requires checking algorithm argument - handled in runner
10929
- { method: "getInstance", class: "MessageDigest", type: "weak_hash", cwe: "CWE-328", severity: "medium", arg_positions: [0] },
10930
- // Weak Crypto (CWE-327) - DES/RC4/Blowfish are weak ciphers
10931
- // Note: Detection requires checking algorithm argument - handled in runner
10932
- { method: "getInstance", class: "Cipher", type: "weak_crypto", cwe: "CWE-327", severity: "high", arg_positions: [0] },
10933
- { method: "getInstance", class: "KeyGenerator", type: "weak_crypto", cwe: "CWE-327", severity: "high", arg_positions: [0] },
10934
- // Insecure Cookie (CWE-614) - cookies without secure/httpOnly flags
10935
- // Note: Detection requires checking if setSecure(true)/setHttpOnly(true) called - handled in runner
10936
- { method: "Cookie", class: "constructor", type: "insecure_cookie", cwe: "CWE-614", severity: "medium", arg_positions: [] },
10926
+ // weak_random → WeakRandomPass (src/analysis/passes/weak-random-pass.ts)
10927
+ // weak_hash → WeakHashPass (src/analysis/passes/weak-hash-pass.ts)
10928
+ // weak_crypto → WeakCryptoPass (src/analysis/passes/weak-crypto-pass.ts)
10929
+ // insecure_cookie InsecureCookiePass (src/analysis/passes/insecure-cookie-pass.ts)
10930
+ // tls_verify_disabled TlsVerifyDisabledPass
10931
+ // These patterns are detected by call-site literal inspection, not taint flow,
10932
+ // so they are NOT registered here as sinks (they could never match a "tainted
10933
+ // value flowing into a sink" because the bad value is a hard-coded constant).
10937
10934
  // Trust Boundary (CWE-501) - using untrusted data as session attribute NAME
10938
10935
  // The vulnerability is attacker controlling which key to use, not the value
10939
10936
  { method: "setAttribute", class: "HttpSession", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [0] },
@@ -12043,10 +12040,11 @@ function matchesSourcePattern(call, pattern) {
12043
12040
  return false;
12044
12041
  }
12045
12042
  if (pattern.class && pattern.class !== "constructor") {
12046
- if (!call.receiver) {
12043
+ if (call.receiver_type && call.receiver_type === pattern.class) {
12044
+ } else if (call.receiver_type_fqn && call.receiver_type_fqn.endsWith("." + pattern.class)) {
12045
+ } else if (!call.receiver) {
12047
12046
  return false;
12048
- }
12049
- if (!receiverMightBeClass(call.receiver, pattern.class)) {
12047
+ } else if (!receiverMightBeClass(call.receiver, pattern.class)) {
12050
12048
  return false;
12051
12049
  }
12052
12050
  }
@@ -12304,13 +12302,14 @@ function matchesSinkPattern(call, pattern, typeHierarchy, language) {
12304
12302
  if (pattern.class === "constructor") {
12305
12303
  return true;
12306
12304
  }
12307
- if (call.receiver && !receiverMightBeClass(call.receiver, pattern.class)) {
12305
+ if (call.receiver_type && call.receiver_type === pattern.class) {
12306
+ } else if (call.receiver_type_fqn && call.receiver_type_fqn.endsWith("." + pattern.class)) {
12307
+ } else if (call.receiver && !receiverMightBeClass(call.receiver, pattern.class)) {
12308
12308
  if (typeHierarchy && typeHierarchy.couldBeType(call.receiver, pattern.class)) {
12309
12309
  return true;
12310
12310
  }
12311
12311
  return false;
12312
- }
12313
- if (!call.receiver) {
12312
+ } else if (!call.receiver && !call.receiver_type) {
12314
12313
  return false;
12315
12314
  }
12316
12315
  }
@@ -9937,6 +9937,13 @@ var DEFAULT_SOURCES = [
9937
9937
  { method: "getFileName", class: "BodyPart", type: "file_input", severity: "high", return_tainted: true },
9938
9938
  { method: "getFileName", class: "MimeBodyPart", type: "file_input", severity: "high", return_tainted: true },
9939
9939
  { method: "getDisposition", class: "Part", type: "file_input", severity: "medium", return_tainted: true },
9940
+ // Archive entry names (Zip-Slip / Tar-Slip CWE-22, issue #52)
9941
+ // entry.getName() returns a path that may contain ../ — flowing into File()/FileOutputStream()
9942
+ // is a classic Zip-Slip vulnerability.
9943
+ { method: "getName", class: "ZipEntry", type: "file_input", severity: "high", return_tainted: true },
9944
+ { method: "getName", class: "ZipArchiveEntry", type: "file_input", severity: "high", return_tainted: true },
9945
+ { method: "getName", class: "TarArchiveEntry", type: "file_input", severity: "high", return_tainted: true },
9946
+ { method: "getName", class: "ArchiveEntry", type: "file_input", severity: "high", return_tainted: true },
9940
9947
  // Command line arguments
9941
9948
  { method: "getArgs", type: "io_input", severity: "high", return_tainted: true },
9942
9949
  { method: "getOptionValue", class: "CommandLine", type: "io_input", severity: "high", return_tainted: true },
@@ -10371,7 +10378,7 @@ var DEFAULT_SINKS = [
10371
10378
  { method: "staticFileLocation", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
10372
10379
  // Zip/archive handling
10373
10380
  { method: "getEntry", class: "ZipFile", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
10374
- { method: "getName", class: "ZipEntry", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [] },
10381
+ // ZipEntry.getName moved to file_sources.yaml as a taint SOURCE (type=archive_entry, issue #52)
10375
10382
  // Resource loading classes (various frameworks)
10376
10383
  { method: "ClassPathResource", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
10377
10384
  { method: "FileSystemResource", class: "constructor", type: "path_traversal", cwe: "CWE-22", severity: "high", arg_positions: [0] },
@@ -10848,26 +10855,16 @@ var DEFAULT_SINKS = [
10848
10855
  { method: "get", class: "WebClient", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [] },
10849
10856
  { method: "post", class: "WebClient", type: "ssrf", cwe: "CWE-918", severity: "high", arg_positions: [] },
10850
10857
  // =============================================================================
10851
- // Weak Cryptography Sinks (no taint flow required - presence alone is vulnerability)
10858
+ // Config / Absence Vulnerabilities (handled by dedicated pattern passes)
10852
10859
  // =============================================================================
10853
- // Weak Random (CWE-330) - java.util.Random is not cryptographically secure
10854
- { method: "Random", class: "constructor", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10855
- { method: "nextInt", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10856
- { method: "nextLong", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10857
- { method: "nextFloat", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10858
- { method: "nextDouble", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10859
- { method: "nextBoolean", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10860
- { method: "nextBytes", class: "Random", type: "weak_random", cwe: "CWE-330", severity: "medium", arg_positions: [] },
10861
- // Weak Hash (CWE-328) - MD5/SHA1 are cryptographically broken
10862
- // Note: Detection requires checking algorithm argument - handled in runner
10863
- { method: "getInstance", class: "MessageDigest", type: "weak_hash", cwe: "CWE-328", severity: "medium", arg_positions: [0] },
10864
- // Weak Crypto (CWE-327) - DES/RC4/Blowfish are weak ciphers
10865
- // Note: Detection requires checking algorithm argument - handled in runner
10866
- { method: "getInstance", class: "Cipher", type: "weak_crypto", cwe: "CWE-327", severity: "high", arg_positions: [0] },
10867
- { method: "getInstance", class: "KeyGenerator", type: "weak_crypto", cwe: "CWE-327", severity: "high", arg_positions: [0] },
10868
- // Insecure Cookie (CWE-614) - cookies without secure/httpOnly flags
10869
- // Note: Detection requires checking if setSecure(true)/setHttpOnly(true) called - handled in runner
10870
- { method: "Cookie", class: "constructor", type: "insecure_cookie", cwe: "CWE-614", severity: "medium", arg_positions: [] },
10860
+ // weak_random → WeakRandomPass (src/analysis/passes/weak-random-pass.ts)
10861
+ // weak_hash → WeakHashPass (src/analysis/passes/weak-hash-pass.ts)
10862
+ // weak_crypto → WeakCryptoPass (src/analysis/passes/weak-crypto-pass.ts)
10863
+ // insecure_cookie InsecureCookiePass (src/analysis/passes/insecure-cookie-pass.ts)
10864
+ // tls_verify_disabled TlsVerifyDisabledPass
10865
+ // These patterns are detected by call-site literal inspection, not taint flow,
10866
+ // so they are NOT registered here as sinks (they could never match a "tainted
10867
+ // value flowing into a sink" because the bad value is a hard-coded constant).
10871
10868
  // Trust Boundary (CWE-501) - using untrusted data as session attribute NAME
10872
10869
  // The vulnerability is attacker controlling which key to use, not the value
10873
10870
  { method: "setAttribute", class: "HttpSession", type: "trust_boundary", cwe: "CWE-501", severity: "medium", arg_positions: [0] },
@@ -11977,10 +11974,11 @@ function matchesSourcePattern(call, pattern) {
11977
11974
  return false;
11978
11975
  }
11979
11976
  if (pattern.class && pattern.class !== "constructor") {
11980
- if (!call.receiver) {
11977
+ if (call.receiver_type && call.receiver_type === pattern.class) {
11978
+ } else if (call.receiver_type_fqn && call.receiver_type_fqn.endsWith("." + pattern.class)) {
11979
+ } else if (!call.receiver) {
11981
11980
  return false;
11982
- }
11983
- if (!receiverMightBeClass(call.receiver, pattern.class)) {
11981
+ } else if (!receiverMightBeClass(call.receiver, pattern.class)) {
11984
11982
  return false;
11985
11983
  }
11986
11984
  }
@@ -12238,13 +12236,14 @@ function matchesSinkPattern(call, pattern, typeHierarchy, language) {
12238
12236
  if (pattern.class === "constructor") {
12239
12237
  return true;
12240
12238
  }
12241
- if (call.receiver && !receiverMightBeClass(call.receiver, pattern.class)) {
12239
+ if (call.receiver_type && call.receiver_type === pattern.class) {
12240
+ } else if (call.receiver_type_fqn && call.receiver_type_fqn.endsWith("." + pattern.class)) {
12241
+ } else if (call.receiver && !receiverMightBeClass(call.receiver, pattern.class)) {
12242
12242
  if (typeHierarchy && typeHierarchy.couldBeType(call.receiver, pattern.class)) {
12243
12243
  return true;
12244
12244
  }
12245
12245
  return false;
12246
- }
12247
- if (!call.receiver) {
12246
+ } else if (!call.receiver && !call.receiver_type) {
12248
12247
  return false;
12249
12248
  }
12250
12249
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "circle-ir",
3
- "version": "3.51.0",
3
+ "version": "3.53.0",
4
4
  "description": "High-performance Static Application Security Testing (SAST) library for detecting security vulnerabilities through taint analysis",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",