Skip to content

Commit 3f203ea

Browse files
authored
Merge pull request github#11486 from github/tiferet/boost-xss-through-dom
ATM: Boost XssThroughDOM
2 parents fae5a9a + 155c146 commit 3f203ea

File tree

11 files changed

+911
-9
lines changed

11 files changed

+911
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* For internal use only.
3+
*
4+
* A taint-tracking configuration for reasoning about XSS through the DOM.
5+
* Defines shared code used by the XSS Through DOM boosted query.
6+
*/
7+
8+
private import semmle.javascript.heuristics.SyntacticHeuristics
9+
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
10+
private import semmle.javascript.dataflow.InferredTypes
11+
private import semmle.javascript.security.dataflow.XssThroughDomCustomizations::XssThroughDom as XssThroughDom
12+
private import semmle.javascript.security.dataflow.UnsafeJQueryPluginCustomizations::UnsafeJQueryPlugin as UnsafeJQuery
13+
import AdaptiveThreatModeling
14+
15+
class XssThroughDomAtmConfig extends AtmConfig {
16+
XssThroughDomAtmConfig() { this = "XssThroughDomAtmConfig" }
17+
18+
override predicate isKnownSource(DataFlow::Node source) {
19+
source instanceof XssThroughDom::Source
20+
}
21+
22+
override EndpointType getASinkEndpointType() { result instanceof XssSinkType }
23+
24+
override predicate isSanitizer(DataFlow::Node node) {
25+
super.isSanitizer(node) or
26+
node instanceof DomBasedXss::Sanitizer
27+
}
28+
29+
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
30+
guard instanceof TypeTestGuard or
31+
guard instanceof UnsafeJQuery::PropertyPresenceSanitizer or
32+
guard instanceof UnsafeJQuery::NumberGuard or
33+
guard instanceof PrefixStringSanitizer or
34+
guard instanceof QuoteGuard or
35+
guard instanceof ContainsHtmlGuard
36+
}
37+
38+
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
39+
DomBasedXss::isOptionallySanitizedEdge(pred, succ)
40+
}
41+
}
42+
43+
/**
44+
* A test of form `typeof x === "something"`, preventing `x` from being a string in some cases.
45+
*
46+
* This sanitizer helps prune infeasible paths in type-overloaded functions.
47+
*/
48+
class TypeTestGuard extends TaintTracking::SanitizerGuardNode, DataFlow::ValueNode {
49+
override EqualityTest astNode;
50+
Expr operand;
51+
boolean polarity;
52+
53+
TypeTestGuard() {
54+
exists(TypeofTag tag | TaintTracking::isTypeofGuard(astNode, operand, tag) |
55+
// typeof x === "string" sanitizes `x` when it evaluates to false
56+
tag = "string" and
57+
polarity = astNode.getPolarity().booleanNot()
58+
or
59+
// typeof x === "object" sanitizes `x` when it evaluates to true
60+
tag != "string" and
61+
polarity = astNode.getPolarity()
62+
)
63+
}
64+
65+
override predicate sanitizes(boolean outcome, Expr e) {
66+
polarity = outcome and
67+
e = operand
68+
}
69+
}
70+
71+
private import semmle.javascript.security.dataflow.Xss::Shared as Shared
72+
73+
private class PrefixStringSanitizer extends TaintTracking::SanitizerGuardNode,
74+
DomBasedXss::PrefixStringSanitizer {
75+
PrefixStringSanitizer() { this = this }
76+
}
77+
78+
private class PrefixString extends DataFlow::FlowLabel, DomBasedXss::PrefixString {
79+
PrefixString() { this = this }
80+
}
81+
82+
private class QuoteGuard extends TaintTracking::SanitizerGuardNode, Shared::QuoteGuard {
83+
QuoteGuard() { this = this }
84+
}
85+
86+
private class ContainsHtmlGuard extends TaintTracking::SanitizerGuardNode, Shared::ContainsHtmlGuard {
87+
ContainsHtmlGuard() { this = this }
88+
}

javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/DebugResultInclusion.ql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ private import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInj
1616
private import experimental.adaptivethreatmodeling.SqlInjectionATM as SqlInjectionAtm
1717
private import experimental.adaptivethreatmodeling.TaintedPathATM as TaintedPathAtm
1818
private import experimental.adaptivethreatmodeling.XssATM as XssAtm
19+
private import experimental.adaptivethreatmodeling.XssThroughDomATM as XssThroughDomAtm
1920

2021
string getAReasonSinkExcluded(DataFlow::Node sinkCandidate, Query query) {
2122
query instanceof NosqlInjectionQuery and
@@ -29,6 +30,9 @@ string getAReasonSinkExcluded(DataFlow::Node sinkCandidate, Query query) {
2930
or
3031
query instanceof XssQuery and
3132
result = any(XssAtm::DomBasedXssAtmConfig cfg).getAReasonSinkExcluded(sinkCandidate)
33+
or
34+
query instanceof XssThroughDomQuery and
35+
result = any(XssThroughDomAtm::XssThroughDomAtmConfig cfg).getAReasonSinkExcluded(sinkCandidate)
3236
}
3337

3438
pragma[inline]

javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/extraction/ExtractEndpointDataTraining.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ private import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInj
1414
private import experimental.adaptivethreatmodeling.SqlInjectionATM as SqlInjectionAtm
1515
private import experimental.adaptivethreatmodeling.TaintedPathATM as TaintedPathAtm
1616
private import experimental.adaptivethreatmodeling.XssATM as XssAtm
17+
private import experimental.adaptivethreatmodeling.XssThroughDomATM as XssThroughDomAtm
1718

1819
/**
1920
* Gets the set of featureName-featureValue pairs for each endpoint in the training set.
@@ -214,6 +215,8 @@ DataFlow::Configuration getDataFlowCfg(Query query) {
214215
query instanceof TaintedPathQuery and result instanceof TaintedPathAtm::TaintedPathAtmConfig
215216
or
216217
query instanceof XssQuery and result instanceof XssAtm::DomBasedXssAtmConfig
218+
or
219+
query instanceof XssThroughDomQuery and result instanceof XssThroughDomAtm::XssThroughDomAtmConfig
217220
}
218221

219222
// TODO: Delete this once we are no longer surfacing `hasFlowFromSource`.

javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/extraction/ExtractEndpointMapping.ql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import experimental.adaptivethreatmodeling.SqlInjectionATM as SqlInjectionAtm
88
import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInjectionAtm
99
import experimental.adaptivethreatmodeling.TaintedPathATM as TaintedPathAtm
1010
import experimental.adaptivethreatmodeling.XssATM as XssAtm
11+
import experimental.adaptivethreatmodeling.XssThroughDomATM as XssThroughDomAtm
1112
import experimental.adaptivethreatmodeling.AdaptiveThreatModeling
1213

1314
from string queryName, AtmConfig c, EndpointType e
@@ -23,6 +24,8 @@ where
2324
c instanceof TaintedPathAtm::TaintedPathAtmConfig
2425
or
2526
queryName = "Xss" and c instanceof XssAtm::DomBasedXssAtmConfig
27+
or
28+
queryName = "XssThroughDom" and c instanceof XssThroughDomAtm::XssThroughDomAtmConfig
2629
) and
2730
e = c.getASinkEndpointType()
2831
select queryName, e.getEncoding() as label

javascript/ql/experimental/adaptivethreatmodeling/modelbuilding/extraction/Queries.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ newtype TQuery =
88
TNosqlInjectionQuery() or
99
TSqlInjectionQuery() or
1010
TTaintedPathQuery() or
11-
TXssQuery()
11+
TXssQuery() or
12+
TXssThroughDomQuery()
1213

1314
abstract class Query extends TQuery {
1415
abstract string getName();
@@ -31,3 +32,7 @@ class TaintedPathQuery extends Query, TTaintedPathQuery {
3132
class XssQuery extends Query, TXssQuery {
3233
override string getName() { result = "Xss" }
3334
}
35+
36+
class XssThroughDomQuery extends Query, TXssThroughDomQuery {
37+
override string getName() { result = "XssThroughDom" }
38+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* For internal use only.
3+
*
4+
* @name DOM text reinterpreted as HTML (experimental)
5+
* @description Reinterpreting text from the DOM as HTML can lead
6+
* to a cross-site scripting vulnerability.
7+
* @kind path-problem
8+
* @scored
9+
* @problem.severity error
10+
* @security-severity 6.1
11+
* @id js/ml-powered/xss-through-dom
12+
* @tags experimental security
13+
* external/cwe/cwe-079 external/cwe/cwe-116
14+
*/
15+
16+
import javascript
17+
import ATM::ResultsInfo
18+
import DataFlow::PathGraph
19+
import experimental.adaptivethreatmodeling.XssThroughDomATM
20+
21+
from AtmConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink, float score
22+
where cfg.hasBoostedFlowPath(source, sink, score)
23+
select sink.getNode(), source, sink,
24+
"(Experimental) $@ may be reinterpreted as HTML without escaping meta-characters. Identified using machine learning.",
25+
source.getNode(), "DOM text", score

javascript/ql/experimental/adaptivethreatmodeling/test/endpoint_large_scale/EndpointFeatures.ql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import experimental.adaptivethreatmodeling.NosqlInjectionATM as NosqlInjectionAt
1111
import experimental.adaptivethreatmodeling.SqlInjectionATM as SqlInjectionAtm
1212
import experimental.adaptivethreatmodeling.TaintedPathATM as TaintedPathAtm
1313
import experimental.adaptivethreatmodeling.XssATM as XssAtm
14+
import experimental.adaptivethreatmodeling.XssThroughDomATM as XssThroughDomAtm
1415
import experimental.adaptivethreatmodeling.EndpointFeatures as EndpointFeatures
1516
import extraction.NoFeaturizationRestrictionsConfig
1617
private import experimental.adaptivethreatmodeling.EndpointCharacteristics as EndpointCharacteristics
@@ -21,6 +22,7 @@ query predicate tokenFeatures(DataFlow::Node endpoint, string featureName, strin
2122
not exists(any(SqlInjectionAtm::SqlInjectionAtmConfig cfg).getAReasonSinkExcluded(endpoint)) or
2223
not exists(any(TaintedPathAtm::TaintedPathAtmConfig cfg).getAReasonSinkExcluded(endpoint)) or
2324
not exists(any(XssAtm::DomBasedXssAtmConfig cfg).getAReasonSinkExcluded(endpoint)) or
25+
not exists(any(XssThroughDomAtm::XssThroughDomAtmConfig cfg).getAReasonSinkExcluded(endpoint)) or
2426
any(EndpointCharacteristics::IsArgumentToModeledFunctionCharacteristic characteristic)
2527
.appliesToEndpoint(endpoint)
2628
) and

0 commit comments

Comments
 (0)