circle-ir 4.0.0 → 4.3.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.
- package/README.md +15 -1
- package/dist/analysis/findings.d.ts.map +1 -1
- package/dist/analysis/findings.js +15 -9
- package/dist/analysis/findings.js.map +1 -1
- package/dist/analysis/note-coalescer.d.ts +0 -4
- package/dist/analysis/note-coalescer.d.ts.map +1 -1
- package/dist/analysis/note-coalescer.js +36 -1
- package/dist/analysis/note-coalescer.js.map +1 -1
- package/dist/analysis/passes/language-sources-pass.d.ts.map +1 -1
- package/dist/analysis/passes/language-sources-pass.js +12 -1
- package/dist/analysis/passes/language-sources-pass.js.map +1 -1
- package/dist/browser/circle-ir.js +43 -12
- package/docs/SPEC.md +1 -1
- package/package.json +1 -1
|
@@ -16657,33 +16657,39 @@ function canSourceReachSink(sourceType, sinkType) {
|
|
|
16657
16657
|
// disagreed. log_injection (CWE-117) and format_string (CWE-134) are
|
|
16658
16658
|
// reachable from any user-controlled value that is logged / used as a
|
|
16659
16659
|
// format string; nosql_injection (CWE-943) mirrors sql_injection's sources.
|
|
16660
|
-
|
|
16661
|
-
|
|
16662
|
-
|
|
16663
|
-
|
|
16660
|
+
// prompt_injection (CWE-1427 / OWASP LLM01) added cognium-ai#281: an
|
|
16661
|
+
// attacker-controlled value reaching an LLM prompt sink (CreateChatCompletion
|
|
16662
|
+
// et al.) is prompt injection. The reach map omitted it entirely, so the
|
|
16663
|
+
// scan path (`generateFindings`) dropped every `http_*/io/network/interproc →
|
|
16664
|
+
// prompt_injection` flow even though `taint.flows` / the trust pass reported
|
|
16665
|
+
// it — the same "two paths disagree" shape as #129. Now emitted from scan too.
|
|
16666
|
+
http_param: ["sql_injection", "command_injection", "path_traversal", "xss", "xpath_injection", "ldap_injection", "ssrf", "mybatis_mapper_call", "code_injection", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "deserialization", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
16667
|
+
http_body: ["sql_injection", "command_injection", "deserialization", "xxe", "xss", "code_injection", "mybatis_mapper_call", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
16668
|
+
http_header: ["sql_injection", "xss", "ssrf", "mybatis_mapper_call", "code_injection", "crlf", "open_redirect", "trust_boundary", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
16669
|
+
http_cookie: ["sql_injection", "xss", "mybatis_mapper_call", "code_injection", "crlf", "open_redirect", "trust_boundary", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
16664
16670
|
// xss added cognium-dev 3.163.0: URL path components (getRequestURI,
|
|
16665
16671
|
// getRequestURL, getPathInfo, getServletPath) reflected back into HTML
|
|
16666
16672
|
// output are a classic reflected-XSS vector — cf. Basic35 in
|
|
16667
16673
|
// SecuriBench Micro where `writer.println(req.getRequestURL())` is
|
|
16668
16674
|
// annotated `/* BAD */`. Prior to 3.163.0 the reach map omitted xss
|
|
16669
16675
|
// so http_path → xss inline-colocation flows were silently dropped.
|
|
16670
|
-
http_path: ["path_traversal", "sql_injection", "ssrf", "mybatis_mapper_call", "open_redirect", "trust_boundary", "xss", "log_injection", "format_string"],
|
|
16671
|
-
http_query: ["sql_injection", "command_injection", "xss", "ssrf", "mybatis_mapper_call", "code_injection", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "deserialization", "log_injection", "format_string", "nosql_injection"],
|
|
16676
|
+
http_path: ["path_traversal", "sql_injection", "ssrf", "mybatis_mapper_call", "open_redirect", "trust_boundary", "xss", "log_injection", "format_string", "prompt_injection"],
|
|
16677
|
+
http_query: ["sql_injection", "command_injection", "xss", "ssrf", "mybatis_mapper_call", "code_injection", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "deserialization", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
16672
16678
|
// ssrf added Sprint 57 #200: bash CGI/webhook handlers and scripts that
|
|
16673
16679
|
// take a URL on stdin or as a positional CLI arg (`curl "$1"`,
|
|
16674
16680
|
// `wget "$(read line)"`) and curl/wget it server-side are textbook SSRF
|
|
16675
16681
|
// (CVE-2022-41040 ProxyShell-class). Cross-language: `socket.urlopen(input())`
|
|
16676
16682
|
// (Python), `axios.get(readline())` (JS) etc. also benefit.
|
|
16677
|
-
io_input: ["command_injection", "path_traversal", "deserialization", "xxe", "code_injection", "xss", "ssrf", "log_injection", "format_string"],
|
|
16683
|
+
io_input: ["command_injection", "path_traversal", "deserialization", "xxe", "code_injection", "xss", "ssrf", "log_injection", "format_string", "prompt_injection"],
|
|
16678
16684
|
env_input: ["command_injection", "path_traversal"],
|
|
16679
16685
|
db_input: ["xss", "sql_injection", "log_injection"],
|
|
16680
16686
|
// Second-order injection
|
|
16681
16687
|
file_input: ["deserialization", "xxe", "path_traversal", "command_injection", "code_injection"],
|
|
16682
|
-
network_input: ["sql_injection", "command_injection", "xss", "ssrf", "log_injection", "format_string", "nosql_injection"],
|
|
16688
|
+
network_input: ["sql_injection", "command_injection", "xss", "ssrf", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
16683
16689
|
config_param: ["sql_injection", "command_injection", "path_traversal", "xss", "ssrf", "log_injection", "format_string"],
|
|
16684
16690
|
// Servlet init params
|
|
16685
|
-
interprocedural_param: ["sql_injection", "command_injection", "path_traversal", "xss", "xpath_injection", "ldap_injection", "ssrf", "code_injection", "mybatis_mapper_call", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "log_injection", "format_string", "nosql_injection"],
|
|
16686
|
-
// Cross-method taint; Sprint 82 (#189) — open_redirect added; Sprint 91 (#117) — trust_boundary added; cognium-ai#129 — log_injection/format_string/nosql_injection added
|
|
16691
|
+
interprocedural_param: ["sql_injection", "command_injection", "path_traversal", "xss", "xpath_injection", "ldap_injection", "ssrf", "code_injection", "mybatis_mapper_call", "crlf", "mass_assignment", "open_redirect", "trust_boundary", "log_injection", "format_string", "nosql_injection", "prompt_injection"],
|
|
16692
|
+
// Cross-method taint; Sprint 82 (#189) — open_redirect added; Sprint 91 (#117) — trust_boundary added; cognium-ai#129 — log_injection/format_string/nosql_injection added; cognium-ai#281 — prompt_injection added
|
|
16687
16693
|
plugin_param: ["sql_injection", "command_injection", "path_traversal", "xss", "code_injection", "log_injection", "format_string"]
|
|
16688
16694
|
// Plugin/config parameters
|
|
16689
16695
|
};
|
|
@@ -21635,6 +21641,10 @@ function applyLibraryApiSurfaceDowngrade(findings) {
|
|
|
21635
21641
|
}
|
|
21636
21642
|
|
|
21637
21643
|
// src/analysis/note-coalescer.ts
|
|
21644
|
+
var CLICKJACKING_PAIR = /* @__PURE__ */ new Set(["missing-x-frame-options", "missing-csp-frame-ancestors"]);
|
|
21645
|
+
function levelRank(level) {
|
|
21646
|
+
return level === "error" ? 0 : level === "warning" ? 1 : 2;
|
|
21647
|
+
}
|
|
21638
21648
|
function coalesceNoteLevelFindings(findings) {
|
|
21639
21649
|
if (findings.length < 2) return [...findings];
|
|
21640
21650
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -21651,11 +21661,30 @@ function coalesceNoteLevelFindings(findings) {
|
|
|
21651
21661
|
}
|
|
21652
21662
|
const out2 = [];
|
|
21653
21663
|
for (const key of order) {
|
|
21654
|
-
|
|
21664
|
+
let bucket = groups.get(key);
|
|
21655
21665
|
if (bucket.length === 1) {
|
|
21656
21666
|
out2.push(bucket[0]);
|
|
21657
21667
|
continue;
|
|
21658
21668
|
}
|
|
21669
|
+
const cj = bucket.filter((f) => CLICKJACKING_PAIR.has(f.rule_id));
|
|
21670
|
+
if (new Set(cj.map((f) => f.rule_id)).size === CLICKJACKING_PAIR.size) {
|
|
21671
|
+
const primary2 = [...cj].sort(
|
|
21672
|
+
(a, b) => levelRank(a.level) - levelRank(b.level) || a.rule_id.localeCompare(b.rule_id)
|
|
21673
|
+
)[0];
|
|
21674
|
+
const labels = Array.from(
|
|
21675
|
+
/* @__PURE__ */ new Set([
|
|
21676
|
+
...primary2.labels ?? [],
|
|
21677
|
+
...cj.flatMap((f) => [f.rule_id, ...f.labels ?? []])
|
|
21678
|
+
])
|
|
21679
|
+
).filter((l) => l !== primary2.rule_id);
|
|
21680
|
+
out2.push({ ...primary2, labels });
|
|
21681
|
+
bucket = bucket.filter((f) => !CLICKJACKING_PAIR.has(f.rule_id));
|
|
21682
|
+
if (bucket.length === 0) continue;
|
|
21683
|
+
if (bucket.length === 1) {
|
|
21684
|
+
out2.push(bucket[0]);
|
|
21685
|
+
continue;
|
|
21686
|
+
}
|
|
21687
|
+
}
|
|
21659
21688
|
const allNote = bucket.every((f) => f.level === "note");
|
|
21660
21689
|
if (!allNote) {
|
|
21661
21690
|
for (const f of bucket) out2.push(f);
|
|
@@ -26977,13 +27006,15 @@ function findJavaScriptAssignmentSources(sourceCode, language) {
|
|
|
26977
27006
|
if (!["javascript", "typescript"].includes(language)) return [];
|
|
26978
27007
|
const sources = [];
|
|
26979
27008
|
const lines = sourceCode.split("\n");
|
|
27009
|
+
const isRouteHandler2 = /export\s+(?:async\s+)?(?:function\s+(?:GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS|loader|action)\b|const\s+(?:GET|POST|PUT|PATCH|DELETE|loader|action)\b)/.test(sourceCode) && /\{[^}]*\bparams\b[^}]*\}/.test(sourceCode);
|
|
27010
|
+
const patterns = isRouteHandler2 ? [...JS_TAINTED_PATTERNS, { pattern: /\bparams\s*[.[]/, type: "http_path" }] : JS_TAINTED_PATTERNS;
|
|
26980
27011
|
for (let lineNum = 0; lineNum < lines.length; lineNum++) {
|
|
26981
27012
|
const line = lines[lineNum];
|
|
26982
27013
|
const lineNumber = lineNum + 1;
|
|
26983
27014
|
const assignmentMatch = line.match(/(?:(?:var|let|const)\s+)?(\w+)\s*=\s*(.+)/);
|
|
26984
27015
|
if (!assignmentMatch) continue;
|
|
26985
27016
|
const [, varName, rhs] = assignmentMatch;
|
|
26986
|
-
for (const { pattern, type } of
|
|
27017
|
+
for (const { pattern, type } of patterns) {
|
|
26987
27018
|
if (pattern.test(rhs)) {
|
|
26988
27019
|
const alreadyExists = sources.some((s) => s.line === lineNumber && s.type === type);
|
|
26989
27020
|
if (!alreadyExists) {
|
package/docs/SPEC.md
CHANGED
|
@@ -90,7 +90,7 @@ File metadata and version information.
|
|
|
90
90
|
interface Meta {
|
|
91
91
|
circle_ir: "3.0";
|
|
92
92
|
file: string;
|
|
93
|
-
language: "java" | "javascript" | "typescript" | "python" | "go" | "rust" | "bash" | "html";
|
|
93
|
+
language: "java" | "javascript" | "typescript" | "python" | "go" | "rust" | "bash" | "html" | "csharp"; // "csharp" experimental (4.0.0+)
|
|
94
94
|
loc: number;
|
|
95
95
|
hash: string; // SHA256 prefix (16 chars)
|
|
96
96
|
package?: string; // PENDING: Add to implementation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circle-ir",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.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",
|