move the DomBasedXss sources/sinks into the Customizations file

This commit is contained in:
Erik Krogh Kristensen
2022-04-20 10:28:06 +02:00
parent 9631b68de9
commit 173e1d0262
14 changed files with 335 additions and 328 deletions

View File

@@ -3,7 +3,7 @@
*/
private import javascript
private import semmle.javascript.security.dataflow.Xss
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
private import semmle.javascript.security.dataflow.CodeInjectionCustomizations
private import semmle.javascript.security.dataflow.ClientSideUrlRedirectCustomizations
private import semmle.javascript.DynamicPropertyAccess

View File

@@ -3,7 +3,7 @@
*/
import javascript
private import semmle.javascript.security.dataflow.Xss as Xss
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
module Cheerio {
/** Gets a reference to the `cheerio` function, possibly with a loaded DOM. */
@@ -95,7 +95,7 @@ module Cheerio {
/**
* An XSS sink through `cheerio`.
*/
class XssSink extends Xss::DomBasedXss::Sink {
class XssSink extends DomBasedXss::Sink {
XssSink() {
exists(string name | this = cheerioObjectRef().getAMethodCall(name).getAnArgument() |
JQuery::isMethodArgumentInterpretedAsHtml(name)

View File

@@ -1,7 +1,7 @@
/** Provides classes and predicates modeling aspects of the `d3` library. */
private import javascript
private import semmle.javascript.security.dataflow.Xss
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
/** Provides classes and predicates modeling aspects of the `d3` library. */
module D3 {

View File

@@ -3,7 +3,7 @@
*/
private import javascript
private import semmle.javascript.security.dataflow.Xss
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
private import semmle.javascript.security.dataflow.ClientSideUrlRedirectCustomizations
private import semmle.javascript.security.dataflow.CodeInjectionCustomizations

View File

@@ -16,6 +16,7 @@ private import semmle.javascript.security.dataflow.RegExpInjectionCustomizations
private import semmle.javascript.security.dataflow.ClientSideUrlRedirectCustomizations
private import semmle.javascript.security.dataflow.ServerSideUrlRedirectCustomizations
private import semmle.javascript.security.dataflow.InsecureRandomnessCustomizations
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
private import HeuristicSinks as Sinks
class HeuristicSink = Sinks::HeuristicSink;
@@ -30,7 +31,7 @@ private class HeuristicCommandInjectionSink extends HeuristicSink, CommandInject
}
}
private class HeuristicDomBasedXssSink extends HeuristicSink, Xss::DomBasedXss::Sink {
private class HeuristicDomBasedXssSink extends HeuristicSink, DomBasedXss::Sink {
HeuristicDomBasedXssSink() {
isAssignedToOrConcatenatedWith(this, "(?i)(html|innerhtml)") or
isArgTo(this, "(?i)(html|render)") or

View File

@@ -4,9 +4,322 @@
*/
import javascript
private import semmle.javascript.dataflow.InferredTypes
module DomBasedXss {
import Xss::DomBasedXss
private import Xss::Shared as Shared
/** A data flow source for DOM-based XSS vulnerabilities. */
abstract class Source extends Shared::Source { }
/** A data flow sink for DOM-based XSS vulnerabilities. */
abstract class Sink extends Shared::Sink { }
/** A sanitizer for DOM-based XSS vulnerabilities. */
abstract class Sanitizer extends Shared::Sanitizer { }
/** A sanitizer guard for DOM-based XSS vulnerabilities. */
abstract class SanitizerGuard extends Shared::SanitizerGuard { }
/**
* An expression whose value is interpreted as HTML
* and may be inserted into the DOM through a library.
*/
class LibrarySink extends Sink {
LibrarySink() {
// call to a jQuery method that interprets its argument as HTML
exists(JQuery::MethodCall call |
call.interpretsArgumentAsHtml(this) and
not call.interpretsArgumentAsSelector(this) // Handled by `JQuerySelectorSink`
)
or
// call to an Angular method that interprets its argument as HTML
any(AngularJS::AngularJSCall call).interpretsArgumentAsHtml(this.asExpr())
or
// call to a WinJS function that interprets its argument as HTML
exists(DataFlow::MethodCallNode mcn, string m |
m = "setInnerHTMLUnsafe" or m = "setOuterHTMLUnsafe"
|
mcn.getMethodName() = m and
this = mcn.getArgument(1)
)
or
this = any(Typeahead::TypeaheadSuggestionFunction f).getAReturn()
or
this = any(Handlebars::SafeString s).getAnArgument()
or
this = any(JQuery::MethodCall call | call.getMethodName() = "jGrowl").getArgument(0)
or
// A construction of a JSDOM object (server side DOM), where scripts are allowed.
exists(DataFlow::NewNode instance |
instance = API::moduleImport("jsdom").getMember("JSDOM").getInstance().getAnImmediateUse() and
this = instance.getArgument(0) and
instance.getOptionArgument(1, "runScripts").mayHaveStringValue("dangerously")
)
or
MooTools::interpretsNodeAsHtml(this)
}
}
/**
* Holds if `prefix` is a prefix of `htmlString`, which may be intepreted as
* HTML by a jQuery method.
*/
predicate isPrefixOfJQueryHtmlString(DataFlow::Node htmlString, DataFlow::Node prefix) {
prefix = getAPrefixOfJQuerySelectorString(htmlString)
}
/**
* Holds if `prefix` is a prefix of `htmlString`, which may be intepreted as
* HTML by a jQuery method.
*/
private DataFlow::Node getAPrefixOfJQuerySelectorString(DataFlow::Node htmlString) {
any(JQuery::MethodCall call).interpretsArgumentAsSelector(htmlString) and
result = htmlString
or
exists(DataFlow::Node pred | pred = getAPrefixOfJQuerySelectorString(htmlString) |
result = StringConcatenation::getFirstOperand(pred)
or
result = pred.getAPredecessor()
)
}
/**
* An argument to the jQuery `$` function or similar, which is interpreted as either a selector
* or as an HTML string depending on its first character.
*/
class JQueryHtmlOrSelectorArgument extends DataFlow::Node {
JQueryHtmlOrSelectorArgument() {
exists(JQuery::MethodCall call |
call.interpretsArgumentAsHtml(this) and
call.interpretsArgumentAsSelector(this) and
pragma[only_bind_out](this.analyze()).getAType() = TTString()
)
}
/** Gets a string that flows to the prefix of this argument. */
string getAPrefix() { result = getAPrefixOfJQuerySelectorString(this).getStringValue() }
}
/**
* An argument to the jQuery `$` function or similar, which may be interpreted as HTML.
*
* This is the same as `JQueryHtmlOrSelectorArgument`, excluding cases where the value
* is prefixed by something other than `<`.
*/
class JQueryHtmlOrSelectorSink extends Sink, JQueryHtmlOrSelectorArgument {
JQueryHtmlOrSelectorSink() {
// If a prefix of the string is known, it must start with '<' or be an empty string
forall(string strval | strval = this.getAPrefix() | strval.regexpMatch("(?s)\\s*<.*|"))
}
}
import ClientSideUrlRedirectCustomizations::ClientSideUrlRedirect as ClientSideUrlRedirect
/**
* A write to a URL which may execute JavaScript code.
*/
class WriteURLSink extends Sink instanceof ClientSideUrlRedirect::Sink {
WriteURLSink() { super.isXssSink() }
}
/**
* An expression whose value is interpreted as HTML or CSS
* and may be inserted into the DOM.
*/
class DomSink extends Sink {
DomSink() {
// Call to a DOM function that inserts its argument into the DOM
any(DomMethodCallExpr call).interpretsArgumentsAsHtml(this.asExpr())
or
// Assignment to a dangerous DOM property
exists(DomPropWriteNode pw |
pw.interpretsValueAsHtml() and
this = DataFlow::valueNode(pw.getRhs())
)
or
// `html` or `source.html` properties of React Native `WebView`
exists(ReactNative::WebViewElement webView, DataFlow::SourceNode source |
source = webView or
source = webView.getAPropertyWrite("source").getRhs().getALocalSource()
|
this = source.getAPropertyWrite("html").getRhs()
)
}
}
/**
* An expression whose value is interpreted as HTML.
*/
class HtmlParserSink extends Sink {
HtmlParserSink() {
exists(DataFlow::GlobalVarRefNode domParser |
domParser.getName() = "DOMParser" and
this = domParser.getAnInstantiation().getAMethodCall("parseFromString").getArgument(0)
)
or
exists(DataFlow::MethodCallNode ccf |
isDomValue(ccf.getReceiver().asExpr()) and
ccf.getMethodName() = "createContextualFragment" and
this = ccf.getArgument(0)
)
}
}
/**
* A React `dangerouslySetInnerHTML` attribute, viewed as an XSS sink.
*
* Any write to the `__html` property of an object assigned to this attribute
* is considered an XSS sink.
*/
class DangerouslySetInnerHtmlSink extends Sink, DataFlow::ValueNode {
DangerouslySetInnerHtmlSink() {
exists(DataFlow::Node danger, DataFlow::SourceNode valueSrc |
exists(JsxAttribute attr |
attr.getName() = "dangerouslySetInnerHTML" and
attr.getValue() = danger.asExpr()
)
or
exists(ReactElementDefinition def, DataFlow::ObjectLiteralNode props |
props.flowsTo(def.getProps()) and
props.hasPropertyWrite("dangerouslySetInnerHTML", danger)
)
|
valueSrc.flowsTo(danger) and
valueSrc.hasPropertyWrite("__html", this)
)
}
}
/**
* A React tooltip where the `data-html` attribute is set to `true`.
*/
class TooltipSink extends Sink {
TooltipSink() {
exists(JsxElement el |
el.getAttributeByName("data-html").getStringValue() = "true" or
el.getAttributeByName("data-html").getValue().mayHaveBooleanValue(true)
|
this = el.getAttributeByName("data-tip").getValue().flow()
)
}
}
/**
* The HTML body of an email, viewed as an XSS sink.
*/
class EmailHtmlBodySink extends Sink {
EmailHtmlBodySink() { this = any(EmailSender sender).getHtmlBody() }
override string getVulnerabilityKind() { result = "HTML injection" }
}
/**
* A write to the `template` option of a Vue instance, viewed as an XSS sink.
*/
class VueTemplateSink extends Sink {
VueTemplateSink() {
// Note: don't use Vue::Component#getTemplate as it includes an unwanted getALocalSource() step
this = any(Vue::Component c).getOption("template")
}
}
/**
* The tag name argument to the `createElement` parameter of the
* `render` method of a Vue instance, viewed as an XSS sink.
*/
class VueCreateElementSink extends Sink {
VueCreateElementSink() {
exists(Vue::Component c, DataFlow::FunctionNode f |
f.flowsTo(c.getRender()) and
this = f.getParameter(0).getACall().getArgument(0)
)
}
}
/**
* A Vue `v-html` attribute, viewed as an XSS sink.
*/
class VHtmlSink extends Vue::VHtmlAttribute, Sink { }
/**
* A raw interpolation tag in a template file, viewed as an XSS sink.
*/
class TemplateSink extends Sink {
TemplateSink() {
exists(Templating::TemplatePlaceholderTag tag |
tag.isRawInterpolation() and
this = tag.asDataFlowNode()
)
}
}
/**
* A value being piped into the `safe` pipe in a template file,
* disabling subsequent HTML escaping.
*/
class SafePipe extends Sink {
SafePipe() { this = Templating::getAPipeCall("safe").getArgument(0) }
}
/**
* A property read from a safe property is considered a sanitizer.
*/
class SafePropertyReadSanitizer extends Sanitizer, DataFlow::Node {
SafePropertyReadSanitizer() {
exists(PropAccess pacc | pacc = this.asExpr() | pacc.getPropertyName() = "length")
}
}
/**
* A regexp replacement involving an HTML meta-character, viewed as a sanitizer for
* XSS vulnerabilities.
*
* The XSS queries do not attempt to reason about correctness or completeness of sanitizers,
* so any such replacement stops taint propagation.
*/
private class MetacharEscapeSanitizer extends Sanitizer, Shared::MetacharEscapeSanitizer { }
private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { }
private class SerializeJavascriptSanitizer extends Sanitizer, Shared::SerializeJavascriptSanitizer {
}
private class IsEscapedInSwitchSanitizer extends Sanitizer, Shared::IsEscapedInSwitchSanitizer { }
private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { }
/**
* Holds if there exists two dataflow edges to `succ`, where one edges is sanitized, and the other edge starts with `pred`.
*/
predicate isOptionallySanitizedEdge(DataFlow::Node pred, DataFlow::Node succ) {
exists(HtmlSanitizerCall sanitizer |
// sanitized = sanitize ? sanitizer(source) : source;
exists(ConditionalExpr branch, Variable var, VarAccess access |
branch = succ.asExpr() and access = var.getAnAccess()
|
branch.getABranch() = access and
pred.getEnclosingExpr() = access and
sanitizer = branch.getABranch().flow() and
sanitizer.getAnArgument().getEnclosingExpr() = var.getAnAccess()
)
or
// sanitized = source; if (sanitize) {sanitized = sanitizer(source)};
exists(SsaPhiNode phi, SsaExplicitDefinition a, SsaDefinition b |
a = phi.getAnInput().getDefinition() and
b = phi.getAnInput().getDefinition() and
count(phi.getAnInput()) = 2 and
not a = b and
sanitizer = DataFlow::valueNode(a.getDef().getSource()) and
sanitizer.getAnArgument().asExpr().(VarAccess).getVariable() = b.getSourceVariable()
|
pred = DataFlow::ssaDefinitionNode(b) and
succ = DataFlow::ssaDefinitionNode(phi)
)
)
}
private class ContainsHtmlGuard extends SanitizerGuard, Shared::ContainsHtmlGuard { }
/** A source of remote user input, considered as a flow source for DOM-based XSS. */
class RemoteFlowSourceAsSource extends Source {

View File

@@ -6,7 +6,7 @@
import javascript
private import semmle.javascript.dataflow.InferredTypes
import semmle.javascript.security.dataflow.Xss
import semmle.javascript.security.dataflow.DomBasedXssCustomizations
module UnsafeJQueryPlugin {
private import DataFlow::FlowLabel

View File

@@ -4,7 +4,7 @@
*/
import javascript
import semmle.javascript.security.dataflow.Xss
import semmle.javascript.security.dataflow.DomBasedXssCustomizations
import UnsafeJQueryPluginCustomizations::UnsafeJQueryPlugin
/**

View File

@@ -3,7 +3,7 @@
*/
import javascript
private import semmle.javascript.dataflow.InferredTypes
private import semmle.javascript.dataflow.InferredTypes // TODO: Try to remove.
/** Provides classes and predicates shared between the XSS queries. */
module Shared {
@@ -146,319 +146,12 @@ module Shared {
}
}
/** Provides classes and predicates for the DOM-based XSS query. */
module DomBasedXss {
/** A data flow source for DOM-based XSS vulnerabilities. */
abstract class Source extends Shared::Source { }
/** A data flow sink for DOM-based XSS vulnerabilities. */
abstract class Sink extends Shared::Sink { }
/** A sanitizer for DOM-based XSS vulnerabilities. */
abstract class Sanitizer extends Shared::Sanitizer { }
/** A sanitizer guard for DOM-based XSS vulnerabilities. */
abstract class SanitizerGuard extends Shared::SanitizerGuard { }
/**
* An expression whose value is interpreted as HTML
* and may be inserted into the DOM through a library.
*/
class LibrarySink extends Sink {
LibrarySink() {
// call to a jQuery method that interprets its argument as HTML
exists(JQuery::MethodCall call |
call.interpretsArgumentAsHtml(this) and
not call.interpretsArgumentAsSelector(this) // Handled by `JQuerySelectorSink`
)
or
// call to an Angular method that interprets its argument as HTML
any(AngularJS::AngularJSCall call).interpretsArgumentAsHtml(this.asExpr())
or
// call to a WinJS function that interprets its argument as HTML
exists(DataFlow::MethodCallNode mcn, string m |
m = "setInnerHTMLUnsafe" or m = "setOuterHTMLUnsafe"
|
mcn.getMethodName() = m and
this = mcn.getArgument(1)
)
or
this = any(Typeahead::TypeaheadSuggestionFunction f).getAReturn()
or
this = any(Handlebars::SafeString s).getAnArgument()
or
this = any(JQuery::MethodCall call | call.getMethodName() = "jGrowl").getArgument(0)
or
// A construction of a JSDOM object (server side DOM), where scripts are allowed.
exists(DataFlow::NewNode instance |
instance = API::moduleImport("jsdom").getMember("JSDOM").getInstance().getAnImmediateUse() and
this = instance.getArgument(0) and
instance.getOptionArgument(1, "runScripts").mayHaveStringValue("dangerously")
)
or
MooTools::interpretsNodeAsHtml(this)
}
}
/**
* Holds if `prefix` is a prefix of `htmlString`, which may be intepreted as
* HTML by a jQuery method.
*/
predicate isPrefixOfJQueryHtmlString(DataFlow::Node htmlString, DataFlow::Node prefix) {
prefix = getAPrefixOfJQuerySelectorString(htmlString)
}
/**
* Holds if `prefix` is a prefix of `htmlString`, which may be intepreted as
* HTML by a jQuery method.
*/
private DataFlow::Node getAPrefixOfJQuerySelectorString(DataFlow::Node htmlString) {
any(JQuery::MethodCall call).interpretsArgumentAsSelector(htmlString) and
result = htmlString
or
exists(DataFlow::Node pred | pred = getAPrefixOfJQuerySelectorString(htmlString) |
result = StringConcatenation::getFirstOperand(pred)
or
result = pred.getAPredecessor()
)
}
/**
* An argument to the jQuery `$` function or similar, which is interpreted as either a selector
* or as an HTML string depending on its first character.
*/
class JQueryHtmlOrSelectorArgument extends DataFlow::Node {
JQueryHtmlOrSelectorArgument() {
exists(JQuery::MethodCall call |
call.interpretsArgumentAsHtml(this) and
call.interpretsArgumentAsSelector(this) and
pragma[only_bind_out](this.analyze()).getAType() = TTString()
)
}
/** Gets a string that flows to the prefix of this argument. */
string getAPrefix() { result = getAPrefixOfJQuerySelectorString(this).getStringValue() }
}
/**
* An argument to the jQuery `$` function or similar, which may be interpreted as HTML.
*
* This is the same as `JQueryHtmlOrSelectorArgument`, excluding cases where the value
* is prefixed by something other than `<`.
*/
class JQueryHtmlOrSelectorSink extends Sink, JQueryHtmlOrSelectorArgument {
JQueryHtmlOrSelectorSink() {
// If a prefix of the string is known, it must start with '<' or be an empty string
forall(string strval | strval = this.getAPrefix() | strval.regexpMatch("(?s)\\s*<.*|"))
}
}
import ClientSideUrlRedirectCustomizations::ClientSideUrlRedirect as ClientSideUrlRedirect
/**
* A write to a URL which may execute JavaScript code.
*/
class WriteURLSink extends Sink instanceof ClientSideUrlRedirect::Sink {
WriteURLSink() { super.isXssSink() }
}
/**
* An expression whose value is interpreted as HTML or CSS
* and may be inserted into the DOM.
*/
class DomSink extends Sink {
DomSink() {
// Call to a DOM function that inserts its argument into the DOM
any(DomMethodCallExpr call).interpretsArgumentsAsHtml(this.asExpr())
or
// Assignment to a dangerous DOM property
exists(DomPropWriteNode pw |
pw.interpretsValueAsHtml() and
this = DataFlow::valueNode(pw.getRhs())
)
or
// `html` or `source.html` properties of React Native `WebView`
exists(ReactNative::WebViewElement webView, DataFlow::SourceNode source |
source = webView or
source = webView.getAPropertyWrite("source").getRhs().getALocalSource()
|
this = source.getAPropertyWrite("html").getRhs()
)
}
}
/**
* An expression whose value is interpreted as HTML.
*/
class HtmlParserSink extends Sink {
HtmlParserSink() {
exists(DataFlow::GlobalVarRefNode domParser |
domParser.getName() = "DOMParser" and
this = domParser.getAnInstantiation().getAMethodCall("parseFromString").getArgument(0)
)
or
exists(DataFlow::MethodCallNode ccf |
isDomValue(ccf.getReceiver().asExpr()) and
ccf.getMethodName() = "createContextualFragment" and
this = ccf.getArgument(0)
)
}
}
/**
* A React `dangerouslySetInnerHTML` attribute, viewed as an XSS sink.
*
* Any write to the `__html` property of an object assigned to this attribute
* is considered an XSS sink.
*/
class DangerouslySetInnerHtmlSink extends Sink, DataFlow::ValueNode {
DangerouslySetInnerHtmlSink() {
exists(DataFlow::Node danger, DataFlow::SourceNode valueSrc |
exists(JsxAttribute attr |
attr.getName() = "dangerouslySetInnerHTML" and
attr.getValue() = danger.asExpr()
)
or
exists(ReactElementDefinition def, DataFlow::ObjectLiteralNode props |
props.flowsTo(def.getProps()) and
props.hasPropertyWrite("dangerouslySetInnerHTML", danger)
)
|
valueSrc.flowsTo(danger) and
valueSrc.hasPropertyWrite("__html", this)
)
}
}
/**
* A React tooltip where the `data-html` attribute is set to `true`.
*/
class TooltipSink extends Sink {
TooltipSink() {
exists(JsxElement el |
el.getAttributeByName("data-html").getStringValue() = "true" or
el.getAttributeByName("data-html").getValue().mayHaveBooleanValue(true)
|
this = el.getAttributeByName("data-tip").getValue().flow()
)
}
}
/**
* The HTML body of an email, viewed as an XSS sink.
*/
class EmailHtmlBodySink extends Sink {
EmailHtmlBodySink() { this = any(EmailSender sender).getHtmlBody() }
override string getVulnerabilityKind() { result = "HTML injection" }
}
/**
* A write to the `template` option of a Vue instance, viewed as an XSS sink.
*/
class VueTemplateSink extends Sink {
VueTemplateSink() {
// Note: don't use Vue::Component#getTemplate as it includes an unwanted getALocalSource() step
this = any(Vue::Component c).getOption("template")
}
}
/**
* The tag name argument to the `createElement` parameter of the
* `render` method of a Vue instance, viewed as an XSS sink.
*/
class VueCreateElementSink extends Sink {
VueCreateElementSink() {
exists(Vue::Component c, DataFlow::FunctionNode f |
f.flowsTo(c.getRender()) and
this = f.getParameter(0).getACall().getArgument(0)
)
}
}
/**
* A Vue `v-html` attribute, viewed as an XSS sink.
*/
class VHtmlSink extends Vue::VHtmlAttribute, Sink { }
/**
* A raw interpolation tag in a template file, viewed as an XSS sink.
*/
class TemplateSink extends Sink {
TemplateSink() {
exists(Templating::TemplatePlaceholderTag tag |
tag.isRawInterpolation() and
this = tag.asDataFlowNode()
)
}
}
/**
* A value being piped into the `safe` pipe in a template file,
* disabling subsequent HTML escaping.
*/
class SafePipe extends Sink {
SafePipe() { this = Templating::getAPipeCall("safe").getArgument(0) }
}
/**
* A property read from a safe property is considered a sanitizer.
*/
class SafePropertyReadSanitizer extends Sanitizer, DataFlow::Node {
SafePropertyReadSanitizer() {
exists(PropAccess pacc | pacc = this.asExpr() | pacc.getPropertyName() = "length")
}
}
/**
* A regexp replacement involving an HTML meta-character, viewed as a sanitizer for
* XSS vulnerabilities.
*
* The XSS queries do not attempt to reason about correctness or completeness of sanitizers,
* so any such replacement stops taint propagation.
*/
private class MetacharEscapeSanitizer extends Sanitizer, Shared::MetacharEscapeSanitizer { }
private class UriEncodingSanitizer extends Sanitizer, Shared::UriEncodingSanitizer { }
private class SerializeJavascriptSanitizer extends Sanitizer, Shared::SerializeJavascriptSanitizer {
}
private class IsEscapedInSwitchSanitizer extends Sanitizer, Shared::IsEscapedInSwitchSanitizer { }
private class QuoteGuard extends SanitizerGuard, Shared::QuoteGuard { }
/**
* Holds if there exists two dataflow edges to `succ`, where one edges is sanitized, and the other edge starts with `pred`.
*/
predicate isOptionallySanitizedEdge(DataFlow::Node pred, DataFlow::Node succ) {
exists(HtmlSanitizerCall sanitizer |
// sanitized = sanitize ? sanitizer(source) : source;
exists(ConditionalExpr branch, Variable var, VarAccess access |
branch = succ.asExpr() and access = var.getAnAccess()
|
branch.getABranch() = access and
pred.getEnclosingExpr() = access and
sanitizer = branch.getABranch().flow() and
sanitizer.getAnArgument().getEnclosingExpr() = var.getAnAccess()
)
or
// sanitized = source; if (sanitize) {sanitized = sanitizer(source)};
exists(SsaPhiNode phi, SsaExplicitDefinition a, SsaDefinition b |
a = phi.getAnInput().getDefinition() and
b = phi.getAnInput().getDefinition() and
count(phi.getAnInput()) = 2 and
not a = b and
sanitizer = DataFlow::valueNode(a.getDef().getSource()) and
sanitizer.getAnArgument().asExpr().(VarAccess).getVariable() = b.getSourceVariable()
|
pred = DataFlow::ssaDefinitionNode(b) and
succ = DataFlow::ssaDefinitionNode(phi)
)
)
}
private class ContainsHtmlGuard extends SanitizerGuard, Shared::ContainsHtmlGuard { }
/**
* DEPRECATED: Use the `DomBasedXssCustomizations.qll` file instead.
* Provides classes and predicates for the DOM-based XSS query.
*/
deprecated module DomBasedXss {
import DomBasedXssCustomizations::DomBasedXss
}
/** Provides classes and predicates for the reflected XSS query. */

View File

@@ -11,7 +11,7 @@ import javascript
module XssThroughDom {
import Xss::XssThroughDom
private import semmle.javascript.dataflow.InferredTypes
private import semmle.javascript.security.dataflow.Xss::DomBasedXss as DomBasedXss
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
/**
* Gets an attribute name that could store user-controlled data.

View File

@@ -7,7 +7,7 @@ import javascript
private import semmle.javascript.dataflow.InferredTypes
import Xss::XssThroughDom
private import XssThroughDomCustomizations::XssThroughDom
private import semmle.javascript.security.dataflow.Xss::DomBasedXss as DomBasedXss
private import semmle.javascript.security.dataflow.DomBasedXssCustomizations
private import semmle.javascript.security.dataflow.UnsafeJQueryPluginCustomizations::UnsafeJQueryPlugin as UnsafeJQuery
/**