cognium-dev 4.9.7 → 4.9.9
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.
- package/dist/cli.js +138 -39
- package/package.json +6 -6
package/dist/cli.js
CHANGED
|
@@ -13764,17 +13764,27 @@ function isSafeCSharpProcessStartCall(call, pattern, language, sourceLines) {
|
|
|
13764
13764
|
function stripCsLiterals(line) {
|
|
13765
13765
|
return line.replace(/\/\/.*$/, "").replace(/@?"(?:[^"\\]|\\.)*"/g, '""').replace(/'(?:[^'\\]|\\.)'/g, "''");
|
|
13766
13766
|
}
|
|
13767
|
+
var _csDepthLines;
|
|
13768
|
+
var _csDepthPrefix;
|
|
13767
13769
|
function csBraceDepthBefore(lines, idx) {
|
|
13768
|
-
|
|
13769
|
-
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
|
|
13770
|
+
if (lines !== _csDepthLines) {
|
|
13771
|
+
const pref = new Int32Array(lines.length + 1);
|
|
13772
|
+
let depth = 0;
|
|
13773
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
13774
|
+
pref[i2] = depth;
|
|
13775
|
+
for (const ch of stripCsLiterals(lines[i2])) {
|
|
13776
|
+
if (ch === "{")
|
|
13777
|
+
depth++;
|
|
13778
|
+
else if (ch === "}")
|
|
13779
|
+
depth--;
|
|
13780
|
+
}
|
|
13775
13781
|
}
|
|
13782
|
+
pref[lines.length] = depth;
|
|
13783
|
+
_csDepthLines = lines;
|
|
13784
|
+
_csDepthPrefix = pref;
|
|
13776
13785
|
}
|
|
13777
|
-
|
|
13786
|
+
const clamped = idx < 0 ? 0 : idx > lines.length ? lines.length : idx;
|
|
13787
|
+
return _csDepthPrefix[clamped];
|
|
13778
13788
|
}
|
|
13779
13789
|
function netBraces(fragment) {
|
|
13780
13790
|
let n = 0;
|
|
@@ -13885,6 +13895,33 @@ function csThenBlock(lines, ifIdx, rest) {
|
|
|
13885
13895
|
}
|
|
13886
13896
|
return { start: ifIdx, end: firstIdx, earlyExit: isExit(firstText.trim()) };
|
|
13887
13897
|
}
|
|
13898
|
+
var _csGuardLines;
|
|
13899
|
+
var _csGuardMap;
|
|
13900
|
+
function csEqualityGuardIndex(lines) {
|
|
13901
|
+
if (lines === _csGuardLines && _csGuardMap)
|
|
13902
|
+
return _csGuardMap;
|
|
13903
|
+
const map = new Map;
|
|
13904
|
+
for (let i2 = 0;i2 < lines.length; i2++) {
|
|
13905
|
+
const parts2 = splitCsIf(lines[i2]);
|
|
13906
|
+
if (!parts2)
|
|
13907
|
+
continue;
|
|
13908
|
+
const guard = csEqualityGuard(parts2.cond);
|
|
13909
|
+
if (!guard)
|
|
13910
|
+
continue;
|
|
13911
|
+
const entry = { i: i2, rest: parts2.rest, ifCol: parts2.ifCol, op: guard.op };
|
|
13912
|
+
for (const id of csIdentifiers(guard.exprSide)) {
|
|
13913
|
+
let arr = map.get(id);
|
|
13914
|
+
if (!arr) {
|
|
13915
|
+
arr = [];
|
|
13916
|
+
map.set(id, arr);
|
|
13917
|
+
}
|
|
13918
|
+
arr.push(entry);
|
|
13919
|
+
}
|
|
13920
|
+
}
|
|
13921
|
+
_csGuardLines = lines;
|
|
13922
|
+
_csGuardMap = map;
|
|
13923
|
+
return map;
|
|
13924
|
+
}
|
|
13888
13925
|
function isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines) {
|
|
13889
13926
|
if (language !== "csharp")
|
|
13890
13927
|
return false;
|
|
@@ -13903,24 +13940,25 @@ function isCSharpSsrfHostAllowlistGuarded(call, pattern, language, sourceLines)
|
|
|
13903
13940
|
return false;
|
|
13904
13941
|
const sinkIdx = call.location.line - 1;
|
|
13905
13942
|
const sinkDepth = csBraceDepthBefore(sourceLines, sinkIdx);
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
13912
|
-
|
|
13913
|
-
|
|
13914
|
-
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
13918
|
-
|
|
13919
|
-
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13943
|
+
const guardMap = csEqualityGuardIndex(sourceLines);
|
|
13944
|
+
const checked = new Set;
|
|
13945
|
+
for (const cand of candidates) {
|
|
13946
|
+
const guards = guardMap.get(cand);
|
|
13947
|
+
if (!guards)
|
|
13948
|
+
continue;
|
|
13949
|
+
for (const g of guards) {
|
|
13950
|
+
if (g.i >= sinkIdx || checked.has(g))
|
|
13951
|
+
continue;
|
|
13952
|
+
checked.add(g);
|
|
13953
|
+
const block = csThenBlock(sourceLines, g.i, g.rest);
|
|
13954
|
+
if (g.op === "==") {
|
|
13955
|
+
if (sinkIdx >= block.start && sinkIdx <= block.end)
|
|
13956
|
+
return true;
|
|
13957
|
+
} else {
|
|
13958
|
+
const guardDepth = csBraceDepthBefore(sourceLines, g.i) + netBraces(stripCsLiterals(sourceLines[g.i]).slice(0, g.ifCol));
|
|
13959
|
+
if (block.earlyExit && sinkIdx > block.end && guardDepth === sinkDepth) {
|
|
13960
|
+
return true;
|
|
13961
|
+
}
|
|
13924
13962
|
}
|
|
13925
13963
|
}
|
|
13926
13964
|
}
|
|
@@ -26939,6 +26977,13 @@ function buildJavaTaintedVars(sourceCode, seedVars) {
|
|
|
26939
26977
|
"interface",
|
|
26940
26978
|
"enum"
|
|
26941
26979
|
]);
|
|
26980
|
+
const complexTaintedRes = [];
|
|
26981
|
+
for (const v of knownTainted) {
|
|
26982
|
+
if (!/^[\p{L}\p{N}_]+$/u.test(v)) {
|
|
26983
|
+
const esc = v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26984
|
+
complexTaintedRes.push(new RegExp(`(?<![\\p{L}\\p{N}_])${esc}(?![\\p{L}\\p{N}_])`, "u"));
|
|
26985
|
+
}
|
|
26986
|
+
}
|
|
26942
26987
|
let changed = true;
|
|
26943
26988
|
let guard = 0;
|
|
26944
26989
|
while (changed && guard < lines.length + 2) {
|
|
@@ -26960,9 +27005,9 @@ function buildJavaTaintedVars(sourceCode, seedVars) {
|
|
|
26960
27005
|
continue;
|
|
26961
27006
|
if (knownTainted.has(lhs))
|
|
26962
27007
|
continue;
|
|
26963
|
-
const escaped = (v) => v.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
26964
27008
|
const rhsCode = rhs.replace(/\$@?"(?:[^"\\]|\\.)*"/g, (lit) => " " + [...lit.matchAll(/\{([^}]*)\}/g)].map((x) => x[1]).join(" ") + " ").replace(/@?"(?:[^"\\]|\\.)*"/g, " ").replace(/'(?:[^'\\]|\\.)'/g, " ");
|
|
26965
|
-
const
|
|
27009
|
+
const rhsIdents = rhsCode.match(/[\p{L}\p{N}_]+/gu);
|
|
27010
|
+
const ref = rhsIdents !== null && rhsIdents.some((t) => knownTainted.has(t)) || complexTaintedRes.length > 0 && complexTaintedRes.some((re) => re.test(rhsCode));
|
|
26966
27011
|
if (ref) {
|
|
26967
27012
|
derived.set(lhs, i2 + 1);
|
|
26968
27013
|
knownTainted.add(lhs);
|
|
@@ -36283,13 +36328,22 @@ function detectParameterSinkFlows(types, calls, sources, sinks, unreachableLines
|
|
|
36283
36328
|
}
|
|
36284
36329
|
return flows;
|
|
36285
36330
|
}
|
|
36331
|
+
var _reassignSplitCode;
|
|
36332
|
+
var _reassignSplitLines;
|
|
36333
|
+
function splitLinesCached(code) {
|
|
36334
|
+
if (code === _reassignSplitCode && _reassignSplitLines)
|
|
36335
|
+
return _reassignSplitLines;
|
|
36336
|
+
_reassignSplitCode = code;
|
|
36337
|
+
_reassignSplitLines = code.split(`
|
|
36338
|
+
`);
|
|
36339
|
+
return _reassignSplitLines;
|
|
36340
|
+
}
|
|
36286
36341
|
function isReassignedToLiteralBetween(code, variable, srcLine, sinkLine) {
|
|
36287
36342
|
if (!variable || sinkLine - srcLine < 2)
|
|
36288
36343
|
return false;
|
|
36289
36344
|
if (!/^[A-Za-z_][\w]*$/.test(variable))
|
|
36290
36345
|
return false;
|
|
36291
|
-
const lines = code
|
|
36292
|
-
`);
|
|
36346
|
+
const lines = splitLinesCached(code);
|
|
36293
36347
|
const lo = Math.max(0, srcLine);
|
|
36294
36348
|
const hi = Math.min(lines.length, sinkLine - 1);
|
|
36295
36349
|
const strLit = `(?:"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'|\`[^\`\\\\]*(?:\\\\.[^\`\\\\]*)*\`)`;
|
|
@@ -36627,9 +36681,10 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
36627
36681
|
}
|
|
36628
36682
|
}
|
|
36629
36683
|
}
|
|
36684
|
+
const SIMPLE_IDENT = /^[\p{L}\p{N}_]+$/u;
|
|
36630
36685
|
const reCache = new Map;
|
|
36631
36686
|
for (const s of sourcesWithVar) {
|
|
36632
|
-
if (reCache.has(s.variable))
|
|
36687
|
+
if (SIMPLE_IDENT.test(s.variable) || reCache.has(s.variable))
|
|
36633
36688
|
continue;
|
|
36634
36689
|
const escaped = s.variable.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
36635
36690
|
reCache.set(s.variable, new RegExp(`(?<![\\p{L}\\p{N}_])${escaped}(?![\\p{L}\\p{N}_])`, "u"));
|
|
@@ -36640,6 +36695,23 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
36640
36695
|
existing.push(call);
|
|
36641
36696
|
callsByLine.set(call.location.line, existing);
|
|
36642
36697
|
}
|
|
36698
|
+
const sourcesByVar = new Map;
|
|
36699
|
+
const complexSources = [];
|
|
36700
|
+
sourcesWithVar.forEach((source, ord) => {
|
|
36701
|
+
const complex = !SIMPLE_IDENT.test(source.variable);
|
|
36702
|
+
const entry = { source, ord, complex };
|
|
36703
|
+
if (!complex) {
|
|
36704
|
+
let list = sourcesByVar.get(source.variable);
|
|
36705
|
+
if (!list) {
|
|
36706
|
+
list = [];
|
|
36707
|
+
sourcesByVar.set(source.variable, list);
|
|
36708
|
+
}
|
|
36709
|
+
list.push(entry);
|
|
36710
|
+
} else {
|
|
36711
|
+
complexSources.push(entry);
|
|
36712
|
+
}
|
|
36713
|
+
});
|
|
36714
|
+
const flowKeys = new Set;
|
|
36643
36715
|
for (const sink of sinks) {
|
|
36644
36716
|
if (unreachableLines.has(sink.line))
|
|
36645
36717
|
continue;
|
|
@@ -36652,18 +36724,35 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
36652
36724
|
const expr = arg.expression;
|
|
36653
36725
|
if (!expr)
|
|
36654
36726
|
continue;
|
|
36655
|
-
|
|
36727
|
+
const exprIdentMatches = expr.match(/[\p{L}\p{N}_]+/gu);
|
|
36728
|
+
let candidates = complexSources.length > 0 ? complexSources.slice() : null;
|
|
36729
|
+
if (exprIdentMatches) {
|
|
36730
|
+
for (const id of new Set(exprIdentMatches)) {
|
|
36731
|
+
const list = sourcesByVar.get(id);
|
|
36732
|
+
if (!list)
|
|
36733
|
+
continue;
|
|
36734
|
+
(candidates ??= []).push(...list);
|
|
36735
|
+
}
|
|
36736
|
+
}
|
|
36737
|
+
if (!candidates)
|
|
36738
|
+
continue;
|
|
36739
|
+
if (candidates.length > 1)
|
|
36740
|
+
candidates.sort((a, b) => a.ord - b.ord);
|
|
36741
|
+
for (const { source, complex } of candidates) {
|
|
36656
36742
|
if (source.line >= sink.line)
|
|
36657
36743
|
continue;
|
|
36658
36744
|
if (source.in_method && call.in_method && source.in_method !== call.in_method) {
|
|
36659
36745
|
continue;
|
|
36660
36746
|
}
|
|
36661
|
-
|
|
36662
|
-
|
|
36663
|
-
|
|
36747
|
+
if (complex) {
|
|
36748
|
+
const re = reCache.get(source.variable);
|
|
36749
|
+
if (!re || !re.test(expr))
|
|
36750
|
+
continue;
|
|
36751
|
+
}
|
|
36664
36752
|
if (!sourceSemanticsAllowed(source, sink.type))
|
|
36665
36753
|
continue;
|
|
36666
|
-
|
|
36754
|
+
const dedupKey = `${source.line}:${sink.line}:${sink.type}`;
|
|
36755
|
+
if (flowKeys.has(dedupKey))
|
|
36667
36756
|
continue;
|
|
36668
36757
|
if (aliasSanitizedFor.get(source.variable)?.has(sink.type)) {
|
|
36669
36758
|
break;
|
|
@@ -36683,6 +36772,7 @@ function detectExpressionScanFlows(calls, sources, sinks, sanitizers, unreachabl
|
|
|
36683
36772
|
confidence: source.confidence * sink.confidence * 0.7,
|
|
36684
36773
|
sanitized: false
|
|
36685
36774
|
});
|
|
36775
|
+
flowKeys.add(dedupKey);
|
|
36686
36776
|
break;
|
|
36687
36777
|
}
|
|
36688
36778
|
}
|
|
@@ -48731,7 +48821,7 @@ var colors = {
|
|
|
48731
48821
|
};
|
|
48732
48822
|
|
|
48733
48823
|
// src/version.ts
|
|
48734
|
-
var version = "4.9.
|
|
48824
|
+
var version = "4.9.9";
|
|
48735
48825
|
|
|
48736
48826
|
// src/formatters.ts
|
|
48737
48827
|
var LIBRARY_API_SURFACE_TAG2 = "library-api-surface:caller-responsibility";
|
|
@@ -49282,6 +49372,12 @@ function generateSarifResults(results, crossFileData) {
|
|
|
49282
49372
|
return sarifResults;
|
|
49283
49373
|
}
|
|
49284
49374
|
|
|
49375
|
+
// src/build-info.ts
|
|
49376
|
+
var buildInfo = {
|
|
49377
|
+
gitSha: "5c476ca",
|
|
49378
|
+
builtAt: "2026-08-26T20:08:56.375Z"
|
|
49379
|
+
};
|
|
49380
|
+
|
|
49285
49381
|
// src/utils/args.ts
|
|
49286
49382
|
function parseArgs(argv) {
|
|
49287
49383
|
const args2 = [];
|
|
@@ -49422,8 +49518,11 @@ EXAMPLES:
|
|
|
49422
49518
|
For more information, visit: https://cognium.dev
|
|
49423
49519
|
`);
|
|
49424
49520
|
}
|
|
49425
|
-
function showVersion(version2) {
|
|
49521
|
+
function showVersion(version2, buildInfo2) {
|
|
49426
49522
|
console.log(`cognium-dev v${version2}`);
|
|
49523
|
+
if (buildInfo2?.builtAt) {
|
|
49524
|
+
console.log(`build ${buildInfo2.gitSha} · ${buildInfo2.builtAt}`);
|
|
49525
|
+
}
|
|
49427
49526
|
console.log(`Powered by Cognium Labs`);
|
|
49428
49527
|
}
|
|
49429
49528
|
|
|
@@ -50557,7 +50656,7 @@ async function main() {
|
|
|
50557
50656
|
return;
|
|
50558
50657
|
}
|
|
50559
50658
|
if (command === "version" || options.version || options.V) {
|
|
50560
|
-
showVersion(version);
|
|
50659
|
+
showVersion(version, buildInfo);
|
|
50561
50660
|
return;
|
|
50562
50661
|
}
|
|
50563
50662
|
if (command === "init") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cognium-dev",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.9",
|
|
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",
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"cognium-dev": "dist/cli.js"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
"build": "
|
|
12
|
-
"build:standalone": "mkdir -p wasm && cp ../circle-ir/wasm/*.wasm wasm/ &&
|
|
11
|
+
"build": "node scripts/build.mjs",
|
|
12
|
+
"build:standalone": "mkdir -p wasm && cp ../circle-ir/wasm/*.wasm wasm/ && node scripts/build.mjs --standalone",
|
|
13
13
|
"dev": "bun run src/cli.ts",
|
|
14
14
|
"test": "bun test",
|
|
15
15
|
"clean": "rm -rf dist cognium-dev cognium-dev-* *.bun-build wasm",
|
|
16
16
|
"typecheck": "tsc --noEmit",
|
|
17
|
-
"version": "node -e \"const v = require('./package.json').version; require('fs').writeFileSync('src/version.ts', '/**\\n * Version information\\n *\\n * Kept in sync with package.json via the \\`version\\` npm lifecycle script.\\n * Do not edit manually
|
|
17
|
+
"version": "node -e \"const v = require('./package.json').version; require('fs').writeFileSync('src/version.ts', '/**\\n * Version information\\n *\\n * Kept in sync with package.json via the \\`version\\` npm lifecycle script.\\n * Do not edit manually \u2014 use \\`npm version patch|minor|major\\` instead.\\n */\\nexport const version = \\x27' + v + '\\x27;\\n')\" && git add src/version.ts",
|
|
18
18
|
"dogfood": "bun run src/cli.ts scan src/ -q",
|
|
19
19
|
"prepublishOnly": "bun run build"
|
|
20
20
|
},
|
|
@@ -65,8 +65,8 @@
|
|
|
65
65
|
"registry": "https://registry.npmjs.org/"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@cognium/project-profile-detect": "
|
|
69
|
-
"circle-ir": "
|
|
68
|
+
"@cognium/project-profile-detect": "1.1.0",
|
|
69
|
+
"circle-ir": "4.9.9"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^25.5.0",
|