Merge pull request #13719 from asgerf/js/barrier-inout

JS: Replace barrier edges with barrier nodes
This commit is contained in:
Asger F 2023-07-13 16:36:52 +02:00 коммит произвёл GitHub
Родитель cafc67e3be c7abd4c2af
Коммит d57276ca35
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
29 изменённых файлов: 216 добавлений и 107 удалений

Просмотреть файл

@ -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 |