circle-ir 4.9.21 → 4.9.22
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/analysis/modelled-cwes.d.ts +35 -0
- package/dist/analysis/modelled-cwes.d.ts.map +1 -0
- package/dist/analysis/modelled-cwes.js +63 -0
- package/dist/analysis/modelled-cwes.js.map +1 -0
- package/dist/analysis/passes/xml-entity-expansion-pass.d.ts +46 -3
- package/dist/analysis/passes/xml-entity-expansion-pass.d.ts.map +1 -1
- package/dist/analysis/passes/xml-entity-expansion-pass.js +139 -13
- package/dist/analysis/passes/xml-entity-expansion-pass.js.map +1 -1
- package/dist/browser/circle-ir.js +98 -15
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/languages/plugins/index.d.ts +8 -0
- package/dist/languages/plugins/index.d.ts.map +1 -1
- package/dist/languages/plugins/index.js +21 -9
- package/dist/languages/plugins/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modelled-CWE export (cognium-dev#393).
|
|
3
|
+
*
|
|
4
|
+
* Which weakness classes does the taint engine have a model for? Anything that
|
|
5
|
+
* scores the engine against a CWE-labelled corpus needs the answer, and a
|
|
6
|
+
* hand-kept list drifts and can be tuned. This derives it from the same runtime
|
|
7
|
+
* registries the analyzer matches against, so it is always the truth for the
|
|
8
|
+
* installed version and grows as sinks are added.
|
|
9
|
+
*
|
|
10
|
+
* "Modelled" is deliberately narrow: a CWE some SINK pattern is registered
|
|
11
|
+
* under. Non-taint pattern passes (weak crypto, missing headers, resource
|
|
12
|
+
* leaks …) stamp their CWE on each finding and have no registry to enumerate,
|
|
13
|
+
* so they are out of this export rather than half-listed.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Ids an advisory may carry for a class the engine models under another id —
|
|
17
|
+
* a child or sibling that reaches the same sink family. Keyed advisory-side,
|
|
18
|
+
* valued with the modelled id. Kept short and literal on purpose: each entry
|
|
19
|
+
* widens what counts as in scope, so each is a claim someone can check.
|
|
20
|
+
*/
|
|
21
|
+
export declare const RELATED_CWE: Readonly<Record<string, string>>;
|
|
22
|
+
export interface ModelledCwes {
|
|
23
|
+
/** CWEs at least one registered sink pattern carries, sorted numerically. */
|
|
24
|
+
sinkCwes: string[];
|
|
25
|
+
/** Advisory-side ids that map onto a modelled class; see `RELATED_CWE`. */
|
|
26
|
+
related: Readonly<Record<string, string>>;
|
|
27
|
+
}
|
|
28
|
+
/** The engine's modelled taint classes, derived from the live sink registries. */
|
|
29
|
+
export declare function getModelledCwes(): ModelledCwes;
|
|
30
|
+
/**
|
|
31
|
+
* Is `cwe` a class the taint engine models, directly or through `RELATED_CWE`?
|
|
32
|
+
* A related id counts only while the id it maps to is itself still modelled.
|
|
33
|
+
*/
|
|
34
|
+
export declare function isModelledCwe(cwe: string, modelled?: ModelledCwes): boolean;
|
|
35
|
+
//# sourceMappingURL=modelled-cwes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelled-cwes.d.ts","sourceRoot":"","sources":["../../src/analysis/modelled-cwes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH;;;;;GAKG;AACH,eAAO,MAAM,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAcvD,CAAC;AAEH,MAAM,WAAW,YAAY;IAC3B,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2EAA2E;IAC3E,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC3C;AAKD,kFAAkF;AAClF,wBAAgB,eAAe,IAAI,YAAY,CAO9C;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,GAAE,YAAgC,GAAG,OAAO,CAK9F"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Modelled-CWE export (cognium-dev#393).
|
|
3
|
+
*
|
|
4
|
+
* Which weakness classes does the taint engine have a model for? Anything that
|
|
5
|
+
* scores the engine against a CWE-labelled corpus needs the answer, and a
|
|
6
|
+
* hand-kept list drifts and can be tuned. This derives it from the same runtime
|
|
7
|
+
* registries the analyzer matches against, so it is always the truth for the
|
|
8
|
+
* installed version and grows as sinks are added.
|
|
9
|
+
*
|
|
10
|
+
* "Modelled" is deliberately narrow: a CWE some SINK pattern is registered
|
|
11
|
+
* under. Non-taint pattern passes (weak crypto, missing headers, resource
|
|
12
|
+
* leaks …) stamp their CWE on each finding and have no registry to enumerate,
|
|
13
|
+
* so they are out of this export rather than half-listed.
|
|
14
|
+
*/
|
|
15
|
+
import { DEFAULT_SINKS } from './config-loader.js';
|
|
16
|
+
import { createBuiltinPlugins } from '../languages/plugins/index.js';
|
|
17
|
+
/**
|
|
18
|
+
* Ids an advisory may carry for a class the engine models under another id —
|
|
19
|
+
* a child or sibling that reaches the same sink family. Keyed advisory-side,
|
|
20
|
+
* valued with the modelled id. Kept short and literal on purpose: each entry
|
|
21
|
+
* widens what counts as in scope, so each is a claim someone can check.
|
|
22
|
+
*/
|
|
23
|
+
export const RELATED_CWE = Object.freeze({
|
|
24
|
+
'CWE-23': 'CWE-22', // relative path traversal
|
|
25
|
+
'CWE-36': 'CWE-22', // absolute path traversal
|
|
26
|
+
'CWE-73': 'CWE-22', // external control of file name or path
|
|
27
|
+
'CWE-77': 'CWE-78', // command injection (generic) -> OS command injection
|
|
28
|
+
'CWE-88': 'CWE-78', // argument injection
|
|
29
|
+
'CWE-80': 'CWE-79', // basic XSS
|
|
30
|
+
'CWE-564': 'CWE-89', // SQL injection: Hibernate
|
|
31
|
+
'CWE-95': 'CWE-94', // eval injection
|
|
32
|
+
'CWE-917': 'CWE-94', // expression language injection
|
|
33
|
+
'CWE-1336': 'CWE-94', // template engine injection
|
|
34
|
+
'CWE-93': 'CWE-113', // CRLF injection -> HTTP response splitting
|
|
35
|
+
'CWE-91': 'CWE-643', // XML injection -> XPath injection
|
|
36
|
+
'CWE-776': 'CWE-611', // entity expansion -> external entities (same parser config)
|
|
37
|
+
});
|
|
38
|
+
const byNumber = (a, b) => Number(a.slice(4)) - Number(b.slice(4));
|
|
39
|
+
/** The engine's modelled taint classes, derived from the live sink registries. */
|
|
40
|
+
export function getModelledCwes() {
|
|
41
|
+
const cwes = new Set();
|
|
42
|
+
for (const sink of DEFAULT_SINKS)
|
|
43
|
+
if (sink.cwe)
|
|
44
|
+
cwes.add(sink.cwe);
|
|
45
|
+
for (const plugin of createBuiltinPlugins()) {
|
|
46
|
+
for (const sink of plugin.getBuiltinSinks())
|
|
47
|
+
if (sink.cwe)
|
|
48
|
+
cwes.add(sink.cwe);
|
|
49
|
+
}
|
|
50
|
+
return { sinkCwes: [...cwes].sort(byNumber), related: RELATED_CWE };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Is `cwe` a class the taint engine models, directly or through `RELATED_CWE`?
|
|
54
|
+
* A related id counts only while the id it maps to is itself still modelled.
|
|
55
|
+
*/
|
|
56
|
+
export function isModelledCwe(cwe, modelled = getModelledCwes()) {
|
|
57
|
+
const direct = new Set(modelled.sinkCwes);
|
|
58
|
+
if (direct.has(cwe))
|
|
59
|
+
return true;
|
|
60
|
+
const parent = modelled.related[cwe];
|
|
61
|
+
return parent !== undefined && direct.has(parent);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=modelled-cwes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"modelled-cwes.js","sourceRoot":"","sources":["../../src/analysis/modelled-cwes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAqC,MAAM,CAAC,MAAM,CAAC;IACzE,QAAQ,EAAE,QAAQ,EAAI,0BAA0B;IAChD,QAAQ,EAAE,QAAQ,EAAI,0BAA0B;IAChD,QAAQ,EAAE,QAAQ,EAAI,wCAAwC;IAC9D,QAAQ,EAAE,QAAQ,EAAI,sDAAsD;IAC5E,QAAQ,EAAE,QAAQ,EAAI,qBAAqB;IAC3C,QAAQ,EAAE,QAAQ,EAAI,YAAY;IAClC,SAAS,EAAE,QAAQ,EAAG,2BAA2B;IACjD,QAAQ,EAAE,QAAQ,EAAI,iBAAiB;IACvC,SAAS,EAAE,QAAQ,EAAG,gCAAgC;IACtD,UAAU,EAAE,QAAQ,EAAE,4BAA4B;IAClD,QAAQ,EAAE,SAAS,EAAG,4CAA4C;IAClE,QAAQ,EAAE,SAAS,EAAG,mCAAmC;IACzD,SAAS,EAAE,SAAS,EAAE,6DAA6D;CACpF,CAAC,CAAC;AASH,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAE,CAAS,EAAU,EAAE,CAChD,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1C,kFAAkF;AAClF,MAAM,UAAU,eAAe;IAC7B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,aAAa;QAAE,IAAI,IAAI,CAAC,GAAG;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnE,KAAK,MAAM,MAAM,IAAI,oBAAoB,EAAE,EAAE,CAAC;QAC5C,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,eAAe,EAAE;YAAE,IAAI,IAAI,CAAC,GAAG;gBAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AACtE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,QAAQ,GAAiB,eAAe,EAAE;IACnF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACrC,OAAO,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pass: xml-entity-expansion (CWE-
|
|
2
|
+
* Pass: xml-entity-expansion (CWE-611 / CWE-776, category: security)
|
|
3
3
|
*
|
|
4
4
|
* Pattern pass — flags XML parser instantiation that does *not* disable
|
|
5
5
|
* DTD / external-entity processing in the same file. This covers:
|
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
* - `XMLInputFactory.newInstance()` (StAX)
|
|
15
15
|
* - `SchemaFactory.newInstance(...)`
|
|
16
16
|
* - `TransformerFactory.newInstance()`
|
|
17
|
-
* Safe-feature setters
|
|
18
|
-
*
|
|
17
|
+
* Safe-feature setters. Any of these in the file silences a factory
|
|
18
|
+
* UNLESS that factory is a local variable which provably never receives
|
|
19
|
+
* one (no hardening-capable setter on it in its method, never passed to
|
|
20
|
+
* another call, never returned) — so one hardened factory no longer masks
|
|
21
|
+
* an unhardened one beside it:
|
|
19
22
|
* - `setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)`
|
|
20
23
|
* - `setFeature("http://xml.org/sax/features/external-general-entities", false)`
|
|
21
24
|
* - `setFeature("http://xml.org/sax/features/external-parameter-entities", false)`
|
|
@@ -35,6 +38,19 @@
|
|
|
35
38
|
* because billion-laughs is exploitable via any attacker-supplied entity
|
|
36
39
|
* file even when the parse() argument itself is trusted.
|
|
37
40
|
*
|
|
41
|
+
* CWE is assigned PER API, by which weakness the unhardened default actually
|
|
42
|
+
* leaves open (#426) — the same per-API reasoning `language-sources-pass`
|
|
43
|
+
* applies to Python's `xml.sax`:
|
|
44
|
+
* - Java JAXP factories -> CWE-611. External entity resolution is ON by
|
|
45
|
+
* default, while JAXP has shipped a default entity-expansion limit for
|
|
46
|
+
* years, so the live risk on a current JDK is external entities. Every
|
|
47
|
+
* hardening token this pass looks for is an external-entity control.
|
|
48
|
+
* - `lxml.etree` -> CWE-611. `resolve_entities` defaults on.
|
|
49
|
+
* - `xml.etree.ElementTree` -> CWE-776. It never resolves external entities;
|
|
50
|
+
* what remains is entity expansion.
|
|
51
|
+
* The JS variant of this rule (`libxmljs` `noent: true`) already reported
|
|
52
|
+
* CWE-611, so before this the rule disagreed with itself across languages.
|
|
53
|
+
*
|
|
38
54
|
* Issue: #86, Sprint 6.
|
|
39
55
|
*/
|
|
40
56
|
import type { AnalysisPass, PassContext } from '../../graph/analysis-pass.js';
|
|
@@ -50,6 +66,33 @@ export declare class XmlEntityExpansionPass implements AnalysisPass<XmlEntityExp
|
|
|
50
66
|
readonly name = "xml-entity-expansion";
|
|
51
67
|
readonly category: 'security';
|
|
52
68
|
run(ctx: PassContext): XmlEntityExpansionResult;
|
|
69
|
+
private methodRanges;
|
|
70
|
+
/**
|
|
71
|
+
* In a file that DOES contain hardening evidence, is the factory created on
|
|
72
|
+
* `line` one that provably never receives it?
|
|
73
|
+
*
|
|
74
|
+
* Deliberately one-sided. It answers true for exactly two shapes:
|
|
75
|
+
*
|
|
76
|
+
* 1. CHAINED — `Factory.newInstance().newDocumentBuilder()`, where the
|
|
77
|
+
* product is not handed on or returned either.
|
|
78
|
+
* 2. LOCAL — `Factory f = Factory.newInstance();` where the enclosing method
|
|
79
|
+
* builds a parser from `f`, never hands `f` to another call, and never
|
|
80
|
+
* returns it.
|
|
81
|
+
*
|
|
82
|
+
* and in both only when the enclosing method contains NO hardening-capable
|
|
83
|
+
* setter on ANY receiver, since hardening may land on the factory's product
|
|
84
|
+
* (`parser.getXMLReader().setFeature(…)`) rather than the factory.
|
|
85
|
+
*
|
|
86
|
+
* Every other shape — a field, a helper that takes the factory, a caller that
|
|
87
|
+
* receives it — may be hardened somewhere this check cannot see, so it keeps
|
|
88
|
+
* the previous file-level silence.
|
|
89
|
+
*
|
|
90
|
+
* A TransformerFactory additionally needs a `StreamSource` in its method: that
|
|
91
|
+
* is the input the transformer parses with its OWN parser. Fed a `DOMSource`
|
|
92
|
+
* it parses nothing, and fed a `SAXSource` it uses the reader it was given —
|
|
93
|
+
* whose hardening is that reader's business, not this factory's.
|
|
94
|
+
*/
|
|
95
|
+
private isProvablyUnhardened;
|
|
53
96
|
private detectJavaCall;
|
|
54
97
|
private detectPythonCall;
|
|
55
98
|
private fixForJava;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xml-entity-expansion-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/xml-entity-expansion-pass.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"xml-entity-expansion-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/xml-entity-expansion-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAwD9E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;KACb,CAAC,CAAC;CACJ;AAED,qBAAa,sBACX,YAAW,YAAY,CAAC,wBAAwB,CAAC;IAEjD,QAAQ,CAAC,IAAI,0BAA0B;IACvC,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;IAExC,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,wBAAwB,CAmG9C;IAED,OAAO,CAAC,YAAY;IAWpB;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,OAAO,CAAC,oBAAoB;IA0D5B,OAAO,CAAC,cAAc;IAiBtB,OAAO,CAAC,gBAAgB;IAyBxB,OAAO,CAAC,UAAU;IA6BlB,OAAO,CAAC,YAAY;CAarB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Pass: xml-entity-expansion (CWE-
|
|
2
|
+
* Pass: xml-entity-expansion (CWE-611 / CWE-776, category: security)
|
|
3
3
|
*
|
|
4
4
|
* Pattern pass — flags XML parser instantiation that does *not* disable
|
|
5
5
|
* DTD / external-entity processing in the same file. This covers:
|
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
* - `XMLInputFactory.newInstance()` (StAX)
|
|
15
15
|
* - `SchemaFactory.newInstance(...)`
|
|
16
16
|
* - `TransformerFactory.newInstance()`
|
|
17
|
-
* Safe-feature setters
|
|
18
|
-
*
|
|
17
|
+
* Safe-feature setters. Any of these in the file silences a factory
|
|
18
|
+
* UNLESS that factory is a local variable which provably never receives
|
|
19
|
+
* one (no hardening-capable setter on it in its method, never passed to
|
|
20
|
+
* another call, never returned) — so one hardened factory no longer masks
|
|
21
|
+
* an unhardened one beside it:
|
|
19
22
|
* - `setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)`
|
|
20
23
|
* - `setFeature("http://xml.org/sax/features/external-general-entities", false)`
|
|
21
24
|
* - `setFeature("http://xml.org/sax/features/external-parameter-entities", false)`
|
|
@@ -35,6 +38,19 @@
|
|
|
35
38
|
* because billion-laughs is exploitable via any attacker-supplied entity
|
|
36
39
|
* file even when the parse() argument itself is trusted.
|
|
37
40
|
*
|
|
41
|
+
* CWE is assigned PER API, by which weakness the unhardened default actually
|
|
42
|
+
* leaves open (#426) — the same per-API reasoning `language-sources-pass`
|
|
43
|
+
* applies to Python's `xml.sax`:
|
|
44
|
+
* - Java JAXP factories -> CWE-611. External entity resolution is ON by
|
|
45
|
+
* default, while JAXP has shipped a default entity-expansion limit for
|
|
46
|
+
* years, so the live risk on a current JDK is external entities. Every
|
|
47
|
+
* hardening token this pass looks for is an external-entity control.
|
|
48
|
+
* - `lxml.etree` -> CWE-611. `resolve_entities` defaults on.
|
|
49
|
+
* - `xml.etree.ElementTree` -> CWE-776. It never resolves external entities;
|
|
50
|
+
* what remains is entity expansion.
|
|
51
|
+
* The JS variant of this rule (`libxmljs` `noent: true`) already reported
|
|
52
|
+
* CWE-611, so before this the rule disagreed with itself across languages.
|
|
53
|
+
*
|
|
38
54
|
* Issue: #86, Sprint 6.
|
|
39
55
|
*/
|
|
40
56
|
const JAVA_FACTORIES = new Set([
|
|
@@ -63,6 +79,13 @@ const JAVA_XML_PARSE_INPUT_RE = /\bnew\s+(?:StreamSource|SAXSource|InputSource)\
|
|
|
63
79
|
// - file calls NO builder.parse(...) (never reads bytes)
|
|
64
80
|
const JAVA_DOC_BUILDER_NEW_DOCUMENT_RE = /\.\s*newDocument\s*\(\s*\)/;
|
|
65
81
|
const JAVA_DOC_BUILDER_PARSE_RE = /(?:DocumentBuilder|builder)\s*\.\s*parse\s*\(/;
|
|
82
|
+
// Any call that CAN carry XML hardening, on any receiver — factory, parser,
|
|
83
|
+
// reader, validator or transformer. Matched by name, not argument, because the
|
|
84
|
+
// feature string is routinely a constant declared elsewhere.
|
|
85
|
+
const JAVA_HARDENING_SETTER_RE = /\.\s*(?:setFeature|setAttribute|setProperty|setXIncludeAware|setExpandEntityReferences)\s*\(/;
|
|
86
|
+
// A factory consumed in the same expression that creates it — never bound to a
|
|
87
|
+
// name, so it can never be configured.
|
|
88
|
+
const JAVA_FACTORY_CHAINED_RE = /\bnewInstance\s*\([^()]*\)\s*\.\s*(?:newDocumentBuilder|newSAXParser|newTransformer|newTemplates|newSchema|createXMLStreamReader|createXMLEventReader)\s*\(/;
|
|
66
89
|
const PY_LXML_PARSER_INSECURE_DEFAULT_RE = /\bresolve_entities\s*=\s*False\b/;
|
|
67
90
|
export class XmlEntityExpansionPass {
|
|
68
91
|
name = 'xml-entity-expansion';
|
|
@@ -74,8 +97,15 @@ export class XmlEntityExpansionPass {
|
|
|
74
97
|
const code = ctx.code ?? '';
|
|
75
98
|
if (language === 'java') {
|
|
76
99
|
const safeInFile = JAVA_SAFE_EVIDENCE_RE.test(code);
|
|
77
|
-
|
|
78
|
-
|
|
100
|
+
// Hardening evidence used to silence the WHOLE file, so one hardened
|
|
101
|
+
// factory masked every other factory beside it. When evidence exists,
|
|
102
|
+
// keep only the factories that provably never receive it (see
|
|
103
|
+
// `isProvablyUnhardened`); anything ambiguous stays silent, as before.
|
|
104
|
+
// `jdk.xml.*` limits are set process-wide (System.setProperty), so they
|
|
105
|
+
// reach every factory regardless of which variable the file touches.
|
|
106
|
+
const processWide = safeInFile && /jdk\.xml\./.test(code);
|
|
107
|
+
const lines = safeInFile ? code.split('\n') : [];
|
|
108
|
+
const methodRanges = safeInFile ? this.methodRanges(graph.ir.types) : [];
|
|
79
109
|
// #173 — output-only TransformerFactory + empty DocumentBuilder.
|
|
80
110
|
// File-level heuristics; conservative-bias (only suppress when the
|
|
81
111
|
// file shows ONLY the safe shape and NO unsafe shape).
|
|
@@ -93,6 +123,8 @@ export class XmlEntityExpansionPass {
|
|
|
93
123
|
if (det.api === 'DocumentBuilderFactory' && isDocumentBuilderEmptyOnly)
|
|
94
124
|
continue;
|
|
95
125
|
const line = call.location.line;
|
|
126
|
+
if (safeInFile && (processWide || !this.isProvablyUnhardened(lines, line, methodRanges, det.api)))
|
|
127
|
+
continue;
|
|
96
128
|
findings.push({ line, language, ...det });
|
|
97
129
|
ctx.addFinding({
|
|
98
130
|
id: `${this.name}-${file}-${line}-${det.api}`,
|
|
@@ -103,15 +135,15 @@ export class XmlEntityExpansionPass {
|
|
|
103
135
|
severity: 'high',
|
|
104
136
|
level: 'error',
|
|
105
137
|
message: `${det.api} created without disabling DTD / external-entity ` +
|
|
106
|
-
'processing. Vulnerable to
|
|
107
|
-
'
|
|
108
|
-
'(CWE-
|
|
138
|
+
'processing. Vulnerable to external-entity disclosure ' +
|
|
139
|
+
'(CWE-611) and billion-laughs / quadratic blow-up DoS ' +
|
|
140
|
+
'(CWE-776). Add `setFeature("http://apache.org/xml/features/' +
|
|
109
141
|
'disallow-doctype-decl", true)` (or the equivalent) before ' +
|
|
110
142
|
'parsing.',
|
|
111
143
|
file,
|
|
112
144
|
line,
|
|
113
145
|
fix: this.fixForJava(det.api),
|
|
114
|
-
evidence: { ...det, language, safeFeatureInFile:
|
|
146
|
+
evidence: { ...det, language, safeFeatureInFile: safeInFile },
|
|
115
147
|
});
|
|
116
148
|
}
|
|
117
149
|
return { findings };
|
|
@@ -136,8 +168,11 @@ export class XmlEntityExpansionPass {
|
|
|
136
168
|
severity: 'high',
|
|
137
169
|
level: 'error',
|
|
138
170
|
message: `${det.api} called without an entity-safe parser. Vulnerable ` +
|
|
139
|
-
|
|
140
|
-
|
|
171
|
+
(det.cwe === 'CWE-611'
|
|
172
|
+
? 'to external-entity disclosure (CWE-611) and billion-laughs / ' +
|
|
173
|
+
'quadratic blow-up DoS (CWE-776). '
|
|
174
|
+
: 'to billion-laughs / quadratic blow-up DoS (CWE-776). ') +
|
|
175
|
+
'Use `defusedxml` or pass ' +
|
|
141
176
|
'an `XMLParser(resolve_entities=False)` to lxml.',
|
|
142
177
|
file,
|
|
143
178
|
line,
|
|
@@ -149,6 +184,97 @@ export class XmlEntityExpansionPass {
|
|
|
149
184
|
}
|
|
150
185
|
return { findings };
|
|
151
186
|
}
|
|
187
|
+
methodRanges(types) {
|
|
188
|
+
const out = [];
|
|
189
|
+
for (const t of types ?? []) {
|
|
190
|
+
for (const m of t.methods ?? []) {
|
|
191
|
+
if (typeof m.start_line === 'number' && typeof m.end_line === 'number')
|
|
192
|
+
out.push([m.start_line, m.end_line]);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* In a file that DOES contain hardening evidence, is the factory created on
|
|
199
|
+
* `line` one that provably never receives it?
|
|
200
|
+
*
|
|
201
|
+
* Deliberately one-sided. It answers true for exactly two shapes:
|
|
202
|
+
*
|
|
203
|
+
* 1. CHAINED — `Factory.newInstance().newDocumentBuilder()`, where the
|
|
204
|
+
* product is not handed on or returned either.
|
|
205
|
+
* 2. LOCAL — `Factory f = Factory.newInstance();` where the enclosing method
|
|
206
|
+
* builds a parser from `f`, never hands `f` to another call, and never
|
|
207
|
+
* returns it.
|
|
208
|
+
*
|
|
209
|
+
* and in both only when the enclosing method contains NO hardening-capable
|
|
210
|
+
* setter on ANY receiver, since hardening may land on the factory's product
|
|
211
|
+
* (`parser.getXMLReader().setFeature(…)`) rather than the factory.
|
|
212
|
+
*
|
|
213
|
+
* Every other shape — a field, a helper that takes the factory, a caller that
|
|
214
|
+
* receives it — may be hardened somewhere this check cannot see, so it keeps
|
|
215
|
+
* the previous file-level silence.
|
|
216
|
+
*
|
|
217
|
+
* A TransformerFactory additionally needs a `StreamSource` in its method: that
|
|
218
|
+
* is the input the transformer parses with its OWN parser. Fed a `DOMSource`
|
|
219
|
+
* it parses nothing, and fed a `SAXSource` it uses the reader it was given —
|
|
220
|
+
* whose hardening is that reader's business, not this factory's.
|
|
221
|
+
*/
|
|
222
|
+
isProvablyUnhardened(lines, line, methodRanges, api) {
|
|
223
|
+
// Innermost enclosing method; without one the factory's reach is unknown.
|
|
224
|
+
let range = null;
|
|
225
|
+
for (const r of methodRanges) {
|
|
226
|
+
if (line < r[0] || line > r[1])
|
|
227
|
+
continue;
|
|
228
|
+
if (!range || r[1] - r[0] < range[1] - range[0])
|
|
229
|
+
range = r;
|
|
230
|
+
}
|
|
231
|
+
if (!range)
|
|
232
|
+
return false;
|
|
233
|
+
// The creating statement, joined to its `;` — `newInstance(` is often broken
|
|
234
|
+
// across lines after the opening parenthesis.
|
|
235
|
+
let decl = '';
|
|
236
|
+
let declEnd = line;
|
|
237
|
+
for (; declEnd <= Math.min(line + 3, range[1]); declEnd++) {
|
|
238
|
+
decl += ' ' + (lines[declEnd - 1] ?? '').trim();
|
|
239
|
+
if (decl.includes(';'))
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
const body = lines.slice(line - 1, range[1]).join('\n');
|
|
243
|
+
if (api === 'TransformerFactory' && !/\bnew\s+StreamSource\s*\(/.test(body))
|
|
244
|
+
return false;
|
|
245
|
+
// Hardening need not land on the factory: `parser.getXMLReader().setFeature(…)`
|
|
246
|
+
// and `parser.setProperty(…)` harden its PRODUCT. So a method containing any
|
|
247
|
+
// hardening-capable setter, on any receiver, is not provable either way.
|
|
248
|
+
if (JAVA_HARDENING_SETTER_RE.test(body))
|
|
249
|
+
return false;
|
|
250
|
+
const chained = JAVA_FACTORY_CHAINED_RE.exec(decl);
|
|
251
|
+
if (chained) {
|
|
252
|
+
// The product may still be handed to a helper that hardens it.
|
|
253
|
+
const prod = /[\w>\]]\s+([A-Za-z_$][\w$]*)\s*=/.exec(decl);
|
|
254
|
+
if (!prod)
|
|
255
|
+
return true;
|
|
256
|
+
const pn = prod[1].replace(/\$/g, '\\$');
|
|
257
|
+
const after = lines.slice(declEnd, range[1]).join('\n');
|
|
258
|
+
return !new RegExp(`[(,]\\s*${pn}\\s*[,)]|\\breturn\\s+${pn}\\s*;`).test(after);
|
|
259
|
+
}
|
|
260
|
+
// `Type name = …newInstance(…);` — a declaration ending the statement, so
|
|
261
|
+
// `name` is a local bound to the factory itself and not to a chained result.
|
|
262
|
+
const m = /[\w>\]]\s+([A-Za-z_$][\w$]*)\s*=\s*[\w.]*\bnewInstance\s*\([^()]*\)\s*;/.exec(decl);
|
|
263
|
+
if (!m)
|
|
264
|
+
return false;
|
|
265
|
+
const name = m[1].replace(/\$/g, '\\$');
|
|
266
|
+
const rest = lines.slice(declEnd, range[1]).join('\n');
|
|
267
|
+
// Only a factory that goes on to build a parser matters; one created to
|
|
268
|
+
// inspect (`factory.getClass()`) and dropped parses nothing.
|
|
269
|
+
const builds = new RegExp(`\\b${name}\\s*\\.\\s*(?:newDocumentBuilder|newSAXParser|newTransformer|newTemplates|newSchema|createXMLStreamReader|createXMLEventReader)\\s*\\(`);
|
|
270
|
+
if (!builds.test(rest))
|
|
271
|
+
return false;
|
|
272
|
+
// Passed to another call (`harden(dbf)`, `x.configure(a, dbf)`) or returned.
|
|
273
|
+
const escapes = new RegExp(`[(,]\\s*${name}\\s*[,)]|\\breturn\\s+${name}\\s*;`);
|
|
274
|
+
if (escapes.test(rest))
|
|
275
|
+
return false;
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
152
278
|
detectJavaCall(call) {
|
|
153
279
|
if (call.method_name !== 'newInstance')
|
|
154
280
|
return null;
|
|
@@ -160,7 +286,7 @@ export class XmlEntityExpansionPass {
|
|
|
160
286
|
return {
|
|
161
287
|
pattern: `${factory}.newInstance()`,
|
|
162
288
|
api: factory,
|
|
163
|
-
cwe: 'CWE-
|
|
289
|
+
cwe: 'CWE-611',
|
|
164
290
|
};
|
|
165
291
|
}
|
|
166
292
|
}
|
|
@@ -175,7 +301,7 @@ export class XmlEntityExpansionPass {
|
|
|
175
301
|
return {
|
|
176
302
|
pattern: `etree.${method}`,
|
|
177
303
|
api: `lxml.etree.${method}`,
|
|
178
|
-
cwe: 'CWE-
|
|
304
|
+
cwe: 'CWE-611',
|
|
179
305
|
};
|
|
180
306
|
}
|
|
181
307
|
// xml.etree.ElementTree.parse / fromstring
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xml-entity-expansion-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/xml-entity-expansion-pass.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"xml-entity-expansion-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/xml-entity-expansion-pass.ts"],"names":[],"mappings":"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"}
|
|
@@ -26446,16 +26446,21 @@ var CSharpPlugin = class extends BaseLanguagePlugin {
|
|
|
26446
26446
|
};
|
|
26447
26447
|
|
|
26448
26448
|
// src/languages/plugins/index.ts
|
|
26449
|
+
function createBuiltinPlugins() {
|
|
26450
|
+
return [
|
|
26451
|
+
new JavaPlugin(),
|
|
26452
|
+
new JavaScriptPlugin(),
|
|
26453
|
+
new PythonPlugin(),
|
|
26454
|
+
new RustPlugin(),
|
|
26455
|
+
new BashPlugin(),
|
|
26456
|
+
new HtmlPlugin(),
|
|
26457
|
+
new VuePlugin(),
|
|
26458
|
+
new GoPlugin(),
|
|
26459
|
+
new CSharpPlugin()
|
|
26460
|
+
];
|
|
26461
|
+
}
|
|
26449
26462
|
function registerBuiltinPlugins() {
|
|
26450
|
-
|
|
26451
|
-
registerLanguage(new JavaScriptPlugin());
|
|
26452
|
-
registerLanguage(new PythonPlugin());
|
|
26453
|
-
registerLanguage(new RustPlugin());
|
|
26454
|
-
registerLanguage(new BashPlugin());
|
|
26455
|
-
registerLanguage(new HtmlPlugin());
|
|
26456
|
-
registerLanguage(new VuePlugin());
|
|
26457
|
-
registerLanguage(new GoPlugin());
|
|
26458
|
-
registerLanguage(new CSharpPlugin());
|
|
26463
|
+
for (const plugin of createBuiltinPlugins()) registerLanguage(plugin);
|
|
26459
26464
|
}
|
|
26460
26465
|
|
|
26461
26466
|
// src/analysis/html/html-extractor.ts
|
|
@@ -46241,6 +46246,8 @@ var JAVA_XML_OUTPUT_ONLY_RE = /\bnew\s+(?:DOMSource|StreamResult)\s*\(/;
|
|
|
46241
46246
|
var JAVA_XML_PARSE_INPUT_RE = /\bnew\s+(?:StreamSource|SAXSource|InputSource)\s*\(/;
|
|
46242
46247
|
var JAVA_DOC_BUILDER_NEW_DOCUMENT_RE = /\.\s*newDocument\s*\(\s*\)/;
|
|
46243
46248
|
var JAVA_DOC_BUILDER_PARSE_RE = /(?:DocumentBuilder|builder)\s*\.\s*parse\s*\(/;
|
|
46249
|
+
var JAVA_HARDENING_SETTER_RE = /\.\s*(?:setFeature|setAttribute|setProperty|setXIncludeAware|setExpandEntityReferences)\s*\(/;
|
|
46250
|
+
var JAVA_FACTORY_CHAINED_RE = /\bnewInstance\s*\([^()]*\)\s*\.\s*(?:newDocumentBuilder|newSAXParser|newTransformer|newTemplates|newSchema|createXMLStreamReader|createXMLEventReader)\s*\(/;
|
|
46244
46251
|
var PY_LXML_PARSER_INSECURE_DEFAULT_RE = /\bresolve_entities\s*=\s*False\b/;
|
|
46245
46252
|
var XmlEntityExpansionPass = class {
|
|
46246
46253
|
name = "xml-entity-expansion";
|
|
@@ -46252,7 +46259,9 @@ var XmlEntityExpansionPass = class {
|
|
|
46252
46259
|
const code = ctx.code ?? "";
|
|
46253
46260
|
if (language === "java") {
|
|
46254
46261
|
const safeInFile = JAVA_SAFE_EVIDENCE_RE.test(code);
|
|
46255
|
-
|
|
46262
|
+
const processWide = safeInFile && /jdk\.xml\./.test(code);
|
|
46263
|
+
const lines = safeInFile ? code.split("\n") : [];
|
|
46264
|
+
const methodRanges = safeInFile ? this.methodRanges(graph.ir.types) : [];
|
|
46256
46265
|
const isXmlOutputOnly = JAVA_XML_OUTPUT_ONLY_RE.test(code) && !JAVA_XML_PARSE_INPUT_RE.test(code);
|
|
46257
46266
|
const isDocumentBuilderEmptyOnly = JAVA_DOC_BUILDER_NEW_DOCUMENT_RE.test(code) && !JAVA_DOC_BUILDER_PARSE_RE.test(code);
|
|
46258
46267
|
for (const call of graph.ir.calls) {
|
|
@@ -46262,6 +46271,8 @@ var XmlEntityExpansionPass = class {
|
|
|
46262
46271
|
if (det.api === "DocumentBuilderFactory" && isDocumentBuilderEmptyOnly)
|
|
46263
46272
|
continue;
|
|
46264
46273
|
const line = call.location.line;
|
|
46274
|
+
if (safeInFile && (processWide || !this.isProvablyUnhardened(lines, line, methodRanges, det.api)))
|
|
46275
|
+
continue;
|
|
46265
46276
|
findings.push({ line, language, ...det });
|
|
46266
46277
|
ctx.addFinding({
|
|
46267
46278
|
id: `${this.name}-${file}-${line}-${det.api}`,
|
|
@@ -46271,11 +46282,11 @@ var XmlEntityExpansionPass = class {
|
|
|
46271
46282
|
cwe: det.cwe,
|
|
46272
46283
|
severity: "high",
|
|
46273
46284
|
level: "error",
|
|
46274
|
-
message: `${det.api} created without disabling DTD / external-entity processing. Vulnerable to billion-laughs / quadratic blow-up DoS (CWE-776)
|
|
46285
|
+
message: `${det.api} created without disabling DTD / external-entity processing. Vulnerable to external-entity disclosure (CWE-611) and billion-laughs / quadratic blow-up DoS (CWE-776). Add \`setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)\` (or the equivalent) before parsing.`,
|
|
46275
46286
|
file,
|
|
46276
46287
|
line,
|
|
46277
46288
|
fix: this.fixForJava(det.api),
|
|
46278
|
-
evidence: { ...det, language, safeFeatureInFile:
|
|
46289
|
+
evidence: { ...det, language, safeFeatureInFile: safeInFile }
|
|
46279
46290
|
});
|
|
46280
46291
|
}
|
|
46281
46292
|
return { findings };
|
|
@@ -46296,7 +46307,7 @@ var XmlEntityExpansionPass = class {
|
|
|
46296
46307
|
cwe: det.cwe,
|
|
46297
46308
|
severity: "high",
|
|
46298
46309
|
level: "error",
|
|
46299
|
-
message: `${det.api} called without an entity-safe parser. Vulnerable to billion-laughs / quadratic blow-up DoS (CWE-776)
|
|
46310
|
+
message: `${det.api} called without an entity-safe parser. Vulnerable ` + (det.cwe === "CWE-611" ? "to external-entity disclosure (CWE-611) and billion-laughs / quadratic blow-up DoS (CWE-776). " : "to billion-laughs / quadratic blow-up DoS (CWE-776). ") + "Use `defusedxml` or pass an `XMLParser(resolve_entities=False)` to lxml.",
|
|
46300
46311
|
file,
|
|
46301
46312
|
line,
|
|
46302
46313
|
fix: this.fixForPython(det.api),
|
|
@@ -46307,6 +46318,78 @@ var XmlEntityExpansionPass = class {
|
|
|
46307
46318
|
}
|
|
46308
46319
|
return { findings };
|
|
46309
46320
|
}
|
|
46321
|
+
methodRanges(types) {
|
|
46322
|
+
const out2 = [];
|
|
46323
|
+
for (const t of types ?? []) {
|
|
46324
|
+
for (const m of t.methods ?? []) {
|
|
46325
|
+
if (typeof m.start_line === "number" && typeof m.end_line === "number")
|
|
46326
|
+
out2.push([m.start_line, m.end_line]);
|
|
46327
|
+
}
|
|
46328
|
+
}
|
|
46329
|
+
return out2;
|
|
46330
|
+
}
|
|
46331
|
+
/**
|
|
46332
|
+
* In a file that DOES contain hardening evidence, is the factory created on
|
|
46333
|
+
* `line` one that provably never receives it?
|
|
46334
|
+
*
|
|
46335
|
+
* Deliberately one-sided. It answers true for exactly two shapes:
|
|
46336
|
+
*
|
|
46337
|
+
* 1. CHAINED — `Factory.newInstance().newDocumentBuilder()`, where the
|
|
46338
|
+
* product is not handed on or returned either.
|
|
46339
|
+
* 2. LOCAL — `Factory f = Factory.newInstance();` where the enclosing method
|
|
46340
|
+
* builds a parser from `f`, never hands `f` to another call, and never
|
|
46341
|
+
* returns it.
|
|
46342
|
+
*
|
|
46343
|
+
* and in both only when the enclosing method contains NO hardening-capable
|
|
46344
|
+
* setter on ANY receiver, since hardening may land on the factory's product
|
|
46345
|
+
* (`parser.getXMLReader().setFeature(…)`) rather than the factory.
|
|
46346
|
+
*
|
|
46347
|
+
* Every other shape — a field, a helper that takes the factory, a caller that
|
|
46348
|
+
* receives it — may be hardened somewhere this check cannot see, so it keeps
|
|
46349
|
+
* the previous file-level silence.
|
|
46350
|
+
*
|
|
46351
|
+
* A TransformerFactory additionally needs a `StreamSource` in its method: that
|
|
46352
|
+
* is the input the transformer parses with its OWN parser. Fed a `DOMSource`
|
|
46353
|
+
* it parses nothing, and fed a `SAXSource` it uses the reader it was given —
|
|
46354
|
+
* whose hardening is that reader's business, not this factory's.
|
|
46355
|
+
*/
|
|
46356
|
+
isProvablyUnhardened(lines, line, methodRanges, api) {
|
|
46357
|
+
let range = null;
|
|
46358
|
+
for (const r of methodRanges) {
|
|
46359
|
+
if (line < r[0] || line > r[1]) continue;
|
|
46360
|
+
if (!range || r[1] - r[0] < range[1] - range[0]) range = r;
|
|
46361
|
+
}
|
|
46362
|
+
if (!range) return false;
|
|
46363
|
+
let decl = "";
|
|
46364
|
+
let declEnd = line;
|
|
46365
|
+
for (; declEnd <= Math.min(line + 3, range[1]); declEnd++) {
|
|
46366
|
+
decl += " " + (lines[declEnd - 1] ?? "").trim();
|
|
46367
|
+
if (decl.includes(";")) break;
|
|
46368
|
+
}
|
|
46369
|
+
const body2 = lines.slice(line - 1, range[1]).join("\n");
|
|
46370
|
+
if (api === "TransformerFactory" && !/\bnew\s+StreamSource\s*\(/.test(body2))
|
|
46371
|
+
return false;
|
|
46372
|
+
if (JAVA_HARDENING_SETTER_RE.test(body2)) return false;
|
|
46373
|
+
const chained = JAVA_FACTORY_CHAINED_RE.exec(decl);
|
|
46374
|
+
if (chained) {
|
|
46375
|
+
const prod = /[\w>\]]\s+([A-Za-z_$][\w$]*)\s*=/.exec(decl);
|
|
46376
|
+
if (!prod) return true;
|
|
46377
|
+
const pn = prod[1].replace(/\$/g, "\\$");
|
|
46378
|
+
const after = lines.slice(declEnd, range[1]).join("\n");
|
|
46379
|
+
return !new RegExp(`[(,]\\s*${pn}\\s*[,)]|\\breturn\\s+${pn}\\s*;`).test(after);
|
|
46380
|
+
}
|
|
46381
|
+
const m = /[\w>\]]\s+([A-Za-z_$][\w$]*)\s*=\s*[\w.]*\bnewInstance\s*\([^()]*\)\s*;/.exec(decl);
|
|
46382
|
+
if (!m) return false;
|
|
46383
|
+
const name2 = m[1].replace(/\$/g, "\\$");
|
|
46384
|
+
const rest = lines.slice(declEnd, range[1]).join("\n");
|
|
46385
|
+
const builds = new RegExp(
|
|
46386
|
+
`\\b${name2}\\s*\\.\\s*(?:newDocumentBuilder|newSAXParser|newTransformer|newTemplates|newSchema|createXMLStreamReader|createXMLEventReader)\\s*\\(`
|
|
46387
|
+
);
|
|
46388
|
+
if (!builds.test(rest)) return false;
|
|
46389
|
+
const escapes = new RegExp(`[(,]\\s*${name2}\\s*[,)]|\\breturn\\s+${name2}\\s*;`);
|
|
46390
|
+
if (escapes.test(rest)) return false;
|
|
46391
|
+
return true;
|
|
46392
|
+
}
|
|
46310
46393
|
detectJavaCall(call) {
|
|
46311
46394
|
if (call.method_name !== "newInstance") return null;
|
|
46312
46395
|
const recv = call.receiver ?? "";
|
|
@@ -46316,7 +46399,7 @@ var XmlEntityExpansionPass = class {
|
|
|
46316
46399
|
return {
|
|
46317
46400
|
pattern: `${factory}.newInstance()`,
|
|
46318
46401
|
api: factory,
|
|
46319
|
-
cwe: "CWE-
|
|
46402
|
+
cwe: "CWE-611"
|
|
46320
46403
|
};
|
|
46321
46404
|
}
|
|
46322
46405
|
}
|
|
@@ -46329,7 +46412,7 @@ var XmlEntityExpansionPass = class {
|
|
|
46329
46412
|
return {
|
|
46330
46413
|
pattern: `etree.${method}`,
|
|
46331
46414
|
api: `lxml.etree.${method}`,
|
|
46332
|
-
cwe: "CWE-
|
|
46415
|
+
cwe: "CWE-611"
|
|
46333
46416
|
};
|
|
46334
46417
|
}
|
|
46335
46418
|
if ((method === "parse" || method === "fromstring") && (recv === "ET" || recv === "ElementTree" || recv.endsWith(".ElementTree"))) {
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export type { UnboundedCollectionOptions } from './analysis/passes/unbounded-col
|
|
|
12
12
|
export type { PassOptions } from './analyzer.js';
|
|
13
13
|
export type { CircleIR, Meta, TypeInfo, MethodInfo, ParameterInfo, FieldInfo, CallInfo, ArgumentInfo, CallResolution, CFG, CFGBlock, CFGEdge, DFG, DFGDef, DFGUse, DFGChain, Taint, TaintSource, TaintSink, TaintSanitizer, ImportInfo, ExportInfo, UnresolvedItem, Enriched, EnrichedFunction, ResolvedCall, Finding, TaintHop, Vulnerability, AnalysisResponse, SourceType, SinkType, Severity, ProjectShape, ProjectEnv, ProjectProfile, ProjectProfileSummary, PassCategory, SarifLevel, SastFinding, MetricCategory, MetricValue, FileMetrics, ProjectAnalysis, ProjectMeta, FileAnalysis, TypeHierarchy, ClassHierarchyInfo, InterfaceHierarchyInfo, CrossFileCall, ArgMapping, TaintPath, } from './types/index.js';
|
|
14
14
|
export { SOURCE_TYPES, SINK_TYPES } from './types/index.js';
|
|
15
|
+
export { getModelledCwes, isModelledCwe, RELATED_CWE, type ModelledCwes, } from './analysis/modelled-cwes.js';
|
|
15
16
|
export type { SourceConfig, SinkConfig, TaintConfig, SourcePattern, SinkPattern, SanitizerPattern, } from './types/config.js';
|
|
16
17
|
export { initParser, parse, walkTree, findNodes, findAncestor, getNodeText, collectAllNodes, type SupportedLanguage, type SyntaxNode, type Node, type NodeCache, type Tree, } from './core/index.js';
|
|
17
18
|
export { extractMeta, extractTypes, extractCalls, extractImports, extractExports, buildCFG, buildDFG, } from './core/index.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACL,YAAY,EACZ,OAAO,EACP,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,aAAa,EACb,KAAK,eAAe,GACrB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,0BAA0B,EAC1B,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,MAAM,GACP,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,UAAU,EACV,SAAS,EACT,eAAe,EACf,YAAY,GACb,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EAAE,uBAAuB,EAAE,MAAM,6CAA6C,CAAC;AAC3F,YAAY,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AAC5F,YAAY,EAAE,0BAA0B,EAAE,MAAM,gDAAgD,CAAC;AACjG,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,YAAY,EAEV,QAAQ,EACR,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,aAAa,EACb,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,cAAc,EACd,GAAG,EACH,QAAQ,EACR,OAAO,EACP,GAAG,EACH,MAAM,EACN,MAAM,EACN,QAAQ,EACR,KAAK,EACL,WAAW,EACX,SAAS,EACT,cAAc,EACd,UAAU,EACV,UAAU,EACV,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,aAAa,EACb,gBAAgB,EAGhB,UAAU,EACV,QAAQ,EACR,QAAQ,EAGR,YAAY,EACZ,UAAU,EACV,cAAc,EACd,qBAAqB,EAGrB,YAAY,EACZ,UAAU,EACV,WAAW,EACX,cAAc,EACd,WAAW,EACX,WAAW,EAGX,eAAe,EACf,WAAW,EACX,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,sBAAsB,EACtB,aAAa,EACb,UAAU,EACV,SAAS,GACV,MAAM,kBAAkB,CAAC;AAU1B,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,9 @@ export { parseNpmDependencies, parseNpmLockDependencies, parsePypiDependencies,
|
|
|
16
16
|
// an unmatched value fails a test on their side rather than falling through
|
|
17
17
|
// to a default branch. Locked by tests/public-entry-exports.test.ts.
|
|
18
18
|
export { SOURCE_TYPES, SINK_TYPES } from './types/index.js';
|
|
19
|
+
// Modelled-CWE export (#393) — which weakness classes the taint engine covers,
|
|
20
|
+
// derived from the live sink registries.
|
|
21
|
+
export { getModelledCwes, isModelledCwe, RELATED_CWE, } from './analysis/modelled-cwes.js';
|
|
19
22
|
// Core utilities (for advanced usage)
|
|
20
23
|
export { initParser, parse, walkTree, findNodes, findAncestor, getNodeText, collectAllNodes, } from './core/index.js';
|
|
21
24
|
// Core extractors
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,gBAAgB;AAChB,OAAO,EACL,YAAY,EACZ,OAAO,EACP,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,aAAa,GAEd,MAAM,eAAe,CAAC;AAEvB,4EAA4E;AAC5E,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,0BAA0B,EAC1B,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,MAAM,GACP,MAAM,oBAAoB,CAAC;AA+E5B,sEAAsE;AACtE,6EAA6E;AAC7E,2EAA2E;AAC3E,6EAA6E;AAC7E,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,qEAAqE;AACrE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,gBAAgB;AAChB,OAAO,EACL,YAAY,EACZ,OAAO,EACP,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,aAAa,GAEd,MAAM,eAAe,CAAC;AAEvB,4EAA4E;AAC5E,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,EACtB,uBAAuB,EACvB,sBAAsB,EACtB,0BAA0B,EAC1B,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,MAAM,GACP,MAAM,oBAAoB,CAAC;AA+E5B,sEAAsE;AACtE,6EAA6E;AAC7E,2EAA2E;AAC3E,6EAA6E;AAC7E,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,qEAAqE;AACrE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE5D,+EAA+E;AAC/E,yCAAyC;AACzC,OAAO,EACL,eAAe,EACf,aAAa,EACb,WAAW,GAEZ,MAAM,6BAA6B,CAAC;AAYrC,sCAAsC;AACtC,OAAO,EACL,UAAU,EACV,KAAK,EACL,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,WAAW,EACX,eAAe,GAMhB,MAAM,iBAAiB,CAAC;AAEzB,kBAAkB;AAClB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,cAAc,EACd,QAAQ,EACR,QAAQ,GACT,MAAM,iBAAiB,CAAC;AAEzB,qBAAqB;AACrB,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,yBAAyB,EACzB,0BAA0B,EAC1B,gCAAgC,EAChC,0BAA0B,EAC1B,kBAAkB,EAClB,OAAO,EACP,aAAa,EACb,WAAW,EACX,eAAe,EACf,aAAa,EACb,kBAAkB,GAMnB,MAAM,qBAAqB,CAAC;AAE7B,mBAAmB;AACnB,OAAO,EACL,WAAW,EACX,gBAAgB,GAEjB,MAAM,qBAAqB,CAAC;AAE7B,kBAAkB;AAClB,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAqB,MAAM,iCAAiC,CAAC;AAExF,uBAAuB;AACvB,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAE/B,mBAAmB;AACnB,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,UAAU,EACV,UAAU,EACV,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAY9B,gCAAgC;AAChC,OAAO,EACL,MAAM,EACN,SAAS,EACT,eAAe,EACf,WAAW,EACX,WAAW,GAIZ,MAAM,mBAAmB,CAAC"}
|
|
@@ -12,6 +12,14 @@ export { HtmlPlugin } from './html.js';
|
|
|
12
12
|
export { VuePlugin } from './vue.js';
|
|
13
13
|
export { GoPlugin } from './go.js';
|
|
14
14
|
export { CSharpPlugin } from './csharp.js';
|
|
15
|
+
import type { LanguagePlugin } from '../types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Fresh instances of every built-in language plugin, unregistered. The single
|
|
18
|
+
* list both `registerBuiltinPlugins` and registry-wide enumerations (e.g. the
|
|
19
|
+
* modelled-CWE export) read, so a new plugin cannot be added to one and missed
|
|
20
|
+
* by the other.
|
|
21
|
+
*/
|
|
22
|
+
export declare function createBuiltinPlugins(): LanguagePlugin[];
|
|
15
23
|
/**
|
|
16
24
|
* Register all built-in language plugins with the global registry.
|
|
17
25
|
* Call this during analyzer initialization.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/languages/plugins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/languages/plugins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAWlD;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,cAAc,EAAE,CAYvD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C"}
|
|
@@ -22,19 +22,31 @@ import { HtmlPlugin } from './html.js';
|
|
|
22
22
|
import { VuePlugin } from './vue.js';
|
|
23
23
|
import { GoPlugin } from './go.js';
|
|
24
24
|
import { CSharpPlugin } from './csharp.js';
|
|
25
|
+
/**
|
|
26
|
+
* Fresh instances of every built-in language plugin, unregistered. The single
|
|
27
|
+
* list both `registerBuiltinPlugins` and registry-wide enumerations (e.g. the
|
|
28
|
+
* modelled-CWE export) read, so a new plugin cannot be added to one and missed
|
|
29
|
+
* by the other.
|
|
30
|
+
*/
|
|
31
|
+
export function createBuiltinPlugins() {
|
|
32
|
+
return [
|
|
33
|
+
new JavaPlugin(),
|
|
34
|
+
new JavaScriptPlugin(),
|
|
35
|
+
new PythonPlugin(),
|
|
36
|
+
new RustPlugin(),
|
|
37
|
+
new BashPlugin(),
|
|
38
|
+
new HtmlPlugin(),
|
|
39
|
+
new VuePlugin(),
|
|
40
|
+
new GoPlugin(),
|
|
41
|
+
new CSharpPlugin(),
|
|
42
|
+
];
|
|
43
|
+
}
|
|
25
44
|
/**
|
|
26
45
|
* Register all built-in language plugins with the global registry.
|
|
27
46
|
* Call this during analyzer initialization.
|
|
28
47
|
*/
|
|
29
48
|
export function registerBuiltinPlugins() {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
registerLanguage(new PythonPlugin());
|
|
33
|
-
registerLanguage(new RustPlugin());
|
|
34
|
-
registerLanguage(new BashPlugin());
|
|
35
|
-
registerLanguage(new HtmlPlugin());
|
|
36
|
-
registerLanguage(new VuePlugin());
|
|
37
|
-
registerLanguage(new GoPlugin());
|
|
38
|
-
registerLanguage(new CSharpPlugin());
|
|
49
|
+
for (const plugin of createBuiltinPlugins())
|
|
50
|
+
registerLanguage(plugin);
|
|
39
51
|
}
|
|
40
52
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/languages/plugins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/languages/plugins/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,IAAI,UAAU,EAAE;QAChB,IAAI,gBAAgB,EAAE;QACtB,IAAI,YAAY,EAAE;QAClB,IAAI,UAAU,EAAE;QAChB,IAAI,UAAU,EAAE;QAChB,IAAI,UAAU,EAAE;QAChB,IAAI,SAAS,EAAE;QACf,IAAI,QAAQ,EAAE;QACd,IAAI,YAAY,EAAE;KACnB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,KAAK,MAAM,MAAM,IAAI,oBAAoB,EAAE;QAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACxE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circle-ir",
|
|
3
|
-
"version": "4.9.
|
|
3
|
+
"version": "4.9.22",
|
|
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",
|