зеркало из https://github.com/github/codeql.git
Merge pull request #13719 from asgerf/js/barrier-inout
JS: Replace barrier edges with barrier nodes
This commit is contained in:
Коммит
d57276ca35
|
@ -23,7 +23,8 @@ class DomBasedXssAtmConfig extends AtmConfig {
|
|||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof DomBasedXss::Sanitizer
|
||||
node instanceof DomBasedXss::Sanitizer or
|
||||
DomBasedXss::isOptionallySanitizedNode(node)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
|
@ -31,10 +32,6 @@ class DomBasedXssAtmConfig extends AtmConfig {
|
|||
guard instanceof QuoteGuard or
|
||||
guard instanceof ContainsHtmlGuard
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
DomBasedXss::isOptionallySanitizedEdge(pred, succ)
|
||||
}
|
||||
}
|
||||
|
||||
private import semmle.javascript.security.dataflow.Xss::Shared as Shared
|
||||
|
|
|
@ -23,7 +23,8 @@ class XssThroughDomAtmConfig extends AtmConfig {
|
|||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof DomBasedXss::Sanitizer
|
||||
node instanceof DomBasedXss::Sanitizer or
|
||||
DomBasedXss::isOptionallySanitizedNode(node)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
|
@ -34,10 +35,6 @@ class XssThroughDomAtmConfig extends AtmConfig {
|
|||
guard instanceof QuoteGuard or
|
||||
guard instanceof ContainsHtmlGuard
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
DomBasedXss::isOptionallySanitizedEdge(pred, succ)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -166,6 +166,26 @@ abstract class Configuration extends string {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if flow into `node` is prohibited.
|
||||
*/
|
||||
predicate isBarrierIn(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow out `node` is prohibited.
|
||||
*/
|
||||
predicate isBarrierOut(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow into `node` is prohibited for the flow label `lbl`.
|
||||
*/
|
||||
predicate isBarrierIn(DataFlow::Node node, FlowLabel lbl) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow out `node` is prohibited for the flow label `lbl`.
|
||||
*/
|
||||
predicate isBarrierOut(DataFlow::Node node, FlowLabel lbl) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow from `pred` to `succ` is prohibited.
|
||||
*/
|
||||
|
@ -494,7 +514,7 @@ private BasicBlock getADominatedBasicBlock(BarrierGuardNode guard, ConditionGuar
|
|||
*
|
||||
* Only holds for barriers that should apply to all flow labels.
|
||||
*/
|
||||
private predicate isBarrierEdge(Configuration cfg, DataFlow::Node pred, DataFlow::Node succ) {
|
||||
private predicate isBarrierEdgeRaw(Configuration cfg, DataFlow::Node pred, DataFlow::Node succ) {
|
||||
cfg.isBarrierEdge(pred, succ)
|
||||
or
|
||||
exists(DataFlow::BarrierGuardNode guard |
|
||||
|
@ -503,11 +523,26 @@ private predicate isBarrierEdge(Configuration cfg, DataFlow::Node pred, DataFlow
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a barrier edge `pred -> succ` in `cfg` either through an explicit barrier edge
|
||||
* or one implied by a barrier guard, or by an out/in barrier for `pred` or `succ`, respectively.
|
||||
*
|
||||
* Only holds for barriers that should apply to all flow labels.
|
||||
*/
|
||||
pragma[inline]
|
||||
private predicate isBarrierEdge(Configuration cfg, DataFlow::Node pred, DataFlow::Node succ) {
|
||||
isBarrierEdgeRaw(cfg, pred, succ)
|
||||
or
|
||||
cfg.isBarrierOut(pred)
|
||||
or
|
||||
cfg.isBarrierIn(succ)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a labeled barrier edge `pred -> succ` in `cfg` either through an explicit barrier edge
|
||||
* or one implied by a barrier guard.
|
||||
*/
|
||||
private predicate isLabeledBarrierEdge(
|
||||
private predicate isLabeledBarrierEdgeRaw(
|
||||
Configuration cfg, DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel label
|
||||
) {
|
||||
cfg.isBarrierEdge(pred, succ, label)
|
||||
|
@ -518,6 +553,21 @@ private predicate isLabeledBarrierEdge(
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a labeled barrier edge `pred -> succ` in `cfg` either through an explicit barrier edge
|
||||
* or one implied by a barrier guard, or by an out/in barrier for `pred` or `succ`, respectively.
|
||||
*/
|
||||
pragma[inline]
|
||||
private predicate isLabeledBarrierEdge(
|
||||
Configuration cfg, DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel label
|
||||
) {
|
||||
isLabeledBarrierEdgeRaw(cfg, pred, succ, label)
|
||||
or
|
||||
cfg.isBarrierOut(pred, label)
|
||||
or
|
||||
cfg.isBarrierIn(succ, label)
|
||||
}
|
||||
|
||||
/**
|
||||
* A guard node that only blocks specific labels.
|
||||
*/
|
||||
|
|
|
@ -62,6 +62,26 @@ module TaintTracking {
|
|||
*/
|
||||
predicate isSanitizer(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow into `node` is prohibited.
|
||||
*/
|
||||
predicate isSanitizerIn(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow out `node` is prohibited.
|
||||
*/
|
||||
predicate isSanitizerOut(DataFlow::Node node) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow into `node` is prohibited for the flow label `lbl`.
|
||||
*/
|
||||
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowLabel lbl) { none() }
|
||||
|
||||
/**
|
||||
* Holds if flow out `node` is prohibited for the flow label `lbl`.
|
||||
*/
|
||||
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowLabel lbl) { none() }
|
||||
|
||||
/** Holds if the edge from `pred` to `succ` is a taint sanitizer. */
|
||||
predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) { none() }
|
||||
|
||||
|
@ -108,6 +128,22 @@ module TaintTracking {
|
|||
this.isSanitizerEdge(source, sink) and lbl.isTaint()
|
||||
}
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node) { none() }
|
||||
|
||||
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowLabel lbl) {
|
||||
this.isSanitizerIn(node, lbl)
|
||||
or
|
||||
this.isSanitizerIn(node) and lbl.isTaint()
|
||||
}
|
||||
|
||||
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowLabel lbl) {
|
||||
this.isSanitizerOut(node, lbl)
|
||||
or
|
||||
this.isSanitizerOut(node) and lbl.isTaint()
|
||||
}
|
||||
|
||||
final override predicate isBarrierGuard(DataFlow::BarrierGuardNode guard) {
|
||||
super.isBarrierGuard(guard) or
|
||||
guard.(AdditionalSanitizerGuardNode).appliesTo(this) or
|
||||
|
|
|
@ -27,10 +27,6 @@ class Configuration extends TaintTracking::Configuration {
|
|||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof CleartextLogging::Barrier }
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
CleartextLogging::isSanitizerEdge(pred, succ)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node trg) {
|
||||
CleartextLogging::isAdditionalTaintStep(src, trg)
|
||||
}
|
||||
|
|
|
@ -175,12 +175,24 @@ module CleartextLogging {
|
|||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use `Barrier` instead, sanitized have been replaced by sanitized nodes.
|
||||
*
|
||||
* Holds if the edge `pred` -> `succ` should be sanitized for clear-text logging of sensitive information.
|
||||
*/
|
||||
predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
deprecated predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
succ.(DataFlow::PropRead).getBase() = pred
|
||||
}
|
||||
|
||||
private class PropReadAsBarrier extends Barrier {
|
||||
PropReadAsBarrier() {
|
||||
this = any(DataFlow::PropRead read).getBase() and
|
||||
// the 'foo' in 'foo.bar()' may have flow, we only want to suppress plain property reads
|
||||
not this = any(DataFlow::MethodCallNode call).getReceiver() and
|
||||
// do not block custom taint steps from this node
|
||||
not isAdditionalTaintStep(this, _)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the edge `src` -> `trg` is an additional taint-step for clear-text logging of sensitive information.
|
||||
*/
|
||||
|
|
|
@ -33,10 +33,6 @@ class Configuration extends TaintTracking::Configuration {
|
|||
|
||||
override predicate isSanitizer(DataFlow::Node node) { node instanceof Barrier }
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
CleartextLogging::isSanitizerEdge(pred, succ)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node trg) {
|
||||
CleartextLogging::isAdditionalTaintStep(src, trg)
|
||||
}
|
||||
|
|
|
@ -31,9 +31,7 @@ class Configuration extends TaintTracking::Configuration {
|
|||
node instanceof Sanitizer
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node source, DataFlow::Node sink) {
|
||||
sanitizingPrefixEdge(source, sink)
|
||||
}
|
||||
override predicate isSanitizerOut(DataFlow::Node node) { sanitizingPrefixEdge(node, _) }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
isAdditionalRequestForgeryStep(pred, succ)
|
||||
|
|
|
@ -33,9 +33,7 @@ class Configuration extends TaintTracking::Configuration {
|
|||
node instanceof Sanitizer
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node source, DataFlow::Node sink) {
|
||||
hostnameSanitizingPrefixEdge(source, sink)
|
||||
}
|
||||
override predicate isSanitizerOut(DataFlow::Node node) { hostnameSanitizingPrefixEdge(node, _) }
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel f, DataFlow::FlowLabel g
|
||||
|
|
|
@ -290,9 +290,13 @@ module DomBasedXss {
|
|||
private class HtmlSanitizerAsSanitizer extends Sanitizer instanceof HtmlSanitizerCall { }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use `isOptionallySanitizedNode` instead.
|
||||
*
|
||||
* 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) {
|
||||
deprecated predicate isOptionallySanitizedEdge = isOptionallySanitizedEdgeInternal/2;
|
||||
|
||||
private predicate isOptionallySanitizedEdgeInternal(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(HtmlSanitizerCall sanitizer |
|
||||
// sanitized = sanitize ? sanitizer(source) : source;
|
||||
exists(ConditionalExpr branch, Variable var, VarAccess access |
|
||||
|
@ -319,6 +323,17 @@ module DomBasedXss {
|
|||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node` should be considered optionally sanitized as it occurs in a branch
|
||||
* that controls whether sanitization is enabled.
|
||||
*
|
||||
* For example, in `sanitized = sanitize ? sanitizer(source) : source`, the right-hand `source` expression
|
||||
* is considered an optionally sanitized node.
|
||||
*/
|
||||
predicate isOptionallySanitizedNode(DataFlow::Node node) {
|
||||
isOptionallySanitizedEdgeInternal(_, node)
|
||||
}
|
||||
|
||||
/** A source of remote user input, considered as a flow source for DOM-based XSS. */
|
||||
class RemoteFlowSourceAsSource extends Source instanceof RemoteFlowSource { }
|
||||
|
||||
|
|
|
@ -86,13 +86,9 @@ class Configuration extends TaintTracking::Configuration {
|
|||
// we assume that `.join()` calls have a prefix, and thus block the prefix label.
|
||||
node = any(DataFlow::MethodCallNode call | call.getMethodName() = "join") and
|
||||
lbl = prefixLabel()
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(
|
||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel label
|
||||
) {
|
||||
isOptionallySanitizedEdge(pred, succ) and
|
||||
label = [DataFlow::FlowLabel::taint(), prefixLabel(), TaintedUrlSuffix::label()]
|
||||
or
|
||||
isOptionallySanitizedNode(node) and
|
||||
lbl = [DataFlow::FlowLabel::taint(), prefixLabel(), TaintedUrlSuffix::label()]
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
|
|
|
@ -46,15 +46,11 @@ class Configuration extends TaintTracking::Configuration {
|
|||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
override predicate isSanitizerIn(DataFlow::Node node) {
|
||||
// Block flow from the location to its properties, as the relevant properties (hash and search) are taint sources of their own.
|
||||
// The location source is only used for propagating through API calls like `new URL(location)` and into external APIs where
|
||||
// the whole location object escapes.
|
||||
exists(DataFlow::PropRead read |
|
||||
read = DOM::locationRef().getAPropertyRead() and
|
||||
pred = read.getBase() and
|
||||
succ = read
|
||||
)
|
||||
node = DOM::locationRef().getAPropertyRead()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,11 +27,9 @@ class Configuration extends TaintTracking::Configuration {
|
|||
node instanceof Sanitizer
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
// stop propagation at the sinks to avoid double reporting
|
||||
pred instanceof Sink and
|
||||
// constrain succ
|
||||
pred = succ.getAPredecessor()
|
||||
this.isSink(node)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
|
|
|
@ -55,20 +55,11 @@ class Configuration extends TaintTracking::Configuration {
|
|||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(
|
||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel lbl
|
||||
) {
|
||||
override predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowLabel lbl) {
|
||||
// Suppress the value-preserving step src -> dst in `extend(dst, src)`. This is modeled as a value-preserving
|
||||
// step because it preserves all properties, but the destination is not actually Object.prototype.
|
||||
exists(ExtendCall call |
|
||||
pred = call.getASourceOperand() and
|
||||
(
|
||||
succ = call.getDestinationOperand().getALocalSource()
|
||||
or
|
||||
succ = call
|
||||
) and
|
||||
lbl instanceof ObjectPrototype
|
||||
)
|
||||
node = any(ExtendCall call).getASourceOperand() and
|
||||
lbl instanceof ObjectPrototype
|
||||
}
|
||||
|
||||
override predicate isAdditionalFlowStep(
|
||||
|
|
|
@ -26,9 +26,7 @@ class Configuration extends TaintTracking::Configuration {
|
|||
node instanceof Sanitizer
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node source, DataFlow::Node sink) {
|
||||
sanitizingPrefixEdge(source, sink)
|
||||
}
|
||||
override predicate isSanitizerOut(DataFlow::Node node) { sanitizingPrefixEdge(node, _) }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
isAdditionalRequestForgeryStep(pred, succ)
|
||||
|
|
|
@ -22,7 +22,8 @@ class Configuration extends TaintTracking::Configuration {
|
|||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof Sanitizer
|
||||
node instanceof Sanitizer or
|
||||
node = any(DataFlow::PropRead read | read.getPropertyName() = "length")
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node src, DataFlow::Node dst) {
|
||||
|
@ -32,10 +33,6 @@ class Configuration extends TaintTracking::Configuration {
|
|||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
guard instanceof UpperBoundsCheckSanitizerGuard
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
succ.(DataFlow::PropRead).accesses(pred, "length")
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if data is converted to a number from `src` to `dst`. */
|
||||
|
|
|
@ -27,9 +27,7 @@ class Configuration extends TaintTracking::Configuration {
|
|||
node instanceof Sanitizer
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node source, DataFlow::Node sink) {
|
||||
hostnameSanitizingPrefixEdge(source, sink)
|
||||
}
|
||||
override predicate isSanitizerOut(DataFlow::Node node) { hostnameSanitizingPrefixEdge(node, _) }
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
guard instanceof LocalUrlSanitizingGuard or
|
||||
|
|
|
@ -31,10 +31,8 @@ class Configration extends TaintTracking::Configuration {
|
|||
node instanceof DomBasedXss::Sanitizer
|
||||
or
|
||||
node instanceof UnsafeJQueryPlugin::Sanitizer
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
DomBasedXss::isOptionallySanitizedEdge(pred, succ)
|
||||
or
|
||||
DomBasedXss::isOptionallySanitizedNode(node)
|
||||
}
|
||||
|
||||
// override to require that there is a path without unmatched return steps
|
||||
|
|
|
@ -31,16 +31,13 @@ class Configuration extends TaintTracking::Configuration {
|
|||
aliasPropertyPresenceStep(src, sink)
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
// prefixing prevents forced html/css confusion:
|
||||
// prefixing through concatenation:
|
||||
StringConcatenation::taintStep(pred, succ, _, any(int i | i >= 1))
|
||||
StringConcatenation::taintStep(node, _, _, any(int i | i >= 1))
|
||||
or
|
||||
// prefixing through a poor-mans templating system:
|
||||
exists(StringReplaceCall replace |
|
||||
replace = succ and
|
||||
pred = replace.getRawReplacement()
|
||||
)
|
||||
node = any(StringReplaceCall call).getRawReplacement()
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode node) {
|
||||
|
|
|
@ -34,11 +34,24 @@ module UnvalidatedDynamicMethodCall {
|
|||
|
||||
/**
|
||||
* A sanitizer for unvalidated dynamic method calls.
|
||||
* Override the `sanitizes` predicate to specify an edge that should be sanitized.
|
||||
* The `this` value is not seen as a sanitizer.
|
||||
*/
|
||||
abstract class Sanitizer extends DataFlow::Node {
|
||||
abstract predicate sanitizes(DataFlow::Node source, DataFlow::Node sink, DataFlow::FlowLabel lbl);
|
||||
/**
|
||||
* Gets the flow label blocked by this sanitizer.
|
||||
*/
|
||||
DataFlow::FlowLabel getFlowLabel() { result.isTaint() }
|
||||
|
||||
/**
|
||||
* DEPRECATED. Use sanitizer nodes instead.
|
||||
*
|
||||
* This predicate no longer has any effect. The `this` value of `Sanitizer` is instead
|
||||
* treated as a sanitizing node, that is, flow in and out of that node is prohibited.
|
||||
*/
|
||||
deprecated predicate sanitizes(
|
||||
DataFlow::Node source, DataFlow::Node sink, DataFlow::FlowLabel lbl
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,10 +38,10 @@ class Configuration extends TaintTracking::Configuration {
|
|||
sink.(Sink).getFlowLabel() = label
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(
|
||||
DataFlow::Node pred, DataFlow::Node succ, DataFlow::FlowLabel lbl
|
||||
) {
|
||||
any(Sanitizer s).sanitizes(pred, succ, lbl)
|
||||
override predicate isLabeledBarrier(DataFlow::Node node, DataFlow::FlowLabel label) {
|
||||
super.isLabeledBarrier(node, label)
|
||||
or
|
||||
node.(Sanitizer).getFlowLabel() = label
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
|
|
|
@ -20,7 +20,8 @@ class Configuration extends TaintTracking::Configuration {
|
|||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
super.isSanitizer(node) or
|
||||
node instanceof DomBasedXss::Sanitizer
|
||||
node instanceof DomBasedXss::Sanitizer or
|
||||
DomBasedXss::isOptionallySanitizedNode(node)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) {
|
||||
|
@ -32,10 +33,6 @@ class Configuration extends TaintTracking::Configuration {
|
|||
guard instanceof ContainsHtmlGuard
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
DomBasedXss::isOptionallySanitizedEdge(pred, succ)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
succ = DataFlow::globalVarRef("URL").getAMemberCall("createObjectURL") and
|
||||
pred = succ.(DataFlow::InvokeNode).getArgument(0)
|
||||
|
|
|
@ -29,8 +29,8 @@ class Configuration extends TaintTracking::Configuration {
|
|||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node source, DataFlow::Node sink) {
|
||||
this.strictSanitizingPrefixEdge(source, sink)
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
this.strictSanitizingPrefixEdge(node, _)
|
||||
}
|
||||
|
||||
override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode nd) {
|
||||
|
|
|
@ -22,10 +22,7 @@ class TestDataFlowConfiguration extends DataFlow::Configuration {
|
|||
f.getName().matches("%noReturnTracking%") and
|
||||
node = f.getAReturnedExpr().flow()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node snk) {
|
||||
src = src and
|
||||
snk.asExpr().(PropAccess).getPropertyName() = "notTracked"
|
||||
or
|
||||
node.asExpr().(PropAccess).getPropertyName() = "notTracked"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,11 +61,8 @@ class TestTaintTrackingConfiguration extends TaintTracking::Configuration {
|
|||
f.getName().matches("%noReturnTracking%") and
|
||||
node = f.getAReturnedExpr().flow()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSanitizerEdge(DataFlow::Node src, DataFlow::Node snk) {
|
||||
src = src and
|
||||
snk.asExpr().(PropAccess).getPropertyName() = "notTracked"
|
||||
or
|
||||
node.asExpr().(PropAccess).getPropertyName() = "notTracked"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,11 +96,8 @@ class GermanFlowConfig extends DataFlow::Configuration {
|
|||
f.getName().matches("%noReturnTracking%") and
|
||||
node = f.getAReturnedExpr().flow()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node snk) {
|
||||
src = src and
|
||||
snk.asExpr().(PropAccess).getPropertyName() = "notTracked"
|
||||
or
|
||||
node.asExpr().(PropAccess).getPropertyName() = "notTracked"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
import javascript
|
||||
|
||||
DataFlow::Node sourceVariable() { result.asExpr().(VarRef).getName() = "sourceVariable" }
|
||||
|
||||
StringOps::ConcatenationRoot sinkConcatenation() {
|
||||
result.getConstantStringParts().matches("<sink>%</sink>")
|
||||
}
|
||||
|
||||
class ExampleConfiguration extends TaintTracking::Configuration {
|
||||
ExampleConfiguration() { this = "ExampleConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr().(CallExpr).getCalleeName() = "SOURCE"
|
||||
or
|
||||
source = sourceVariable()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
|
@ -12,8 +20,14 @@ class ExampleConfiguration extends TaintTracking::Configuration {
|
|||
callExpr.getCalleeName() = "SINK" and
|
||||
DataFlow::valueNode(callExpr.getArgument(0)) = sink
|
||||
)
|
||||
or
|
||||
sink = sinkConcatenation()
|
||||
}
|
||||
|
||||
override predicate isSanitizerIn(DataFlow::Node node) { node = sourceVariable() }
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) { node = sinkConcatenation() }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
exists(CallExpr callExpr |
|
||||
callExpr.getCalleeName() = "SANITIZE" and
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import 'dummy';
|
||||
|
||||
function barrierIn() {
|
||||
var sourceVariable = 123;
|
||||
SINK(sourceVariable); // NOT OK
|
||||
|
||||
flowWithSourceParam(sourceVariable);
|
||||
}
|
||||
|
||||
function barrierInParameter(sourceVariable) {
|
||||
SINK(sourceVariable); // NOT OK, but only report the parameter as the source
|
||||
}
|
||||
|
||||
function barrierOut() {
|
||||
let taint = SOURCE();
|
||||
taint = "<sink>" + taint + "</sink>"; // NOT OK
|
||||
taint = "<sink>" + taint + "</sink>"; // OK - only report first instance
|
||||
}
|
|
@ -133,6 +133,9 @@ sanitizingGuard
|
|||
| tst.js:399:16:399:41 | o.hasOw ... "p.q"]) | tst.js:399:33:399:40 | v["p.q"] | true |
|
||||
| tst.js:401:16:401:34 | Object.hasOwn(o, v) | tst.js:401:33:401:33 | v | true |
|
||||
taintedSink
|
||||
| sanitizer-in-out.js:5:10:5:23 | sourceVariable | sanitizer-in-out.js:5:10:5:23 | sourceVariable |
|
||||
| sanitizer-in-out.js:11:10:11:23 | sourceVariable | sanitizer-in-out.js:11:10:11:23 | sourceVariable |
|
||||
| sanitizer-in-out.js:15:17:15:24 | SOURCE() | sanitizer-in-out.js:16:13:16:40 | "<sink> ... /sink>" |
|
||||
| tst.js:2:13:2:20 | SOURCE() | tst.js:3:10:3:10 | v |
|
||||
| tst.js:2:13:2:20 | SOURCE() | tst.js:8:14:8:14 | v |
|
||||
| tst.js:2:13:2:20 | SOURCE() | tst.js:12:14:12:14 | v |
|
||||
|
|
|
@ -9,12 +9,15 @@ nodes
|
|||
| build-leaks.js:14:18:14:20 | env |
|
||||
| build-leaks.js:15:24:15:34 | process.env |
|
||||
| build-leaks.js:15:24:15:34 | process.env |
|
||||
| build-leaks.js:15:24:15:39 | process.env[key] |
|
||||
| build-leaks.js:16:20:16:22 | env |
|
||||
| build-leaks.js:21:11:26:5 | stringifed |
|
||||
| build-leaks.js:21:24:26:5 | {\\n ... )\\n } |
|
||||
| build-leaks.js:22:24:25:14 | Object. ... }, {}) |
|
||||
| build-leaks.js:22:49:22:51 | env |
|
||||
| build-leaks.js:23:24:23:47 | JSON.st ... w[key]) |
|
||||
| build-leaks.js:23:39:23:41 | raw |
|
||||
| build-leaks.js:23:39:23:46 | raw[key] |
|
||||
| build-leaks.js:24:20:24:22 | env |
|
||||
| build-leaks.js:30:22:30:31 | stringifed |
|
||||
| build-leaks.js:34:26:34:57 | getEnv( ... ngified |
|
||||
|
@ -36,13 +39,19 @@ edges
|
|||
| build-leaks.js:14:18:14:20 | env | build-leaks.js:16:20:16:22 | env |
|
||||
| build-leaks.js:15:24:15:34 | process.env | build-leaks.js:14:18:14:20 | env |
|
||||
| build-leaks.js:15:24:15:34 | process.env | build-leaks.js:14:18:14:20 | env |
|
||||
| build-leaks.js:15:24:15:34 | process.env | build-leaks.js:15:24:15:39 | process.env[key] |
|
||||
| build-leaks.js:15:24:15:34 | process.env | build-leaks.js:15:24:15:39 | process.env[key] |
|
||||
| build-leaks.js:15:24:15:39 | process.env[key] | build-leaks.js:14:18:14:20 | env |
|
||||
| build-leaks.js:16:20:16:22 | env | build-leaks.js:13:17:19:10 | Object. ... }) |
|
||||
| build-leaks.js:16:20:16:22 | env | build-leaks.js:14:18:14:20 | env |
|
||||
| build-leaks.js:21:11:26:5 | stringifed | build-leaks.js:30:22:30:31 | stringifed |
|
||||
| build-leaks.js:21:24:26:5 | {\\n ... )\\n } | build-leaks.js:21:11:26:5 | stringifed |
|
||||
| build-leaks.js:22:24:25:14 | Object. ... }, {}) | build-leaks.js:21:24:26:5 | {\\n ... )\\n } |
|
||||
| build-leaks.js:22:49:22:51 | env | build-leaks.js:24:20:24:22 | env |
|
||||
| build-leaks.js:23:24:23:47 | JSON.st ... w[key]) | build-leaks.js:22:49:22:51 | env |
|
||||
| build-leaks.js:23:39:23:41 | raw | build-leaks.js:22:49:22:51 | env |
|
||||
| build-leaks.js:23:39:23:41 | raw | build-leaks.js:23:39:23:46 | raw[key] |
|
||||
| build-leaks.js:23:39:23:46 | raw[key] | build-leaks.js:23:24:23:47 | JSON.st ... w[key]) |
|
||||
| build-leaks.js:24:20:24:22 | env | build-leaks.js:22:24:25:14 | Object. ... }, {}) |
|
||||
| build-leaks.js:24:20:24:22 | env | build-leaks.js:22:49:22:51 | env |
|
||||
| build-leaks.js:30:22:30:31 | stringifed | build-leaks.js:34:26:34:57 | getEnv( ... ngified |
|
||||
|
|
Загрузка…
Ссылка в новой задаче