cognium-dev 3.194.0 → 3.197.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 (2) hide show
  1. package/dist/cli.js +497 -573
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -10719,7 +10719,7 @@ var DEFAULT_SOURCES = [
10719
10719
  { method: "Json", type: "http_body", severity: "high", return_tainted: true, languages: ["rust"] },
10720
10720
  { method: "Query", type: "http_param", severity: "high", return_tainted: true, languages: ["rust"] },
10721
10721
  { method: "Path", type: "http_path", severity: "high", return_tainted: true, languages: ["rust"] },
10722
- { method: "Form", type: "http_param", severity: "high", return_tainted: true, languages: ["rust"] },
10722
+ { method: "Form", type: "http_body", severity: "high", return_tainted: true, languages: ["rust"] },
10723
10723
  { method: "var", class: "env", type: "env_input", severity: "medium", return_tainted: true },
10724
10724
  { method: "var_os", class: "env", type: "env_input", severity: "medium", return_tainted: true },
10725
10725
  { method: "args", class: "env", type: "env_input", severity: "medium", return_tainted: true },
@@ -11508,7 +11508,7 @@ var DEFAULT_SINKS = [
11508
11508
  { method: "execSync", class: "child_process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
11509
11509
  { method: "spawn", class: "child_process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
11510
11510
  { method: "spawnSync", class: "child_process", type: "command_injection", cwe: "CWE-78", severity: "critical", arg_positions: [0] },
11511
- { method: "exec", type: "command_injection", cwe: "CWE-78", severity: "high", arg_positions: [0] },
11511
+ { method: "exec", type: "command_injection", cwe: "CWE-78", severity: "high", arg_positions: [0], exclude_languages: ["python"] },
11512
11512
  { method: "execSync", type: "command_injection", cwe: "CWE-78", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
11513
11513
  { method: "spawn", type: "command_injection", cwe: "CWE-78", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
11514
11514
  { method: "spawnSync", type: "command_injection", cwe: "CWE-78", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
@@ -11528,7 +11528,7 @@ var DEFAULT_SINKS = [
11528
11528
  { method: "query", class: "Client", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"], allow_unresolved_receiver: true },
11529
11529
  { method: "execute", class: "Pool", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"], allow_unresolved_receiver: true },
11530
11530
  { method: "execute", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"], allow_unresolved_receiver: true },
11531
- { method: "raw", type: "sql_injection", cwe: "CWE-89", severity: "high", arg_positions: [0], languages: ["javascript", "typescript"] },
11531
+ { method: "raw", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"] },
11532
11532
  { method: "all", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"], allow_unresolved_receiver: true },
11533
11533
  { method: "run", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"], allow_unresolved_receiver: true },
11534
11534
  { method: "each", class: "Connection", type: "sql_injection", cwe: "CWE-89", severity: "critical", arg_positions: [0], languages: ["javascript", "typescript"], allow_unresolved_receiver: true },
@@ -12483,6 +12483,17 @@ function analyzeTaint(calls, types, config = getDefaultConfig(), typeHierarchy,
12483
12483
  const sanitizers = findSanitizers(calls, types, config.sanitizers, sourceLines);
12484
12484
  return { sources, sinks, sanitizers };
12485
12485
  }
12486
+ function sinkPatternAppliesTo(pattern, language) {
12487
+ if (language === undefined)
12488
+ return true;
12489
+ if (pattern.languages && pattern.languages.length > 0 && !pattern.languages.includes(language)) {
12490
+ return false;
12491
+ }
12492
+ if (pattern.exclude_languages && pattern.exclude_languages.includes(language)) {
12493
+ return false;
12494
+ }
12495
+ return true;
12496
+ }
12486
12497
  function expandPromisifyAliases(patterns, sourceLines, language) {
12487
12498
  if (!sourceLines || sourceLines.length === 0)
12488
12499
  return patterns;
@@ -12491,7 +12502,7 @@ function expandPromisifyAliases(patterns, sourceLines, language) {
12491
12502
  const PROMISIFY_RE = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:util\s*\.\s*)?promisify\s*\(\s*([A-Za-z_$][\w$]*)\s*\)/;
12492
12503
  const innerToPattern = new Map;
12493
12504
  for (const p of patterns) {
12494
- if (p.languages && !p.languages.includes(language))
12505
+ if (!sinkPatternAppliesTo(p, language))
12495
12506
  continue;
12496
12507
  if (p.class !== undefined)
12497
12508
  continue;
@@ -12499,7 +12510,7 @@ function expandPromisifyAliases(patterns, sourceLines, language) {
12499
12510
  innerToPattern.set(p.method, p);
12500
12511
  }
12501
12512
  for (const p of patterns) {
12502
- if (p.languages && !p.languages.includes(language))
12513
+ if (!sinkPatternAppliesTo(p, language))
12503
12514
  continue;
12504
12515
  if (innerToPattern.has(p.method))
12505
12516
  continue;
@@ -12541,7 +12552,7 @@ function expandIndirectEvalAliases(patterns, sourceLines, language) {
12541
12552
  const INDIRECT_EVAL_RE = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*(?::[^=]+)?=\s*(eval|Function)\b(?!\s*\()/;
12542
12553
  const innerToPattern = new Map;
12543
12554
  for (const p of patterns) {
12544
- if (p.languages && !p.languages.includes(language))
12555
+ if (!sinkPatternAppliesTo(p, language))
12545
12556
  continue;
12546
12557
  if (p.class !== undefined)
12547
12558
  continue;
@@ -13301,7 +13312,7 @@ function isSafeJinjaRenderCall(call, pattern, language, sourceLines) {
13301
13312
  return false;
13302
13313
  }
13303
13314
  function findSinks(calls, patterns, typeHierarchy, language, sourceLines, types) {
13304
- const patternsForLanguage = language === undefined ? patterns : patterns.filter((p) => !p.languages || p.languages.length === 0 || p.languages.includes(language));
13315
+ const patternsForLanguage = language === undefined ? patterns : patterns.filter((p) => sinkPatternAppliesTo(p, language));
13305
13316
  const sinkMap = new Map;
13306
13317
  for (const call of calls) {
13307
13318
  for (const pattern of patternsForLanguage) {
@@ -13636,10 +13647,8 @@ var SINK_FQN_EXCLUSIONS = {
13636
13647
  ]
13637
13648
  };
13638
13649
  function matchesSinkPattern(call, pattern, typeHierarchy, language) {
13639
- if (pattern.languages && pattern.languages.length > 0 && language !== undefined) {
13640
- if (!pattern.languages.includes(language)) {
13641
- return false;
13642
- }
13650
+ if (!sinkPatternAppliesTo(pattern, language)) {
13651
+ return false;
13643
13652
  }
13644
13653
  const callMethodName = call.method_name;
13645
13654
  const patternMethod = pattern.method;
@@ -20987,99 +20996,11 @@ class JavaPlugin extends BaseLanguagePlugin {
20987
20996
  severity: "high",
20988
20997
  confidence: 0.9,
20989
20998
  returnTainted: true
20990
- },
20991
- {
20992
- method: "getParameter",
20993
- class: "HttpServletRequest",
20994
- type: "http_param",
20995
- severity: "high",
20996
- confidence: 0.95,
20997
- returnTainted: true
20998
- },
20999
- {
21000
- method: "getParameterValues",
21001
- class: "HttpServletRequest",
21002
- type: "http_param",
21003
- severity: "high",
21004
- confidence: 0.95,
21005
- returnTainted: true
21006
- },
21007
- {
21008
- method: "getHeader",
21009
- class: "HttpServletRequest",
21010
- type: "http_header",
21011
- severity: "high",
21012
- confidence: 0.9,
21013
- returnTainted: true
21014
- },
21015
- {
21016
- method: "getCookies",
21017
- class: "HttpServletRequest",
21018
- type: "http_cookie",
21019
- severity: "high",
21020
- confidence: 0.9,
21021
- returnTainted: true
21022
- },
21023
- {
21024
- method: "getInputStream",
21025
- class: "HttpServletRequest",
21026
- type: "http_body",
21027
- severity: "high",
21028
- confidence: 0.85,
21029
- returnTainted: true
21030
- },
21031
- {
21032
- method: "getReader",
21033
- class: "HttpServletRequest",
21034
- type: "http_body",
21035
- severity: "high",
21036
- confidence: 0.85,
21037
- returnTainted: true
21038
20999
  }
21039
21000
  ];
21040
21001
  }
21041
21002
  getBuiltinSinks() {
21042
21003
  return [
21043
- {
21044
- method: "executeQuery",
21045
- class: "Statement",
21046
- type: "sql_injection",
21047
- cwe: "CWE-89",
21048
- severity: "critical",
21049
- argPositions: [0]
21050
- },
21051
- {
21052
- method: "executeUpdate",
21053
- class: "Statement",
21054
- type: "sql_injection",
21055
- cwe: "CWE-89",
21056
- severity: "critical",
21057
- argPositions: [0]
21058
- },
21059
- {
21060
- method: "execute",
21061
- class: "Statement",
21062
- type: "sql_injection",
21063
- cwe: "CWE-89",
21064
- severity: "critical",
21065
- argPositions: [0]
21066
- },
21067
- {
21068
- method: "exec",
21069
- class: "Runtime",
21070
- type: "command_injection",
21071
- cwe: "CWE-78",
21072
- severity: "critical",
21073
- argPositions: [0]
21074
- },
21075
- {
21076
- method: "start",
21077
- class: "ProcessBuilder",
21078
- type: "command_injection",
21079
- cwe: "CWE-78",
21080
- severity: "critical",
21081
- argPositions: []
21082
- },
21083
21004
  {
21084
21005
  method: "FileInputStream",
21085
21006
  type: "path_traversal",
@@ -21094,38 +21015,6 @@ class JavaPlugin extends BaseLanguagePlugin {
21094
21015
  severity: "high",
21095
21016
  argPositions: [0]
21096
21017
  },
21097
- {
21098
- method: "write",
21099
- class: "PrintWriter",
21100
- type: "xss",
21101
- cwe: "CWE-79",
21102
- severity: "high",
21103
- argPositions: [0]
21104
- },
21105
- {
21106
- method: "println",
21107
- class: "PrintWriter",
21108
- type: "xss",
21109
- cwe: "CWE-79",
21110
- severity: "high",
21111
- argPositions: [0]
21112
- },
21113
- {
21114
- method: "search",
21115
- class: "DirContext",
21116
- type: "ldap_injection",
21117
- cwe: "CWE-90",
21118
- severity: "high",
21119
- argPositions: [0, 1]
21120
- },
21121
- {
21122
- method: "evaluate",
21123
- class: "XPath",
21124
- type: "xpath_injection",
21125
- cwe: "CWE-643",
21126
- severity: "high",
21127
- argPositions: [0]
21128
- },
21129
21018
  {
21130
21019
  method: "readObject",
21131
21020
  class: "ObjectInputStream",
@@ -21635,37 +21524,6 @@ class JavaScriptPlugin extends BaseLanguagePlugin {
21635
21524
  }
21636
21525
  getBuiltinSinks() {
21637
21526
  return [
21638
- {
21639
- method: "exec",
21640
- class: "child_process",
21641
- type: "command_injection",
21642
- cwe: "CWE-78",
21643
- severity: "critical",
21644
- argPositions: [0]
21645
- },
21646
- {
21647
- method: "execSync",
21648
- class: "child_process",
21649
- type: "command_injection",
21650
- cwe: "CWE-78",
21651
- severity: "critical",
21652
- argPositions: [0]
21653
- },
21654
- {
21655
- method: "spawn",
21656
- class: "child_process",
21657
- type: "command_injection",
21658
- cwe: "CWE-78",
21659
- severity: "critical",
21660
- argPositions: [0, 1]
21661
- },
21662
- {
21663
- method: "eval",
21664
- type: "code_injection",
21665
- cwe: "CWE-94",
21666
- severity: "critical",
21667
- argPositions: [0]
21668
- },
21669
21527
  {
21670
21528
  method: "Function",
21671
21529
  type: "code_injection",
@@ -21687,44 +21545,6 @@ class JavaScriptPlugin extends BaseLanguagePlugin {
21687
21545
  severity: "high",
21688
21546
  argPositions: [0]
21689
21547
  },
21690
- {
21691
- method: "readFileSync",
21692
- class: "fs",
21693
- type: "path_traversal",
21694
- cwe: "CWE-22",
21695
- severity: "high",
21696
- argPositions: [0]
21697
- },
21698
- {
21699
- method: "writeFileSync",
21700
- class: "fs",
21701
- type: "path_traversal",
21702
- cwe: "CWE-22",
21703
- severity: "high",
21704
- argPositions: [0]
21705
- },
21706
- {
21707
- method: "createReadStream",
21708
- class: "fs",
21709
- type: "path_traversal",
21710
- cwe: "CWE-22",
21711
- severity: "high",
21712
- argPositions: [0]
21713
- },
21714
- {
21715
- method: "innerHTML",
21716
- type: "xss",
21717
- cwe: "CWE-79",
21718
- severity: "high",
21719
- argPositions: [0]
21720
- },
21721
- {
21722
- method: "outerHTML",
21723
- type: "xss",
21724
- cwe: "CWE-79",
21725
- severity: "high",
21726
- argPositions: [0]
21727
- },
21728
21548
  {
21729
21549
  method: "document.write",
21730
21550
  type: "xss",
@@ -21774,13 +21594,6 @@ class JavaScriptPlugin extends BaseLanguagePlugin {
21774
21594
  severity: "critical",
21775
21595
  argPositions: [0]
21776
21596
  },
21777
- {
21778
- method: "raw",
21779
- type: "sql_injection",
21780
- cwe: "CWE-89",
21781
- severity: "critical",
21782
- argPositions: [0]
21783
- },
21784
21597
  {
21785
21598
  method: "$executeRawUnsafe",
21786
21599
  type: "sql_injection",
@@ -21795,29 +21608,6 @@ class JavaScriptPlugin extends BaseLanguagePlugin {
21795
21608
  severity: "critical",
21796
21609
  argPositions: [0]
21797
21610
  },
21798
- {
21799
- method: "fetch",
21800
- type: "ssrf",
21801
- cwe: "CWE-918",
21802
- severity: "high",
21803
- argPositions: [0]
21804
- },
21805
- {
21806
- method: "get",
21807
- class: "axios",
21808
- type: "ssrf",
21809
- cwe: "CWE-918",
21810
- severity: "high",
21811
- argPositions: [0]
21812
- },
21813
- {
21814
- method: "request",
21815
- class: "http",
21816
- type: "ssrf",
21817
- cwe: "CWE-918",
21818
- severity: "high",
21819
- argPositions: [0]
21820
- },
21821
21611
  {
21822
21612
  method: "find",
21823
21613
  type: "nosql_injection",
@@ -21825,13 +21615,6 @@ class JavaScriptPlugin extends BaseLanguagePlugin {
21825
21615
  severity: "high",
21826
21616
  argPositions: [0]
21827
21617
  },
21828
- {
21829
- method: "findOne",
21830
- type: "nosql_injection",
21831
- cwe: "CWE-943",
21832
- severity: "high",
21833
- argPositions: [0]
21834
- },
21835
21618
  {
21836
21619
  method: "merge",
21837
21620
  type: "prototype_pollution",
@@ -21907,13 +21690,6 @@ class JavaScriptPlugin extends BaseLanguagePlugin {
21907
21690
  severity: "high",
21908
21691
  argPositions: [0]
21909
21692
  },
21910
- {
21911
- method: "redirect",
21912
- type: "open_redirect",
21913
- cwe: "CWE-601",
21914
- severity: "high",
21915
- argPositions: [0]
21916
- },
21917
21693
  {
21918
21694
  method: "push",
21919
21695
  class: "router",
@@ -22156,13 +21932,6 @@ class PythonPlugin extends BaseLanguagePlugin {
22156
21932
  confidence: 0.9,
22157
21933
  returnTainted: true
22158
21934
  },
22159
- {
22160
- method: "input",
22161
- type: "user_input",
22162
- severity: "high",
22163
- confidence: 0.95,
22164
- returnTainted: true
22165
- },
22166
21935
  {
22167
21936
  method: "argv",
22168
21937
  class: "sys",
@@ -22178,129 +21947,11 @@ class PythonPlugin extends BaseLanguagePlugin {
22178
21947
  severity: "medium",
22179
21948
  confidence: 0.85,
22180
21949
  returnTainted: true
22181
- },
22182
- {
22183
- method: "getenv",
22184
- class: "os",
22185
- type: "env_var",
22186
- severity: "medium",
22187
- confidence: 0.85,
22188
- returnTainted: true
22189
- },
22190
- {
22191
- method: "read",
22192
- type: "file_input",
22193
- severity: "medium",
22194
- confidence: 0.8,
22195
- returnTainted: true
22196
- },
22197
- {
22198
- method: "readline",
22199
- type: "file_input",
22200
- severity: "medium",
22201
- confidence: 0.8,
22202
- returnTainted: true
22203
- },
22204
- {
22205
- method: "readlines",
22206
- type: "file_input",
22207
- severity: "medium",
22208
- confidence: 0.8,
22209
- returnTainted: true
22210
21950
  }
22211
21951
  ];
22212
21952
  }
22213
21953
  getBuiltinSinks() {
22214
21954
  return [
22215
- {
22216
- method: "system",
22217
- class: "os",
22218
- type: "command_injection",
22219
- cwe: "CWE-78",
22220
- severity: "critical",
22221
- argPositions: [0]
22222
- },
22223
- {
22224
- method: "popen",
22225
- class: "os",
22226
- type: "command_injection",
22227
- cwe: "CWE-78",
22228
- severity: "critical",
22229
- argPositions: [0]
22230
- },
22231
- {
22232
- method: "run",
22233
- class: "subprocess",
22234
- type: "command_injection",
22235
- cwe: "CWE-78",
22236
- severity: "critical",
22237
- argPositions: [0]
22238
- },
22239
- {
22240
- method: "call",
22241
- class: "subprocess",
22242
- type: "command_injection",
22243
- cwe: "CWE-78",
22244
- severity: "critical",
22245
- argPositions: [0]
22246
- },
22247
- {
22248
- method: "Popen",
22249
- class: "subprocess",
22250
- type: "command_injection",
22251
- cwe: "CWE-78",
22252
- severity: "critical",
22253
- argPositions: [0]
22254
- },
22255
- {
22256
- method: "eval",
22257
- type: "code_injection",
22258
- cwe: "CWE-94",
22259
- severity: "critical",
22260
- argPositions: [0]
22261
- },
22262
- {
22263
- method: "exec",
22264
- type: "code_injection",
22265
- cwe: "CWE-94",
22266
- severity: "critical",
22267
- argPositions: [0]
22268
- },
22269
- {
22270
- method: "compile",
22271
- type: "code_injection",
22272
- cwe: "CWE-94",
22273
- severity: "high",
22274
- argPositions: [0]
22275
- },
22276
- {
22277
- method: "execute",
22278
- type: "sql_injection",
22279
- cwe: "CWE-89",
22280
- severity: "critical",
22281
- argPositions: [0]
22282
- },
22283
- {
22284
- method: "executemany",
22285
- type: "sql_injection",
22286
- cwe: "CWE-89",
22287
- severity: "critical",
22288
- argPositions: [0]
22289
- },
22290
- {
22291
- method: "raw",
22292
- type: "sql_injection",
22293
- cwe: "CWE-89",
22294
- severity: "critical",
22295
- argPositions: [0]
22296
- },
22297
- {
22298
- method: "open",
22299
- type: "path_traversal",
22300
- cwe: "CWE-22",
22301
- severity: "high",
22302
- argPositions: [0]
22303
- },
22304
21955
  {
22305
21956
  method: "read",
22306
21957
  class: "pathlib",
@@ -22309,13 +21960,6 @@ class PythonPlugin extends BaseLanguagePlugin {
22309
21960
  severity: "high",
22310
21961
  argPositions: [0]
22311
21962
  },
22312
- {
22313
- method: "Markup",
22314
- type: "xss",
22315
- cwe: "CWE-79",
22316
- severity: "high",
22317
- argPositions: [0]
22318
- },
22319
21963
  {
22320
21964
  method: "safe",
22321
21965
  type: "xss",
@@ -22323,22 +21967,6 @@ class PythonPlugin extends BaseLanguagePlugin {
22323
21967
  severity: "high",
22324
21968
  argPositions: [0]
22325
21969
  },
22326
- {
22327
- method: "get",
22328
- class: "requests",
22329
- type: "ssrf",
22330
- cwe: "CWE-918",
22331
- severity: "high",
22332
- argPositions: [0]
22333
- },
22334
- {
22335
- method: "post",
22336
- class: "requests",
22337
- type: "ssrf",
22338
- cwe: "CWE-918",
22339
- severity: "high",
22340
- argPositions: [0]
22341
- },
22342
21970
  {
22343
21971
  method: "urlopen",
22344
21972
  class: "urllib",
@@ -22363,30 +21991,6 @@ class PythonPlugin extends BaseLanguagePlugin {
22363
21991
  severity: "high",
22364
21992
  argPositions: [1]
22365
21993
  },
22366
- {
22367
- method: "loads",
22368
- class: "pickle",
22369
- type: "deserialization",
22370
- cwe: "CWE-502",
22371
- severity: "critical",
22372
- argPositions: [0]
22373
- },
22374
- {
22375
- method: "load",
22376
- class: "pickle",
22377
- type: "deserialization",
22378
- cwe: "CWE-502",
22379
- severity: "critical",
22380
- argPositions: [0]
22381
- },
22382
- {
22383
- method: "load",
22384
- class: "yaml",
22385
- type: "deserialization",
22386
- cwe: "CWE-502",
22387
- severity: "critical",
22388
- argPositions: [0]
22389
- },
22390
21994
  {
22391
21995
  method: "unsafe_load",
22392
21996
  class: "yaml",
@@ -22522,34 +22126,6 @@ class RustPlugin extends BaseLanguagePlugin {
22522
22126
  }
22523
22127
  getBuiltinSources() {
22524
22128
  return [
22525
- {
22526
- method: "Query",
22527
- type: "http_param",
22528
- severity: "high",
22529
- confidence: 0.95,
22530
- returnTainted: true
22531
- },
22532
- {
22533
- method: "Json",
22534
- type: "http_body",
22535
- severity: "high",
22536
- confidence: 0.95,
22537
- returnTainted: true
22538
- },
22539
- {
22540
- method: "Path",
22541
- type: "http_path",
22542
- severity: "high",
22543
- confidence: 0.95,
22544
- returnTainted: true
22545
- },
22546
- {
22547
- method: "Form",
22548
- type: "http_body",
22549
- severity: "high",
22550
- confidence: 0.95,
22551
- returnTainted: true
22552
- },
22553
22129
  {
22554
22130
  method: "args",
22555
22131
  class: "std::env",
@@ -22597,14 +22173,6 @@ class RustPlugin extends BaseLanguagePlugin {
22597
22173
  severity: "medium",
22598
22174
  confidence: 0.8,
22599
22175
  returnTainted: true
22600
- },
22601
- {
22602
- method: "read",
22603
- class: "TcpStream",
22604
- type: "network_input",
22605
- severity: "high",
22606
- confidence: 0.85,
22607
- returnTainted: true
22608
22176
  }
22609
22177
  ];
22610
22178
  }
@@ -22618,29 +22186,6 @@ class RustPlugin extends BaseLanguagePlugin {
22618
22186
  severity: "critical",
22619
22187
  argPositions: [0]
22620
22188
  },
22621
- {
22622
- method: "arg",
22623
- class: "Command",
22624
- type: "command_injection",
22625
- cwe: "CWE-78",
22626
- severity: "critical",
22627
- argPositions: [0]
22628
- },
22629
- {
22630
- method: "args",
22631
- class: "Command",
22632
- type: "command_injection",
22633
- cwe: "CWE-78",
22634
- severity: "critical",
22635
- argPositions: [0]
22636
- },
22637
- {
22638
- method: "execute",
22639
- type: "sql_injection",
22640
- cwe: "CWE-89",
22641
- severity: "critical",
22642
- argPositions: [0]
22643
- },
22644
22189
  {
22645
22190
  method: "query",
22646
22191
  type: "sql_injection",
@@ -22655,22 +22200,6 @@ class RustPlugin extends BaseLanguagePlugin {
22655
22200
  severity: "critical",
22656
22201
  argPositions: [0]
22657
22202
  },
22658
- {
22659
- method: "open",
22660
- class: "File",
22661
- type: "path_traversal",
22662
- cwe: "CWE-22",
22663
- severity: "high",
22664
- argPositions: [0]
22665
- },
22666
- {
22667
- method: "create",
22668
- class: "File",
22669
- type: "path_traversal",
22670
- cwe: "CWE-22",
22671
- severity: "high",
22672
- argPositions: [0]
22673
- },
22674
22203
  {
22675
22204
  method: "read_to_string",
22676
22205
  class: "std::fs",
@@ -22708,38 +22237,6 @@ class RustPlugin extends BaseLanguagePlugin {
22708
22237
  severity: "critical",
22709
22238
  argPositions: [0]
22710
22239
  },
22711
- {
22712
- method: "from_str",
22713
- class: "serde_json",
22714
- type: "deserialization",
22715
- cwe: "CWE-502",
22716
- severity: "medium",
22717
- argPositions: [0]
22718
- },
22719
- {
22720
- method: "from_slice",
22721
- class: "serde_json",
22722
- type: "deserialization",
22723
- cwe: "CWE-502",
22724
- severity: "medium",
22725
- argPositions: [0]
22726
- },
22727
- {
22728
- method: "get",
22729
- class: "reqwest",
22730
- type: "ssrf",
22731
- cwe: "CWE-918",
22732
- severity: "high",
22733
- argPositions: [0]
22734
- },
22735
- {
22736
- method: "post",
22737
- class: "reqwest",
22738
- type: "ssrf",
22739
- cwe: "CWE-918",
22740
- severity: "high",
22741
- argPositions: [0]
22742
- },
22743
22240
  {
22744
22241
  method: "new",
22745
22242
  class: "Regex",
@@ -22832,13 +22329,6 @@ class BashPlugin extends BaseLanguagePlugin {
22832
22329
  }
22833
22330
  getBuiltinSources() {
22834
22331
  return [
22835
- {
22836
- method: "read",
22837
- type: "io_input",
22838
- severity: "high",
22839
- confidence: 0.9,
22840
- returnTainted: true
22841
- },
22842
22332
  {
22843
22333
  method: "curl",
22844
22334
  type: "http_response",
@@ -22857,13 +22347,6 @@ class BashPlugin extends BaseLanguagePlugin {
22857
22347
  }
22858
22348
  getBuiltinSinks() {
22859
22349
  return [
22860
- {
22861
- method: "eval",
22862
- type: "code_injection",
22863
- cwe: "CWE-94",
22864
- severity: "critical",
22865
- argPositions: [0]
22866
- },
22867
22350
  {
22868
22351
  method: "bash",
22869
22352
  type: "command_injection",
@@ -23259,30 +22742,6 @@ class GoPlugin extends BaseLanguagePlugin {
23259
22742
  confidence: 0.9,
23260
22743
  returnTainted: true
23261
22744
  },
23262
- {
23263
- method: "Query",
23264
- class: "Context",
23265
- type: "http_param",
23266
- severity: "high",
23267
- confidence: 0.95,
23268
- returnTainted: true
23269
- },
23270
- {
23271
- method: "Param",
23272
- class: "Context",
23273
- type: "http_path",
23274
- severity: "high",
23275
- confidence: 0.95,
23276
- returnTainted: true
23277
- },
23278
- {
23279
- method: "PostForm",
23280
- class: "Context",
23281
- type: "http_param",
23282
- severity: "high",
23283
- confidence: 0.95,
23284
- returnTainted: true
23285
- },
23286
22745
  {
23287
22746
  method: "GetRawData",
23288
22747
  class: "Context",
@@ -23479,14 +22938,6 @@ class GoPlugin extends BaseLanguagePlugin {
23479
22938
  severity: "medium",
23480
22939
  argPositions: [0]
23481
22940
  },
23482
- {
23483
- method: "Decode",
23484
- class: "Decoder",
23485
- type: "deserialization",
23486
- cwe: "CWE-502",
23487
- severity: "medium",
23488
- argPositions: [0]
23489
- },
23490
22941
  {
23491
22942
  method: "Print",
23492
22943
  class: "log",
@@ -25121,6 +24572,10 @@ class LanguageSourcesPass {
25121
24572
  additionalSanitizers.push(...findPythonRangeCheckGuardSanitizers(code));
25122
24573
  additionalSanitizers.push(...findPythonRegexAllowlistWrapperSanitizers(code));
25123
24574
  additionalSanitizers.push(...findPythonSetMembershipXssGuardSanitizers(code));
24575
+ additionalSanitizers.push(...findPythonTraversalRejectGuardSanitizers(code));
24576
+ additionalSanitizers.push(...findPythonStringLiteralGuardSanitizers(code));
24577
+ additionalSanitizers.push(...findPythonDefaultSaxParserXxeSanitizers(code));
24578
+ additionalSanitizers.push(...findPythonUrlAllowlistRedirectSanitizers(code));
25124
24579
  additionalSanitizers.push(...findPythonDefusedXmlSanitizers(code));
25125
24580
  additionalSanitizers.push(...findPythonJinjaAutoescapeSanitizers(code));
25126
24581
  const pyMisconfigFindings = findPythonPatternFindings(code, graph.ir.meta.file);
@@ -25715,15 +25170,165 @@ function findPythonAssignmentSources(sourceCode, language) {
25715
25170
  }
25716
25171
  return sources;
25717
25172
  }
25173
+ function evaluatePythonConstExpression(expr, consts) {
25174
+ const COMPARISON = /(<=|>=|==|!=|<|>)/;
25175
+ const parts2 = expr.split(COMPARISON);
25176
+ if (parts2.length === 3) {
25177
+ const left = evaluatePythonConstExpression(parts2[0], consts);
25178
+ const right = evaluatePythonConstExpression(parts2[2], consts);
25179
+ if (typeof left !== "number" || typeof right !== "number")
25180
+ return;
25181
+ switch (parts2[1]) {
25182
+ case "<":
25183
+ return left < right;
25184
+ case ">":
25185
+ return left > right;
25186
+ case "<=":
25187
+ return left <= right;
25188
+ case ">=":
25189
+ return left >= right;
25190
+ case "==":
25191
+ return left === right;
25192
+ case "!=":
25193
+ return left !== right;
25194
+ default:
25195
+ return;
25196
+ }
25197
+ }
25198
+ if (parts2.length !== 1)
25199
+ return;
25200
+ const matched = expr.match(/\d+|[A-Za-z_][A-Za-z0-9_]*|\/\/|[-+*/%()]|\S/g);
25201
+ if (!matched)
25202
+ return;
25203
+ const tokens = matched;
25204
+ let pos = 0;
25205
+ const peek = () => tokens[pos];
25206
+ const parseFactor = () => {
25207
+ const tok = tokens[pos++];
25208
+ if (tok === undefined)
25209
+ return;
25210
+ if (tok === "(") {
25211
+ const inner = parseSum();
25212
+ if (tokens[pos++] !== ")")
25213
+ return;
25214
+ return inner;
25215
+ }
25216
+ if (tok === "-") {
25217
+ const operand = parseFactor();
25218
+ return operand === undefined ? undefined : -operand;
25219
+ }
25220
+ if (/^\d+$/.test(tok))
25221
+ return Number(tok);
25222
+ if (/^[A-Za-z_]/.test(tok))
25223
+ return consts.get(tok);
25224
+ return;
25225
+ };
25226
+ const parseTerm = () => {
25227
+ let value = parseFactor();
25228
+ if (value === undefined)
25229
+ return;
25230
+ while (peek() === "*" || peek() === "/" || peek() === "//" || peek() === "%") {
25231
+ const op = tokens[pos++];
25232
+ const rhs = parseFactor();
25233
+ if (rhs === undefined)
25234
+ return;
25235
+ if ((op === "/" || op === "//" || op === "%") && rhs === 0)
25236
+ return;
25237
+ if (op === "*")
25238
+ value *= rhs;
25239
+ else if (op === "/")
25240
+ value /= rhs;
25241
+ else if (op === "//")
25242
+ value = Math.floor(value / rhs);
25243
+ else
25244
+ value = (value % rhs + rhs) % rhs;
25245
+ }
25246
+ return value;
25247
+ };
25248
+ function parseSum() {
25249
+ let value = parseTerm();
25250
+ if (value === undefined)
25251
+ return;
25252
+ while (peek() === "+" || peek() === "-") {
25253
+ const op = tokens[pos++];
25254
+ const rhs = parseTerm();
25255
+ if (rhs === undefined)
25256
+ return;
25257
+ value = op === "+" ? value + rhs : value - rhs;
25258
+ }
25259
+ return value;
25260
+ }
25261
+ const result = parseSum();
25262
+ return pos === tokens.length ? result : undefined;
25263
+ }
25264
+ function normalizeListIndex(index, length) {
25265
+ const resolved = index < 0 ? length + index : index;
25266
+ return resolved >= 0 && resolved < length ? resolved : undefined;
25267
+ }
25268
+ function computeDeadPythonBranchLines(lines) {
25269
+ const dead = new Set;
25270
+ const consts = new Map;
25271
+ const indentOf = (line) => line.length - line.trimStart().length;
25272
+ for (let i2 = 0;i2 < lines.length; i2++) {
25273
+ const line = lines[i2];
25274
+ const assign = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=(?!=)\s*(.+)$/);
25275
+ if (assign) {
25276
+ const value = evaluatePythonConstExpression(assign[2].trim(), consts);
25277
+ if (typeof value === "number")
25278
+ consts.set(assign[1], value);
25279
+ else
25280
+ consts.delete(assign[1]);
25281
+ }
25282
+ const ifMatch = line.match(/^(\s*)if\s+(.+?)\s*:\s*$/);
25283
+ if (!ifMatch)
25284
+ continue;
25285
+ const indent = ifMatch[1].length;
25286
+ const decided = evaluatePythonConstExpression(ifMatch[2].trim(), consts);
25287
+ if (decided !== true && decided !== false)
25288
+ continue;
25289
+ const thenStart = i2 + 1;
25290
+ let cursor = thenStart;
25291
+ while (cursor < lines.length && (lines[cursor].trim() === "" || indentOf(lines[cursor]) > indent)) {
25292
+ cursor++;
25293
+ }
25294
+ const thenEnd = cursor - 1;
25295
+ let elseStart = -1;
25296
+ let elseEnd = -1;
25297
+ if (cursor < lines.length && indentOf(lines[cursor]) === indent) {
25298
+ if (/^\s*elif\b/.test(lines[cursor]))
25299
+ continue;
25300
+ if (/^\s*else\s*:\s*$/.test(lines[cursor])) {
25301
+ elseStart = cursor + 1;
25302
+ let k = elseStart;
25303
+ while (k < lines.length && (lines[k].trim() === "" || indentOf(lines[k]) > indent))
25304
+ k++;
25305
+ elseEnd = k - 1;
25306
+ }
25307
+ }
25308
+ if (decided === true) {
25309
+ for (let l = elseStart;l >= 0 && l <= elseEnd; l++)
25310
+ dead.add(l);
25311
+ } else {
25312
+ for (let l = thenStart;l <= thenEnd; l++)
25313
+ dead.add(l);
25314
+ }
25315
+ }
25316
+ return dead;
25317
+ }
25718
25318
  function buildPythonTaintedVars(sourceCode) {
25719
25319
  const tainted = new Map;
25720
25320
  const containerTainted = new Map;
25721
25321
  const lines = sourceCode.split(`
25722
25322
  `);
25323
+ const deadBranchLines = computeDeadPythonBranchLines(lines);
25324
+ const listElems = new Map;
25325
+ const intConsts = new Map;
25723
25326
  for (let i2 = 0;i2 < lines.length; i2++) {
25724
25327
  const line = lines[i2];
25725
25328
  if (line.trimStart().startsWith("#"))
25726
25329
  continue;
25330
+ if (deadBranchLines.has(i2))
25331
+ continue;
25727
25332
  const subscriptAssign = line.match(/^\s*([\p{L}\p{N}_]+)\[(['"])([^'"]+)\2\]\s*=\s*(.+)$/u);
25728
25333
  if (subscriptAssign) {
25729
25334
  const [, container, , key, rhs2] = subscriptAssign;
@@ -25742,11 +25347,54 @@ function buildPythonTaintedVars(sourceCode) {
25742
25347
  }
25743
25348
  const containerAppendMatch = line.match(/^\s*([\p{L}\p{N}_]+)\.(append|extend|insert|add|push|put|appendleft)\s*\(\s*(.+?)\s*\)\s*$/u);
25744
25349
  if (containerAppendMatch) {
25745
- const [, receiver, , argExpr] = containerAppendMatch;
25350
+ const [, receiver, method, argExpr] = containerAppendMatch;
25746
25351
  const argIsTainted = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(argExpr));
25747
25352
  const argIsDirectSource = PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(argExpr));
25748
25353
  if (argIsTainted || argIsDirectSource)
25749
25354
  tainted.set(receiver, tainted.get(receiver) ?? i2 + 1);
25355
+ const elems = listElems.get(receiver);
25356
+ if (elems) {
25357
+ if (method === "append") {
25358
+ elems.push(argIsTainted || argIsDirectSource);
25359
+ } else if (method === "insert") {
25360
+ const insertAt = argExpr.match(/^(-?\d+)\s*,\s*(.+)$/);
25361
+ if (insertAt) {
25362
+ const idx = normalizeListIndex(Number(insertAt[1]), elems.length);
25363
+ const valueExpr = insertAt[2];
25364
+ const valueTainted = [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(valueExpr)) || PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(valueExpr));
25365
+ if (idx !== undefined)
25366
+ elems.splice(idx, 0, valueTainted);
25367
+ else
25368
+ listElems.delete(receiver);
25369
+ } else {
25370
+ listElems.delete(receiver);
25371
+ }
25372
+ } else {
25373
+ listElems.delete(receiver);
25374
+ }
25375
+ }
25376
+ continue;
25377
+ }
25378
+ const popMatch = line.match(/^\s*(?:([\p{L}\p{N}_]+)\s*=\s*)?([\p{L}\p{N}_]+)\.pop\s*\(\s*(-?\d+)?\s*\)\s*$/u);
25379
+ const delMatch = line.match(/^\s*del\s+([\p{L}\p{N}_]+)\s*\[\s*(-?\d+)\s*\]\s*$/u);
25380
+ if (popMatch || delMatch) {
25381
+ const receiver = popMatch ? popMatch[2] : delMatch[1];
25382
+ const rawIndex = popMatch ? popMatch[3] !== undefined ? Number(popMatch[3]) : -1 : Number(delMatch[2]);
25383
+ const elems = listElems.get(receiver);
25384
+ if (elems) {
25385
+ const idx = normalizeListIndex(rawIndex, elems.length);
25386
+ if (idx === undefined)
25387
+ listElems.delete(receiver);
25388
+ else {
25389
+ const [removed] = elems.splice(idx, 1);
25390
+ if (popMatch && popMatch[1]) {
25391
+ if (removed)
25392
+ tainted.set(popMatch[1], i2 + 1);
25393
+ else
25394
+ tainted.delete(popMatch[1]);
25395
+ }
25396
+ }
25397
+ }
25750
25398
  continue;
25751
25399
  }
25752
25400
  const augAssign = line.match(/^\s*([\p{L}\p{N}_]+)\s*\+=\s*(.+)$/u);
@@ -25769,7 +25417,51 @@ function buildPythonTaintedVars(sourceCode) {
25769
25417
  const assignMatch = line.match(/^\s*([\p{L}\p{N}_]+)\s*=\s*(.+)$/u);
25770
25418
  if (!assignMatch)
25771
25419
  continue;
25772
- const [, lhs, rhs] = assignMatch;
25420
+ const [, lhs, rhsRaw] = assignMatch;
25421
+ const constValue = evaluatePythonConstExpression(rhsRaw.trim(), intConsts);
25422
+ if (typeof constValue === "number")
25423
+ intConsts.set(lhs, constValue);
25424
+ else
25425
+ intConsts.delete(lhs);
25426
+ let rhs = rhsRaw;
25427
+ const ternary = rhsRaw.match(/^(.+?)\s+if\s+(.+?)\s+else\s+(.+)$/);
25428
+ if (ternary) {
25429
+ const decided = evaluatePythonConstExpression(ternary[2].trim(), intConsts);
25430
+ if (decided === true)
25431
+ rhs = ternary[1].trim();
25432
+ else if (decided === false)
25433
+ rhs = ternary[3].trim();
25434
+ }
25435
+ const listLiteral = rhs.trim().match(/^\[\s*(.*?)\s*\]$/);
25436
+ if (listLiteral) {
25437
+ const inner = listLiteral[1];
25438
+ if (inner === "") {
25439
+ listElems.set(lhs, []);
25440
+ } else if (!inner.includes("[") && !inner.includes("(")) {
25441
+ listElems.set(lhs, inner.split(",").map((part) => {
25442
+ const expr = part.trim();
25443
+ return [...tainted.keys()].some((v) => new RegExp(`(?<![\\p{L}\\p{N}_])${v}(?![\\p{L}\\p{N}_])`, "u").test(expr)) || PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(expr));
25444
+ }));
25445
+ } else {
25446
+ listElems.delete(lhs);
25447
+ }
25448
+ } else {
25449
+ listElems.delete(lhs);
25450
+ }
25451
+ const indexRead = rhs.trim().match(/^([\p{L}\p{N}_]+)\s*\[\s*(-?\d+)\s*\]$/u);
25452
+ if (indexRead) {
25453
+ const elems = listElems.get(indexRead[1]);
25454
+ if (elems) {
25455
+ const idx = normalizeListIndex(Number(indexRead[2]), elems.length);
25456
+ if (idx !== undefined) {
25457
+ if (elems[idx])
25458
+ tainted.set(lhs, i2 + 1);
25459
+ else
25460
+ tainted.delete(lhs);
25461
+ continue;
25462
+ }
25463
+ }
25464
+ }
25773
25465
  const isDirectSource = PYTHON_TAINTED_PATTERNS2.some((p) => p.pattern.test(rhs));
25774
25466
  let propagatedFrom;
25775
25467
  const dictAccessMatch = rhs.trim().match(/^([\p{L}\p{N}_]+)\[(['"])([^'"]+)\2\]$/u);
@@ -27024,6 +26716,210 @@ function findPythonSetMembershipXssGuardSanitizers(code) {
27024
26716
  }
27025
26717
  return sanitizers;
27026
26718
  }
26719
+ function findPythonTraversalRejectGuardSanitizers(code) {
26720
+ const sanitizers = [];
26721
+ const lines = code.split(`
26722
+ `);
26723
+ const guardOpen = /^(\s*)if\s+(['"])(\.\.[/\\]?)\2\s+in\s+([A-Za-z_][A-Za-z0-9_]*)\s*:\s*$/;
26724
+ const terminator = /\b(return|raise|abort\s*\(|sys\.exit\s*\()/;
26725
+ for (let i2 = 0;i2 < lines.length; i2++) {
26726
+ const m = guardOpen.exec(lines[i2]);
26727
+ if (!m)
26728
+ continue;
26729
+ const guardIndent = m[1].length;
26730
+ const guardedVar = m[4];
26731
+ let bodyHasTerminator = false;
26732
+ let blockEnd = -1;
26733
+ const maxScan = Math.min(lines.length, i2 + 26);
26734
+ for (let j = i2 + 1;j < maxScan; j++) {
26735
+ const line = lines[j];
26736
+ if (line.trim() === "")
26737
+ continue;
26738
+ const indent = line.length - line.trimStart().length;
26739
+ if (indent <= guardIndent) {
26740
+ blockEnd = j - 1;
26741
+ break;
26742
+ }
26743
+ if (terminator.test(line))
26744
+ bodyHasTerminator = true;
26745
+ }
26746
+ if (blockEnd === -1)
26747
+ blockEnd = Math.min(lines.length - 1, i2 + 25);
26748
+ if (!bodyHasTerminator)
26749
+ continue;
26750
+ const guarded = new Set([guardedVar]);
26751
+ const assignRe = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=(?!=)\s*(.*)$/;
26752
+ const mentionsGuarded = (text) => {
26753
+ for (const name2 of guarded) {
26754
+ if (new RegExp(`\\b${name2}\\b`).test(text))
26755
+ return true;
26756
+ }
26757
+ return false;
26758
+ };
26759
+ for (let l = blockEnd + 2;l <= lines.length; l++) {
26760
+ const lineText = lines[l - 1];
26761
+ const assign = assignRe.exec(lineText);
26762
+ if (assign) {
26763
+ const target = assign[1];
26764
+ const rhs = assign[2];
26765
+ if (mentionsGuarded(rhs))
26766
+ guarded.add(target);
26767
+ else if (target !== guardedVar)
26768
+ guarded.delete(target);
26769
+ }
26770
+ if (!mentionsGuarded(lineText))
26771
+ continue;
26772
+ sanitizers.push({
26773
+ type: "python_traversal_reject_guard",
26774
+ method: "if",
26775
+ line: l,
26776
+ sanitizes: ["path_traversal"]
26777
+ });
26778
+ }
26779
+ }
26780
+ return sanitizers;
26781
+ }
26782
+ function findPythonStringLiteralGuardSanitizers(code) {
26783
+ const sanitizers = [];
26784
+ const lines = code.split(`
26785
+ `);
26786
+ const terminator = /\b(return|raise|abort\s*\(|sys\.exit\s*\()/;
26787
+ const Q = `(?:'(?:\\\\')'|"'"|'"'|"(?:\\\\")")`;
26788
+ for (let i2 = 0;i2 < lines.length; i2++) {
26789
+ const guard = lines[i2].match(new RegExp(`^(\\s*)if\\s+not\\s+([A-Za-z_][A-Za-z0-9_]*)\\.startswith\\(\\s*${Q}\\s*\\)` + `\\s+or\\s+not\\s+\\2\\.endswith\\(\\s*${Q}\\s*\\)` + `\\s+or\\s+${Q}\\s+in\\s+\\2\\[1:-1\\]\\s*:\\s*$`));
26790
+ if (!guard)
26791
+ continue;
26792
+ const guardIndent = guard[1].length;
26793
+ const guardedVar = guard[2];
26794
+ let bodyHasTerminator = false;
26795
+ let blockEnd = -1;
26796
+ const maxScan = Math.min(lines.length, i2 + 26);
26797
+ for (let j = i2 + 1;j < maxScan; j++) {
26798
+ const line = lines[j];
26799
+ if (line.trim() === "")
26800
+ continue;
26801
+ const indent = line.length - line.trimStart().length;
26802
+ if (indent <= guardIndent) {
26803
+ blockEnd = j - 1;
26804
+ break;
26805
+ }
26806
+ if (terminator.test(line))
26807
+ bodyHasTerminator = true;
26808
+ }
26809
+ if (blockEnd === -1)
26810
+ blockEnd = Math.min(lines.length - 1, i2 + 25);
26811
+ if (!bodyHasTerminator)
26812
+ continue;
26813
+ const varRe = new RegExp(`\\b${guardedVar}\\b`);
26814
+ for (let l = blockEnd + 2;l <= lines.length; l++) {
26815
+ if (!varRe.test(lines[l - 1]))
26816
+ continue;
26817
+ sanitizers.push({
26818
+ type: "python_string_literal_guard",
26819
+ method: "if",
26820
+ line: l,
26821
+ sanitizes: ["code_injection"]
26822
+ });
26823
+ }
26824
+ }
26825
+ return sanitizers;
26826
+ }
26827
+ function findPythonDefaultSaxParserXxeSanitizers(code) {
26828
+ const sanitizers = [];
26829
+ const lines = code.split(`
26830
+ `);
26831
+ const parserVars = new Set;
26832
+ for (const line of lines) {
26833
+ const made = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?:xml\.)?sax\.make_parser\s*\(/);
26834
+ if (made)
26835
+ parserVars.add(made[1]);
26836
+ }
26837
+ if (parserVars.size === 0)
26838
+ return sanitizers;
26839
+ for (const line of lines) {
26840
+ for (const parser of [...parserVars]) {
26841
+ const enabled = new RegExp(`\\b${parser}\\.setFeature\\s*\\([^,]*external_(?:ges|pes)[^,]*,\\s*True\\s*\\)`);
26842
+ const resolver = new RegExp(`\\b${parser}\\.setEntityResolver\\s*\\(`);
26843
+ const rebound = new RegExp(`^\\s*${parser}\\s*=(?!=)`);
26844
+ if (enabled.test(line) || resolver.test(line))
26845
+ parserVars.delete(parser);
26846
+ else if (rebound.test(line) && !/make_parser\s*\(/.test(line))
26847
+ parserVars.delete(parser);
26848
+ }
26849
+ }
26850
+ if (parserVars.size === 0)
26851
+ return sanitizers;
26852
+ for (let i2 = 0;i2 < lines.length; i2++) {
26853
+ const line = lines[i2];
26854
+ const parseCall = /\b(?:minidom\.)?parseString\s*\(|\b(?:minidom\.)?parse\s*\(|\bsax\.parse(?:String)?\s*\(/;
26855
+ if (!parseCall.test(line))
26856
+ continue;
26857
+ const usesDefaultParser = [...parserVars].some((p) => new RegExp(`\\b${p}\\b`).test(line));
26858
+ if (!usesDefaultParser)
26859
+ continue;
26860
+ sanitizers.push({
26861
+ type: "python_default_sax_parser",
26862
+ method: "make_parser",
26863
+ line: i2 + 1,
26864
+ sanitizes: ["xxe"]
26865
+ });
26866
+ }
26867
+ return sanitizers;
26868
+ }
26869
+ function findPythonUrlAllowlistRedirectSanitizers(code) {
26870
+ const sanitizers = [];
26871
+ const lines = code.split(`
26872
+ `);
26873
+ const parsedFrom = new Map;
26874
+ for (const line of lines) {
26875
+ const m = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?:urllib\.parse\.)?urlparse\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*\)/);
26876
+ if (m)
26877
+ parsedFrom.set(m[1], m[2]);
26878
+ }
26879
+ if (parsedFrom.size === 0)
26880
+ return sanitizers;
26881
+ const terminator = /\b(return|raise|abort\s*\(|sys\.exit\s*\()/;
26882
+ for (let i2 = 0;i2 < lines.length; i2++) {
26883
+ const guard = lines[i2].match(/^(\s*)if\s+([A-Za-z_][A-Za-z0-9_]*)\.netloc\s+not\s+in\s+[[({]/);
26884
+ if (!guard)
26885
+ continue;
26886
+ const guardIndent = guard[1].length;
26887
+ const rawVar = parsedFrom.get(guard[2]);
26888
+ if (!rawVar)
26889
+ continue;
26890
+ let bodyHasTerminator = false;
26891
+ let blockEnd = -1;
26892
+ const maxScan = Math.min(lines.length, i2 + 26);
26893
+ for (let j = i2 + 1;j < maxScan; j++) {
26894
+ const line = lines[j];
26895
+ if (line.trim() === "")
26896
+ continue;
26897
+ const indent = line.length - line.trimStart().length;
26898
+ if (indent <= guardIndent) {
26899
+ blockEnd = j - 1;
26900
+ break;
26901
+ }
26902
+ if (terminator.test(line))
26903
+ bodyHasTerminator = true;
26904
+ }
26905
+ if (blockEnd === -1)
26906
+ blockEnd = Math.min(lines.length - 1, i2 + 25);
26907
+ if (!bodyHasTerminator)
26908
+ continue;
26909
+ const varRe = new RegExp(`\\b${rawVar}\\b`);
26910
+ for (let l = blockEnd + 2;l <= lines.length; l++) {
26911
+ if (!varRe.test(lines[l - 1]))
26912
+ continue;
26913
+ sanitizers.push({
26914
+ type: "python_url_allowlist_guard",
26915
+ method: "if",
26916
+ line: l,
26917
+ sanitizes: ["open_redirect"]
26918
+ });
26919
+ }
26920
+ }
26921
+ return sanitizers;
26922
+ }
27027
26923
  function findPythonDefusedXmlSanitizers(code) {
27028
26924
  const sanitizers = [];
27029
26925
  const lines = code.split(`
@@ -32044,14 +31940,20 @@ class SinkFilterPass {
32044
31940
  if (sink.type !== "xpath_injection")
32045
31941
  return true;
32046
31942
  const sinkLineText = sourceLines[sink.line - 1] ?? "";
32047
- const taintedVarOnLine = [...pyTaintedVars.keys()].find((v) => new RegExp(`\\b${v}\\b`).test(sinkLineText));
31943
+ const taintedValueVars = [...pyTaintedVars.keys()].filter((v) => new RegExp(`(?<![\\w.])${v}\\b(?!\\s*=(?!=))`).test(sinkLineText));
31944
+ const taintedVarOnLine = taintedValueVars[0];
32048
31945
  const oopVarOnLine = [...oopFieldVars].find((v) => sinkLineText.includes(v));
32049
31946
  if (oopVarOnLine)
32050
31947
  return true;
32051
31948
  if (!taintedVarOnLine)
32052
31949
  return false;
31950
+ const neutralised = (v) => pySanitizedVars.has(v) || new RegExp(`\\.xpath\\s*\\([^)]*\\b\\w+\\s*=\\s*\\b${v}\\b`).test(sinkLineText) || isXPathQuoteEscapedOnLine(sinkLineText, v);
31951
+ if (taintedValueVars.every(neutralised))
31952
+ return false;
32053
31953
  if (pySanitizedVars.has(taintedVarOnLine))
32054
31954
  return false;
31955
+ if (isXPathQuoteEscapedOnLine(sinkLineText, taintedVarOnLine))
31956
+ return false;
32055
31957
  if (new RegExp(`\\.xpath\\s*\\([^)]*\\b\\w+\\s*=\\s*\\b${taintedVarOnLine}\\b`).test(sinkLineText))
32056
31958
  return false;
32057
31959
  return true;
@@ -33155,6 +33057,28 @@ function filterSanitizedSinks(sinks, sanitizers, calls) {
33155
33057
  return true;
33156
33058
  });
33157
33059
  }
33060
+ function isXPathQuoteEscapedOnLine(lineText, varName) {
33061
+ const STRING_LITERAL = `'(?:[^'\\\\]|\\\\.)*'|"(?:[^"\\\\]|\\\\.)*"`;
33062
+ const replaceCall = new RegExp(`^${varName}\\.replace\\s*\\(\\s*(${STRING_LITERAL})\\s*,\\s*(${STRING_LITERAL})\\s*\\)`);
33063
+ const decode = (literal) => literal.slice(1, -1).replace(/\\(.)/g, "$1");
33064
+ const occurrence = new RegExp(`(?<![\\w.])${varName}\\b`, "g");
33065
+ let match;
33066
+ let seen = 0;
33067
+ while ((match = occurrence.exec(lineText)) !== null) {
33068
+ seen++;
33069
+ const rest = lineText.slice(match.index);
33070
+ const call = replaceCall.exec(rest);
33071
+ if (!call)
33072
+ return false;
33073
+ const searched = decode(call[1]);
33074
+ const replacement = decode(call[2]);
33075
+ if (searched !== "'" && searched !== '"')
33076
+ return false;
33077
+ if (replacement.includes("'") || replacement.includes('"'))
33078
+ return false;
33079
+ }
33080
+ return seen > 0;
33081
+ }
33158
33082
 
33159
33083
  // ../circle-ir/dist/analysis/passes/sink-semantics-pass.js
33160
33084
  function buildRegistry(entries) {
@@ -46492,7 +46416,7 @@ var colors = {
46492
46416
  };
46493
46417
 
46494
46418
  // src/version.ts
46495
- var version = "3.194.0";
46419
+ var version = "3.197.0";
46496
46420
 
46497
46421
  // src/formatters.ts
46498
46422
  var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cognium-dev",
3
- "version": "3.194.0",
3
+ "version": "3.197.0",
4
4
  "description": "Static Application Security Testing CLI for detecting security vulnerabilities via taint tracking",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -66,7 +66,7 @@
66
66
  },
67
67
  "dependencies": {
68
68
  "@cognium/project-profile-detect": "^1.1.0",
69
- "circle-ir": "^3.194.0"
69
+ "circle-ir": "^3.197.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",