cognium-dev 3.128.0 → 3.129.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 +300 -1
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -22600,6 +22600,10 @@ class LanguageSourcesPass {
22600
22600
  if (language === "go") {
22601
22601
  additionalSanitizers.push(...findGoMapAllowlistGuardSanitizers(code));
22602
22602
  additionalSanitizers.push(...findGoHtmlTemplateImportSanitizers(code));
22603
+ const goMisconfigFindings = findGoPatternFindings(code, graph.ir.meta.file);
22604
+ for (const finding of goMisconfigFindings) {
22605
+ ctx.addFinding(finding);
22606
+ }
22603
22607
  }
22604
22608
  if (language === "python") {
22605
22609
  additionalSanitizers.push(...findPythonNetlocAllowlistGuardSanitizers(code));
@@ -22621,6 +22625,18 @@ class LanguageSourcesPass {
22621
22625
  for (const finding of rustMisconfigFindings) {
22622
22626
  ctx.addFinding(finding);
22623
22627
  }
22628
+ for (const finding of findRustHardcodedCredentialFindings(code, graph.ir.meta.file)) {
22629
+ ctx.addFinding(finding);
22630
+ }
22631
+ for (const finding of findRustInsecureCookieFindings(code, graph.ir.meta.file)) {
22632
+ ctx.addFinding(finding);
22633
+ }
22634
+ for (const finding of findRustJwtVerifyDisabledFindings(code, graph.ir.meta.file)) {
22635
+ ctx.addFinding(finding);
22636
+ }
22637
+ for (const finding of findRustWeakCryptoEcbFindings(code, graph.ir.meta.file)) {
22638
+ ctx.addFinding(finding);
22639
+ }
22624
22640
  }
22625
22641
  if (language === "javascript" || language === "typescript" || language === "htmljs") {
22626
22642
  additionalSanitizers.push(...findJsSafeJsonParseSanitizers(code));
@@ -22628,12 +22644,18 @@ class LanguageSourcesPass {
22628
22644
  additionalSanitizers.push(...findJsCsvFormulaPrefixSanitizers(code));
22629
22645
  additionalSanitizers.push(...findJsWrapperFunctionSanitizers(code));
22630
22646
  additionalSanitizers.push(...findJsSsrfAllowlistGuardSanitizers(code));
22647
+ for (const finding of findJsPatternFindings(code, graph.ir.meta.file)) {
22648
+ ctx.addFinding(finding);
22649
+ }
22631
22650
  }
22632
22651
  if (language === "java") {
22633
22652
  additionalSanitizers.push(...findJavaSafeJsonParseSanitizers(code));
22634
22653
  additionalSanitizers.push(...findJavaPathNormalizeStartsWithGuardSanitizers(code));
22635
22654
  additionalSanitizers.push(...findJavaInlineCrlfStripLogSanitizers(code));
22636
22655
  additionalSanitizers.push(...findJavaArgvFormExecSanitizers(code));
22656
+ for (const finding of findJavaPatternFindings(code, graph.ir.meta.file)) {
22657
+ ctx.addFinding(finding);
22658
+ }
22637
22659
  }
22638
22660
  if (language === "python" || language === "javascript" || language === "typescript" || language === "go") {
22639
22661
  const exfilFindings = findExternalSecretExfiltrationFindings(code, graph.ir.meta.file, language);
@@ -25145,6 +25167,283 @@ function findRustPatternFindings(code, file) {
25145
25167
  }
25146
25168
  return out2;
25147
25169
  }
25170
+ function findRustHardcodedCredentialFindings(code, file) {
25171
+ const out2 = [];
25172
+ const lines = code.split(`
25173
+ `);
25174
+ const re = /\b(?:pub\s+)?(?:const|static)\s+([A-Z][A-Z0-9_]*)\s*:\s*&\s*'?[a-z_]*\s*str\s*=\s*"([^"]+)"/;
25175
+ const nameRe = /(?:^|_)(?:API[_]?KEY|SECRET|TOKEN|PASSWORD|PASSWD|PWD|AUTH)(?:_|$)/i;
25176
+ for (let i2 = 0;i2 < lines.length; i2++) {
25177
+ const raw = lines[i2];
25178
+ const trimmed = raw.trim();
25179
+ if (!trimmed || trimmed.startsWith("//"))
25180
+ continue;
25181
+ const m = trimmed.match(re);
25182
+ if (!m)
25183
+ continue;
25184
+ const name2 = m[1];
25185
+ const value = m[2];
25186
+ if (!nameRe.test(name2))
25187
+ continue;
25188
+ if (value.length < 8)
25189
+ continue;
25190
+ if (/^(?:xxx|todo|fixme|placeholder|changeme)/i.test(value))
25191
+ continue;
25192
+ out2.push({
25193
+ id: `hardcoded-credential-${file}-${i2 + 1}`,
25194
+ pass: "language-sources",
25195
+ category: "security",
25196
+ rule_id: "hardcoded-credential",
25197
+ cwe: "CWE-798",
25198
+ severity: "high",
25199
+ level: "error",
25200
+ message: `Hardcoded credential: const ${name2} contains a literal secret value`,
25201
+ file,
25202
+ line: i2 + 1,
25203
+ snippet: trimmed.substring(0, 100)
25204
+ });
25205
+ }
25206
+ return out2;
25207
+ }
25208
+ function findRustInsecureCookieFindings(code, file) {
25209
+ const out2 = [];
25210
+ const lines = code.split(`
25211
+ `);
25212
+ const builderRe = /\bCookie\s*::\s*build\s*\(/;
25213
+ const insecureFlagRe = /\.\s*(?:secure|http_only)\s*\(\s*false\s*\)/;
25214
+ for (let i2 = 0;i2 < lines.length; i2++) {
25215
+ const raw = lines[i2];
25216
+ const trimmed = raw.trim();
25217
+ if (!trimmed || trimmed.startsWith("//"))
25218
+ continue;
25219
+ if (!builderRe.test(trimmed))
25220
+ continue;
25221
+ if (!insecureFlagRe.test(trimmed))
25222
+ continue;
25223
+ out2.push({
25224
+ id: `insecure-cookie-${file}-${i2 + 1}`,
25225
+ pass: "language-sources",
25226
+ category: "security",
25227
+ rule_id: "insecure-cookie",
25228
+ cwe: "CWE-1004",
25229
+ severity: "medium",
25230
+ level: "warning",
25231
+ message: "Insecure cookie: Cookie::build chain disables Secure / HttpOnly flag(s)",
25232
+ file,
25233
+ line: i2 + 1,
25234
+ snippet: trimmed.substring(0, 100)
25235
+ });
25236
+ }
25237
+ return out2;
25238
+ }
25239
+ function findRustJwtVerifyDisabledFindings(code, file) {
25240
+ const out2 = [];
25241
+ const lines = code.split(`
25242
+ `);
25243
+ const re = /\.\s*insecure_disable_signature_validation\s*\(/;
25244
+ for (let i2 = 0;i2 < lines.length; i2++) {
25245
+ const raw = lines[i2];
25246
+ const trimmed = raw.trim();
25247
+ if (!trimmed || trimmed.startsWith("//"))
25248
+ continue;
25249
+ if (!re.test(trimmed))
25250
+ continue;
25251
+ out2.push({
25252
+ id: `jwt-verify-disabled-${file}-${i2 + 1}`,
25253
+ pass: "language-sources",
25254
+ category: "security",
25255
+ rule_id: "jwt-verify-disabled",
25256
+ cwe: "CWE-347",
25257
+ severity: "critical",
25258
+ level: "error",
25259
+ message: "JWT signature verification disabled: " + "Validation::insecure_disable_signature_validation() forfeits signature enforcement",
25260
+ file,
25261
+ line: i2 + 1,
25262
+ snippet: trimmed.substring(0, 100)
25263
+ });
25264
+ }
25265
+ return out2;
25266
+ }
25267
+ function findRustWeakCryptoEcbFindings(code, file) {
25268
+ const out2 = [];
25269
+ const lines = code.split(`
25270
+ `);
25271
+ const ctorRe = /\bAes(?:128|192|256)(?:Ecb)?\s*::\s*new\s*\(/;
25272
+ const blockOpRe = /\.\s*(encrypt_block|decrypt_block)\s*\(/;
25273
+ let sawCtor = false;
25274
+ for (const line of lines) {
25275
+ if (ctorRe.test(line)) {
25276
+ sawCtor = true;
25277
+ break;
25278
+ }
25279
+ }
25280
+ if (!sawCtor)
25281
+ return out2;
25282
+ for (let i2 = 0;i2 < lines.length; i2++) {
25283
+ const raw = lines[i2];
25284
+ const trimmed = raw.trim();
25285
+ if (!trimmed || trimmed.startsWith("//"))
25286
+ continue;
25287
+ if (!blockOpRe.test(trimmed))
25288
+ continue;
25289
+ out2.push({
25290
+ id: `weak-crypto-${file}-${i2 + 1}`,
25291
+ pass: "language-sources",
25292
+ category: "security",
25293
+ rule_id: "weak-crypto",
25294
+ cwe: "CWE-327",
25295
+ severity: "high",
25296
+ level: "error",
25297
+ message: "Weak crypto (ECB mode): raw Aes::encrypt_block/decrypt_block " + "leaks repeating-block patterns. Use AES-GCM, AES-CTR, or " + "AES-CBC with an HMAC.",
25298
+ file,
25299
+ line: i2 + 1,
25300
+ snippet: trimmed.substring(0, 100)
25301
+ });
25302
+ }
25303
+ return out2;
25304
+ }
25305
+ function findJavaPatternFindings(code, file) {
25306
+ const out2 = [];
25307
+ const lines = code.split(`
25308
+ `);
25309
+ const jwtDecodeRe = /\bJWT\s*\.\s*decode\s*\(/;
25310
+ for (let i2 = 0;i2 < lines.length; i2++) {
25311
+ const raw = lines[i2];
25312
+ const trimmed = raw.trim();
25313
+ if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("*"))
25314
+ continue;
25315
+ if (!jwtDecodeRe.test(trimmed))
25316
+ continue;
25317
+ if (/\.\s*verify\s*\(/.test(trimmed))
25318
+ continue;
25319
+ out2.push({
25320
+ id: `jwt-verify-disabled-${file}-${i2 + 1}-decode`,
25321
+ pass: "language-sources",
25322
+ category: "security",
25323
+ rule_id: "jwt-verify-disabled",
25324
+ cwe: "CWE-347",
25325
+ severity: "critical",
25326
+ level: "error",
25327
+ message: "JWT signature not verified: auth0 `JWT.decode(token)` parses " + "without checking the signature. Use `JWT.require(<algorithm>)" + ".build().verify(token)` to enforce verification.",
25328
+ file,
25329
+ line: i2 + 1,
25330
+ snippet: trimmed.substring(0, 100)
25331
+ });
25332
+ }
25333
+ const anonStartRe = /\bnew\s+X509TrustManager\s*\(\s*\)\s*\{/;
25334
+ const checkServerSig = /\bcheckServerTrusted\s*\([^)]*\)\s*(?:throws\s+[^\{]*)?\{\s*\}/;
25335
+ for (let i2 = 0;i2 < lines.length; i2++) {
25336
+ const raw = lines[i2];
25337
+ if (!anonStartRe.test(raw))
25338
+ continue;
25339
+ const end = Math.min(lines.length, i2 + 16);
25340
+ let foundAt = -1;
25341
+ for (let j = i2;j < end; j++) {
25342
+ if (checkServerSig.test(lines[j])) {
25343
+ foundAt = j;
25344
+ break;
25345
+ }
25346
+ }
25347
+ if (foundAt < 0)
25348
+ continue;
25349
+ out2.push({
25350
+ id: `tls-verify-disabled-${file}-${foundAt + 1}`,
25351
+ pass: "language-sources",
25352
+ category: "security",
25353
+ rule_id: "tls-verify-disabled",
25354
+ cwe: "CWE-295",
25355
+ severity: "high",
25356
+ level: "error",
25357
+ message: "TLS certificate verification disabled: anonymous X509TrustManager " + "with empty checkServerTrusted body accepts every certificate.",
25358
+ file,
25359
+ line: foundAt + 1,
25360
+ snippet: lines[foundAt].trim().substring(0, 100)
25361
+ });
25362
+ }
25363
+ return out2;
25364
+ }
25365
+ function findGoPatternFindings(code, file) {
25366
+ const out2 = [];
25367
+ const lines = code.split(`
25368
+ `);
25369
+ const cipherVars = new Set;
25370
+ const ctorRe = /\b([a-zA-Z_]\w*)\s*(?:,\s*[a-zA-Z_]\w*)?\s*:?=\s*aes\.NewCipher\s*\(/;
25371
+ for (const line of lines) {
25372
+ const m = line.match(ctorRe);
25373
+ if (m)
25374
+ cipherVars.add(m[1]);
25375
+ }
25376
+ if (cipherVars.size === 0)
25377
+ return out2;
25378
+ for (const v of Array.from(cipherVars)) {
25379
+ const wrapRe = new RegExp(`\\bcipher\\.New(?:GCM|CBCEncrypter|CBCDecrypter|CTR|OFB|CFBEncrypter|CFBDecrypter)\\s*\\(\\s*${v}\\b`);
25380
+ for (const line of lines) {
25381
+ if (wrapRe.test(line)) {
25382
+ cipherVars.delete(v);
25383
+ break;
25384
+ }
25385
+ }
25386
+ }
25387
+ if (cipherVars.size === 0)
25388
+ return out2;
25389
+ for (let i2 = 0;i2 < lines.length; i2++) {
25390
+ const raw = lines[i2];
25391
+ const trimmed = raw.trim();
25392
+ if (!trimmed || trimmed.startsWith("//"))
25393
+ continue;
25394
+ for (const v of cipherVars) {
25395
+ const opRe = new RegExp(`\\b${v}\\s*\\.\\s*(?:Encrypt|Decrypt)\\s*\\(`);
25396
+ if (!opRe.test(trimmed))
25397
+ continue;
25398
+ out2.push({
25399
+ id: `weak-crypto-${file}-${i2 + 1}`,
25400
+ pass: "language-sources",
25401
+ category: "security",
25402
+ rule_id: "weak-crypto",
25403
+ cwe: "CWE-327",
25404
+ severity: "high",
25405
+ level: "error",
25406
+ message: "Weak crypto (ECB mode): raw aes.Cipher.Encrypt/Decrypt on a " + "block leaks repeating-block patterns. Wrap with cipher.NewGCM, " + "cipher.NewCTR, or cipher.NewCBCEncrypter + HMAC.",
25407
+ file,
25408
+ line: i2 + 1,
25409
+ snippet: trimmed.substring(0, 100)
25410
+ });
25411
+ break;
25412
+ }
25413
+ }
25414
+ return out2;
25415
+ }
25416
+ function findJsPatternFindings(code, file) {
25417
+ const out2 = [];
25418
+ const lines = code.split(`
25419
+ `);
25420
+ const parseRe = /\blibxml(?:js)?\s*\.\s*parseXml(?:String)?\s*\(/;
25421
+ const noentTrueRe = /\bnoent\s*:\s*true\b/;
25422
+ for (let i2 = 0;i2 < lines.length; i2++) {
25423
+ const raw = lines[i2];
25424
+ const trimmed = raw.trim();
25425
+ if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("*"))
25426
+ continue;
25427
+ if (!parseRe.test(trimmed))
25428
+ continue;
25429
+ if (!noentTrueRe.test(trimmed))
25430
+ continue;
25431
+ out2.push({
25432
+ id: `xml-entity-expansion-${file}-${i2 + 1}`,
25433
+ pass: "language-sources",
25434
+ category: "security",
25435
+ rule_id: "xml-entity-expansion",
25436
+ cwe: "CWE-611",
25437
+ severity: "high",
25438
+ level: "error",
25439
+ message: "XML external entity resolution enabled: libxmljs parseXml " + "called with `noent: true` resolves external entities (XXE / " + "billion-laughs). Omit the flag or set `noent: false`.",
25440
+ file,
25441
+ line: i2 + 1,
25442
+ snippet: trimmed.substring(0, 100)
25443
+ });
25444
+ }
25445
+ return out2;
25446
+ }
25148
25447
 
25149
25448
  // ../circle-ir/dist/analysis/passes/sink-filter-pass.js
25150
25449
  var JS_XSS_SANITIZERS = [
@@ -38272,7 +38571,7 @@ var colors = {
38272
38571
  };
38273
38572
 
38274
38573
  // src/version.ts
38275
- var version = "3.128.0";
38574
+ var version = "3.129.0";
38276
38575
 
38277
38576
  // src/formatters.ts
38278
38577
  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.128.0",
3
+ "version": "3.129.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.128.0"
69
+ "circle-ir": "^3.129.0"
70
70
  },
71
71
  "devDependencies": {
72
72
  "@types/node": "^25.5.0",