Merge pull request #18203 from asgerf/jss/document-url

JS: Use TaintedUrlSuffix in ClientSideUrlRedirect
This commit is contained in:
Asger F
2024-12-12 15:47:51 +01:00
committed by GitHub
18 changed files with 486 additions and 235 deletions

View File

@@ -1611,7 +1611,12 @@ class RegExpConstructorInvokeNode extends DataFlow::InvokeNode {
* Gets the AST of the regular expression created here, provided that the
* first argument is a string literal.
*/
RegExpTerm getRoot() { result = this.getArgument(0).asExpr().(StringLiteral).asRegExp() }
RegExpTerm getRoot() {
result = this.getArgument(0).asExpr().(StringLiteral).asRegExp()
or
// In case someone writes `new RegExp(/foo/)` for some reason
result = this.getArgument(0).asExpr().(RegExpLiteral).getRoot()
}
/**
* Gets the flags provided in the second argument, or an empty string if no

View File

@@ -4,114 +4,15 @@
*/
import javascript
private import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate
/**
* Provides a flow label for reasoning about URLs with a tainted query and fragment part,
* which we collectively refer to as the "suffix" of the URL.
*/
module TaintedUrlSuffix {
private import DataFlow
import TaintedUrlSuffixCustomizations::TaintedUrlSuffix
/**
* The flow label representing a URL with a tainted query and fragment part.
*
* Can also be accessed using `TaintedUrlSuffix::label()`.
*/
class TaintedUrlSuffixLabel extends FlowLabel {
TaintedUrlSuffixLabel() { this = "tainted-url-suffix" }
}
/**
* Gets the flow label representing a URL with a tainted query and fragment part.
*/
FlowLabel label() { result instanceof TaintedUrlSuffixLabel }
/** Gets a remote flow source that is a tainted URL query or fragment part from `window.location`. */
ClientSideRemoteFlowSource source() {
result = DOM::locationRef().getAPropertyRead(["search", "hash"])
or
result = DOM::locationSource()
or
result.getKind().isUrl()
}
/**
* Holds if `node` should be a barrier for the given `label`.
*
* This should be used in the `isBarrier` predicate of a configuration that uses the tainted-url-suffix
* label.
*/
predicate isBarrier(Node node, FlowLabel label) {
label = label() and
DataFlowPrivate::optionalBarrier(node, "split-url-suffix")
}
/**
* Holds if there is a flow step `src -> dst` involving the URL suffix taint label.
*
* This handles steps through string operations, promises, URL parsers, and URL accessors.
*/
predicate step(Node src, Node dst, FlowLabel srclbl, FlowLabel dstlbl) {
// Transition from tainted-url-suffix to general taint when entering the second array element
// of a split('#') or split('?') array.
//
// x [tainted-url-suffix] --> x.split('#') [array element 1] [taint]
//
// Technically we should also preverse tainted-url-suffix when entering the first array element of such
// a split, but this mostly leads to FPs since we currently don't track if the taint has been through URI-decoding.
// (The query/fragment parts are often URI-decoded in practice, but not the other URL parts are not)
srclbl = label() and
dstlbl.isTaint() and
DataFlowPrivate::optionalStep(src, "split-url-suffix-post", dst)
or
// Transition from URL suffix to full taint when extracting the query/fragment part.
srclbl = label() and
dstlbl.isTaint() and
(
exists(MethodCallNode call, string name |
src = call.getReceiver() and
dst = call and
name = call.getMethodName()
|
// Substring that is not a prefix
name = StringOps::substringMethodName() and
not call.getArgument(0).getIntValue() = 0
or
// Replace '#' and '?' with nothing
name = "replace" and
call.getArgument(0).getStringValue() = ["#", "?"] and
call.getArgument(1).getStringValue() = ""
or
// The `get` call in `url.searchParams.get(x)` and `url.hashParams.get(x)`
// The step should be safe since nothing else reachable by this flow label supports a method named 'get'.
name = "get"
or
// Methods on URL objects from the Closure library
name = "getDecodedQuery"
or
name = "getFragment"
or
name = "getParameterValue"
or
name = "getParameterValues"
or
name = "getQueryData"
)
or
exists(PropRead read |
src = read.getBase() and
dst = read and
// Unlike the `search` property, the `query` property from `url.parse` does not include the `?`.
read.getPropertyName() = "query"
)
or
// Assume calls to regexp.exec always extract query/fragment parameters.
exists(MethodCallNode call |
call = any(RegExpLiteral re).flow().(DataFlow::SourceNode).getAMethodCall("exec") and
src = call.getArgument(0) and
dst = call
)
)
private class ConcreteTaintedUrlSuffixLabel extends TaintedUrlSuffixLabel {
ConcreteTaintedUrlSuffixLabel() { this = this }
}
}

View File

@@ -0,0 +1,153 @@
/**
* Provides a flow label for reasoning about URLs with a tainted query and fragment part,
* which we collectively refer to as the "suffix" of the URL.
*/
import javascript
private import semmle.javascript.dataflow.internal.DataFlowPrivate as DataFlowPrivate
/**
* Provides a flow label for reasoning about URLs with a tainted query and fragment part,
* which we collectively refer to as the "suffix" of the URL.
*/
module TaintedUrlSuffix {
private import DataFlow
/**
* The flow label representing a URL with a tainted query and fragment part.
*
* Can also be accessed using `TaintedUrlSuffix::label()`.
*/
abstract class TaintedUrlSuffixLabel extends FlowLabel {
TaintedUrlSuffixLabel() { this = "tainted-url-suffix" }
}
/**
* Gets the flow label representing a URL with a tainted query and fragment part.
*/
FlowLabel label() { result instanceof TaintedUrlSuffixLabel }
/** Gets a remote flow source that is a tainted URL query or fragment part from `window.location`. */
ClientSideRemoteFlowSource source() {
result = DOM::locationRef().getAPropertyRead(["search", "hash"])
or
result = DOM::locationSource()
or
result.getKind().isUrl()
}
/**
* Holds if `node` should be a barrier for the given `label`.
*
* This should be used in the `isBarrier` predicate of a configuration that uses the tainted-url-suffix
* label.
*/
predicate isBarrier(Node node, FlowLabel label) {
label = label() and
DataFlowPrivate::optionalBarrier(node, "split-url-suffix")
}
/**
* Holds if there is a flow step `src -> dst` involving the URL suffix taint label.
*
* This handles steps through string operations, promises, URL parsers, and URL accessors.
*/
predicate step(Node src, Node dst, FlowLabel srclbl, FlowLabel dstlbl) {
// Transition from tainted-url-suffix to general taint when entering the second array element
// of a split('#') or split('?') array.
//
// x [tainted-url-suffix] --> x.split('#') [array element 1] [taint]
//
// Technically we should also preverse tainted-url-suffix when entering the first array element of such
// a split, but this mostly leads to FPs since we currently don't track if the taint has been through URI-decoding.
// (The query/fragment parts are often URI-decoded in practice, but not the other URL parts are not)
srclbl = label() and
dstlbl.isTaint() and
DataFlowPrivate::optionalStep(src, "split-url-suffix-post", dst)
or
// Transition from URL suffix to full taint when extracting the query/fragment part.
srclbl = label() and
dstlbl.isTaint() and
(
exists(MethodCallNode call, string name |
src = call.getReceiver() and
dst = call and
name = call.getMethodName()
|
// Substring that is not a prefix
name = StringOps::substringMethodName() and
not call.getArgument(0).getIntValue() = 0
or
// Replace '#' and '?' with nothing
name = "replace" and
call.getArgument(0).getStringValue() = ["#", "?"] and
call.getArgument(1).getStringValue() = ""
or
// The `get` call in `url.searchParams.get(x)` and `url.hashParams.get(x)`
// The step should be safe since nothing else reachable by this flow label supports a method named 'get'.
name = "get"
or
// Methods on URL objects from the Closure library
name = "getDecodedQuery"
or
name = "getFragment"
or
name = "getParameterValue"
or
name = "getParameterValues"
or
name = "getQueryData"
)
or
exists(PropRead read |
src = read.getBase() and
dst = read and
// Unlike the `search` property, the `query` property from `url.parse` does not include the `?`.
read.getPropertyName() = "query"
)
or
exists(MethodCallNode call, DataFlow::RegExpCreationNode re |
(
call = re.getAMethodCall("exec") and
src = call.getArgument(0) and
dst = call
or
call.getMethodName() = ["match", "matchAll"] and
re.flowsTo(call.getArgument(0)) and
src = call.getReceiver() and
dst = call
)
|
captureAfterSuffixIndicator(re.getRoot().getAChild*())
or
// If the regexp is unknown, assume it will extract the URL suffix
not exists(re.getRoot())
)
)
}
/** Holds if the `n`th child of `seq` contains a character indicating that everything thereafter is part of the suffix */
private predicate containsSuffixIndicator(RegExpSequence seq, int n) {
// Also include '=' as it usually only appears in the URL suffix
seq.getChild(n).getAChild*().(RegExpConstant).getValue().regexpMatch(".*[?#=].*")
}
/** Holds if the `n`th child of `seq` contains a capture group. */
private predicate containsCaptureGroup(RegExpSequence seq, int n) {
seq.getChild(n).getAChild*().(RegExpGroup).isCapture()
}
/**
* Holds if `seq` contains a capture group that will likely match path of the URL suffix,
* thereby extracting tainted data.
*
* For example, `/#(.*)/.exec(url)` will extract the tainted URL suffix from `url`.
*/
private predicate captureAfterSuffixIndicator(RegExpSequence seq) {
exists(int suffix, int capture |
containsSuffixIndicator(seq, suffix) and
containsCaptureGroup(seq, capture) and
suffix < capture
)
}
}

View File

@@ -5,6 +5,7 @@
*/
import javascript
private import semmle.javascript.security.TaintedUrlSuffixCustomizations
module ClientSideUrlRedirect {
/**
@@ -31,12 +32,12 @@ module ClientSideUrlRedirect {
abstract class Sanitizer extends DataFlow::Node { }
/**
* DEPRECATED. Replaced by functionality from the `TaintedUrlSuffix` library.
*
* A flow label for values that represent the URL of the current document, and
* hence are only partially user-controlled.
*/
abstract class DocumentUrl extends DataFlow::FlowLabel {
DocumentUrl() { this = "document.url" } // TODO: replace with TaintedUrlSuffix
}
deprecated class DocumentUrl = TaintedUrlSuffix::TaintedUrlSuffixLabel;
/**
* DEPRECATED: Use `ActiveThreatModelSource` from Concepts instead!
@@ -50,8 +51,8 @@ module ClientSideUrlRedirect {
ActiveThreatModelSourceAsSource() { not this.(ClientSideRemoteFlowSource).getKind().isPath() }
override DataFlow::FlowLabel getAFlowLabel() {
if this.(ClientSideRemoteFlowSource).getKind().isUrl()
then result instanceof DocumentUrl
if this = TaintedUrlSuffix::source()
then result = TaintedUrlSuffix::label()
else result.isTaint()
}
}
@@ -60,7 +61,7 @@ module ClientSideUrlRedirect {
* Holds if `node` extracts a part of a URL that does not contain the suffix.
*/
pragma[inline]
predicate isPrefixExtraction(DataFlow::MethodCallNode node) {
deprecated predicate isPrefixExtraction(DataFlow::MethodCallNode node) {
// Block flow through prefix-extraction `substring(0, ...)` and `split("#")[0]`
node.getMethodName() = [StringOps::substringMethodName(), "split"] and
not untrustedUrlSubstring(_, node)
@@ -70,7 +71,7 @@ module ClientSideUrlRedirect {
* Holds if `substring` refers to a substring of `base` which is considered untrusted
* when `base` is the current URL.
*/
predicate untrustedUrlSubstring(DataFlow::Node base, DataFlow::Node substring) {
deprecated predicate untrustedUrlSubstring(DataFlow::Node base, DataFlow::Node substring) {
exists(DataFlow::MethodCallNode mcn, string methodName |
mcn = substring and mcn.calls(base, methodName)
|

View File

@@ -10,9 +10,10 @@
import javascript
import UrlConcatenation
import ClientSideUrlRedirectCustomizations::ClientSideUrlRedirect
import semmle.javascript.security.TaintedUrlSuffix
// Materialize flow labels
private class ConcreteDocumentUrl extends DocumentUrl {
deprecated private class ConcreteDocumentUrl extends DocumentUrl {
ConcreteDocumentUrl() { this = this }
}
@@ -35,8 +36,7 @@ module ClientSideUrlRedirectConfig implements DataFlow::StateConfigSig {
}
predicate isBarrier(DataFlow::Node node, DataFlow::FlowLabel state) {
isPrefixExtraction(node) and
state instanceof DocumentUrl
TaintedUrlSuffix::isBarrier(node, state)
}
predicate isBarrierOut(DataFlow::Node node) { hostnameSanitizingPrefixEdge(node, _) }
@@ -47,9 +47,7 @@ module ClientSideUrlRedirectConfig implements DataFlow::StateConfigSig {
DataFlow::Node node1, DataFlow::FlowLabel state1, DataFlow::Node node2,
DataFlow::FlowLabel state2
) {
untrustedUrlSubstring(node1, node2) and
state1 instanceof DocumentUrl and
state2.isTaint()
TaintedUrlSuffix::step(node1, node2, state1, state2)
or
exists(HtmlSanitizerCall call |
node1 = call.getInput() and

View File

@@ -2,13 +2,40 @@ nodes
| electron.js:4:12:4:22 | window.name | semmle.label | window.name |
| electron.js:7:20:7:29 | getTaint() | semmle.label | getTaint() |
| react.js:10:60:10:81 | documen ... on.hash | semmle.label | documen ... on.hash |
| react.js:21:24:21:45 | documen ... on.hash | semmle.label | documen ... on.hash |
| react.js:28:43:28:64 | documen ... on.hash | semmle.label | documen ... on.hash |
| react.js:28:43:28:74 | documen ... bstr(1) | semmle.label | documen ... bstr(1) |
| react.js:34:43:34:64 | documen ... on.hash | semmle.label | documen ... on.hash |
| react.js:34:43:34:74 | documen ... bstr(1) | semmle.label | documen ... bstr(1) |
| react.js:40:19:40:40 | documen ... on.hash | semmle.label | documen ... on.hash |
| react.js:40:19:40:50 | documen ... bstr(1) | semmle.label | documen ... bstr(1) |
| react.js:10:60:10:91 | documen ... bstr(1) | semmle.label | documen ... bstr(1) |
| react.js:23:19:23:40 | documen ... on.hash | semmle.label | documen ... on.hash |
| react.js:23:19:23:50 | documen ... bstr(1) | semmle.label | documen ... bstr(1) |
| react.js:31:43:31:64 | documen ... on.hash | semmle.label | documen ... on.hash |
| react.js:31:43:31:74 | documen ... bstr(1) | semmle.label | documen ... bstr(1) |
| react.js:37:43:37:64 | documen ... on.hash | semmle.label | documen ... on.hash |
| react.js:37:43:37:74 | documen ... bstr(1) | semmle.label | documen ... bstr(1) |
| react.js:43:19:43:40 | documen ... on.hash | semmle.label | documen ... on.hash |
| react.js:43:19:43:50 | documen ... bstr(1) | semmle.label | documen ... bstr(1) |
| regexp-exec.js:4:11:4:20 | [, group1] | semmle.label | [, group1] |
| regexp-exec.js:4:11:4:57 | group1 | semmle.label | group1 |
| regexp-exec.js:4:24:4:57 | /#(.*)/ ... n.href) | semmle.label | /#(.*)/ ... n.href) |
| regexp-exec.js:4:37:4:56 | window.location.href | semmle.label | window.location.href |
| regexp-exec.js:5:28:5:33 | group1 | semmle.label | group1 |
| regexp-exec.js:9:11:9:20 | [, group1] | semmle.label | [, group1] |
| regexp-exec.js:9:11:9:58 | group1 | semmle.label | group1 |
| regexp-exec.js:9:24:9:58 | /\\?(.*) ... n.href) | semmle.label | /\\?(.*) ... n.href) |
| regexp-exec.js:9:38:9:57 | window.location.href | semmle.label | window.location.href |
| regexp-exec.js:10:28:10:33 | group1 | semmle.label | group1 |
| regexp-exec.js:29:11:29:20 | [, group1] | semmle.label | [, group1] |
| regexp-exec.js:29:11:29:58 | group1 | semmle.label | group1 |
| regexp-exec.js:29:24:29:43 | window.location.href | semmle.label | window.location.href |
| regexp-exec.js:29:24:29:58 | window. ... #(.*)/) | semmle.label | window. ... #(.*)/) |
| regexp-exec.js:30:28:30:33 | group1 | semmle.label | group1 |
| regexp-exec.js:34:11:34:20 | [, group1] | semmle.label | [, group1] |
| regexp-exec.js:34:11:34:64 | group1 | semmle.label | group1 |
| regexp-exec.js:34:24:34:43 | window.location.href | semmle.label | window.location.href |
| regexp-exec.js:34:24:34:61 | window. ... #(.*)/) | semmle.label | window. ... #(.*)/) |
| regexp-exec.js:35:28:35:33 | group1 | semmle.label | group1 |
| regexp-exec.js:39:11:39:20 | [, group1] | semmle.label | [, group1] |
| regexp-exec.js:39:11:39:71 | group1 | semmle.label | group1 |
| regexp-exec.js:39:24:39:71 | new Reg ... n.href) | semmle.label | new Reg ... n.href) |
| regexp-exec.js:39:51:39:70 | window.location.href | semmle.label | window.location.href |
| regexp-exec.js:40:28:40:33 | group1 | semmle.label | group1 |
| sanitizer.js:2:9:2:25 | url | semmle.label | url |
| sanitizer.js:2:15:2:25 | window.name | semmle.label | window.name |
| sanitizer.js:4:27:4:29 | url | semmle.label | url |
@@ -30,27 +57,23 @@ nodes
| tst6.js:8:21:8:48 | $locati ... irect') | semmle.label | $locati ... irect') |
| tst6.js:8:21:8:56 | $locati ... + "foo" | semmle.label | $locati ... + "foo" |
| tst7.js:2:12:2:35 | documen ... .search | semmle.label | documen ... .search |
| tst7.js:2:12:2:48 | documen ... ring(1) | semmle.label | documen ... ring(1) |
| tst7.js:5:27:5:50 | documen ... .search | semmle.label | documen ... .search |
| tst7.js:5:27:5:63 | documen ... ring(1) | semmle.label | documen ... ring(1) |
| tst9.js:2:21:2:42 | documen ... on.hash | semmle.label | documen ... on.hash |
| tst9.js:2:21:2:55 | documen ... ring(1) | semmle.label | documen ... ring(1) |
| tst10.js:5:17:5:46 | '/' + d ... .search | semmle.label | '/' + d ... .search |
| tst10.js:5:17:5:59 | '/' + d ... ring(1) | semmle.label | '/' + d ... ring(1) |
| tst10.js:5:23:5:46 | documen ... .search | semmle.label | documen ... .search |
| tst10.js:8:17:8:47 | '//' + ... .search | semmle.label | '//' + ... .search |
| tst10.js:5:23:5:59 | documen ... ring(1) | semmle.label | documen ... ring(1) |
| tst10.js:8:17:8:60 | '//' + ... ring(1) | semmle.label | '//' + ... ring(1) |
| tst10.js:8:24:8:47 | documen ... .search | semmle.label | documen ... .search |
| tst10.js:11:17:11:50 | '//foo' ... .search | semmle.label | '//foo' ... .search |
| tst10.js:8:24:8:60 | documen ... ring(1) | semmle.label | documen ... ring(1) |
| tst10.js:11:17:11:63 | '//foo' ... ring(1) | semmle.label | '//foo' ... ring(1) |
| tst10.js:11:27:11:50 | documen ... .search | semmle.label | documen ... .search |
| tst10.js:14:17:14:56 | 'https: ... .search | semmle.label | 'https: ... .search |
| tst10.js:11:27:11:63 | documen ... ring(1) | semmle.label | documen ... ring(1) |
| tst10.js:14:17:14:69 | 'https: ... ring(1) | semmle.label | 'https: ... ring(1) |
| tst10.js:14:33:14:56 | documen ... .search | semmle.label | documen ... .search |
| tst12.js:3:9:3:50 | urlParts | semmle.label | urlParts |
| tst12.js:3:9:3:50 | urlParts [ArrayElement] | semmle.label | urlParts [ArrayElement] |
| tst12.js:3:20:3:39 | window.location.hash | semmle.label | window.location.hash |
| tst12.js:3:20:3:50 | window. ... it('?') | semmle.label | window. ... it('?') |
| tst12.js:3:20:3:50 | window. ... it('?') [ArrayElement] | semmle.label | window. ... it('?') [ArrayElement] |
| tst12.js:4:9:4:45 | loc | semmle.label | loc |
| tst12.js:4:15:4:22 | urlParts | semmle.label | urlParts |
| tst12.js:4:15:4:22 | urlParts [ArrayElement] | semmle.label | urlParts [ArrayElement] |
| tst12.js:4:15:4:25 | urlParts[0] | semmle.label | urlParts[0] |
| tst12.js:5:23:5:25 | loc | semmle.label | loc |
| tst10.js:14:33:14:69 | documen ... ring(1) | semmle.label | documen ... ring(1) |
| tst13.js:2:9:2:52 | payload | semmle.label | payload |
| tst13.js:2:19:2:42 | documen ... .search | semmle.label | documen ... .search |
| tst13.js:2:19:2:52 | documen ... bstr(1) | semmle.label | documen ... bstr(1) |
@@ -88,6 +111,42 @@ nodes
| tst13.js:81:28:81:30 | url | semmle.label | url |
| tst13.js:82:27:82:29 | url | semmle.label | url |
| tst13.js:83:22:83:24 | url | semmle.label | url |
| tst15.js:2:9:2:42 | url | semmle.label | url |
| tst15.js:2:15:2:31 | document.location | semmle.label | document.location |
| tst15.js:2:15:2:42 | documen ... tring() | semmle.label | documen ... tring() |
| tst15.js:3:23:3:25 | url | semmle.label | url |
| tst15.js:3:23:3:38 | url.substring(0) | semmle.label | url.substring(0) |
| tst15.js:3:23:3:51 | url.sub ... ring(1) | semmle.label | url.sub ... ring(1) |
| tst15.js:4:23:4:25 | url | semmle.label | url |
| tst15.js:4:23:4:42 | url.substring(0, 10) | semmle.label | url.substring(0, 10) |
| tst15.js:4:23:4:55 | url.sub ... ring(1) | semmle.label | url.sub ... ring(1) |
| tst15.js:5:23:5:25 | url | semmle.label | url |
| tst15.js:5:23:5:60 | url.sub ... ', 10)) | semmle.label | url.sub ... ', 10)) |
| tst15.js:5:23:5:73 | url.sub ... ring(1) | semmle.label | url.sub ... ring(1) |
| tst15.js:7:9:7:43 | url2 | semmle.label | url2 |
| tst15.js:7:16:7:32 | document.location | semmle.label | document.location |
| tst15.js:7:16:7:43 | documen ... tring() | semmle.label | documen ... tring() |
| tst15.js:8:23:8:26 | url2 | semmle.label | url2 |
| tst15.js:8:23:8:39 | url2.substring(0) | semmle.label | url2.substring(0) |
| tst15.js:8:23:8:60 | url2.su ... nown()) | semmle.label | url2.su ... nown()) |
| tst15.js:9:23:9:26 | url2 | semmle.label | url2 |
| tst15.js:9:23:9:43 | url2.su ... (0, 10) | semmle.label | url2.su ... (0, 10) |
| tst15.js:9:23:9:64 | url2.su ... nown()) | semmle.label | url2.su ... nown()) |
| tst15.js:10:23:10:26 | url2 | semmle.label | url2 |
| tst15.js:10:23:10:62 | url2.su ... ', 10)) | semmle.label | url2.su ... ', 10)) |
| tst15.js:10:23:10:83 | url2.su ... nown()) | semmle.label | url2.su ... nown()) |
| tst15.js:12:9:12:52 | search | semmle.label | search |
| tst15.js:12:18:12:41 | documen ... .search | semmle.label | documen ... .search |
| tst15.js:12:18:12:52 | documen ... tring() | semmle.label | documen ... tring() |
| tst15.js:13:23:13:28 | search | semmle.label | search |
| tst15.js:13:23:13:41 | search.substring(0) | semmle.label | search.substring(0) |
| tst15.js:13:23:13:54 | search. ... ring(1) | semmle.label | search. ... ring(1) |
| tst15.js:14:23:14:28 | search | semmle.label | search |
| tst15.js:14:23:14:45 | search. ... (0, 10) | semmle.label | search. ... (0, 10) |
| tst15.js:14:23:14:58 | search. ... ring(1) | semmle.label | search. ... ring(1) |
| tst15.js:15:23:15:28 | search | semmle.label | search |
| tst15.js:15:23:15:66 | search. ... ', 10)) | semmle.label | search. ... ', 10)) |
| tst15.js:15:23:15:79 | search. ... ring(1) | semmle.label | search. ... ring(1) |
| tst.js:2:19:2:69 | /.*redi ... n.href) | semmle.label | /.*redi ... n.href) |
| tst.js:2:19:2:72 | /.*redi ... ref)[1] | semmle.label | /.*redi ... ref)[1] |
| tst.js:2:47:2:68 | documen ... on.href | semmle.label | documen ... on.href |
@@ -109,25 +168,51 @@ nodes
| tst.js:26:22:26:79 | new Reg ... n.href) | semmle.label | new Reg ... n.href) |
| tst.js:26:22:26:82 | new Reg ... ref)[1] | semmle.label | new Reg ... ref)[1] |
| tst.js:26:62:26:78 | win.location.href | semmle.label | win.location.href |
| typed.ts:4:13:4:36 | params | semmle.label | params |
| typed.ts:4:13:4:49 | params | semmle.label | params |
| typed.ts:4:22:4:36 | location.search | semmle.label | location.search |
| typed.ts:4:22:4:49 | locatio ... ring(1) | semmle.label | locatio ... ring(1) |
| typed.ts:5:25:5:30 | params | semmle.label | params |
| typed.ts:7:24:7:34 | redirectUri | semmle.label | redirectUri |
| typed.ts:8:33:8:43 | redirectUri | semmle.label | redirectUri |
| typed.ts:25:25:25:34 | loc.search | semmle.label | loc.search |
| typed.ts:25:25:25:47 | loc.sea ... ring(1) | semmle.label | loc.sea ... ring(1) |
| typed.ts:28:24:28:34 | redirectUri | semmle.label | redirectUri |
| typed.ts:29:33:29:43 | redirectUri | semmle.label | redirectUri |
| typed.ts:47:25:47:34 | loc.search | semmle.label | loc.search |
| typed.ts:47:25:47:47 | loc.sea ... ring(1) | semmle.label | loc.sea ... ring(1) |
| typed.ts:48:26:48:36 | loc2.search | semmle.label | loc2.search |
| typed.ts:48:26:48:49 | loc2.se ... ring(1) | semmle.label | loc2.se ... ring(1) |
| typed.ts:51:24:51:34 | redirectUri | semmle.label | redirectUri |
| typed.ts:52:33:52:43 | redirectUri | semmle.label | redirectUri |
| typed.ts:55:25:55:35 | redirectUri | semmle.label | redirectUri |
| typed.ts:56:33:56:43 | redirectUri | semmle.label | redirectUri |
edges
| electron.js:4:12:4:22 | window.name | electron.js:7:20:7:29 | getTaint() | provenance | |
| react.js:28:43:28:64 | documen ... on.hash | react.js:28:43:28:74 | documen ... bstr(1) | provenance | |
| react.js:34:43:34:64 | documen ... on.hash | react.js:34:43:34:74 | documen ... bstr(1) | provenance | |
| react.js:40:19:40:40 | documen ... on.hash | react.js:40:19:40:50 | documen ... bstr(1) | provenance | |
| react.js:10:60:10:81 | documen ... on.hash | react.js:10:60:10:91 | documen ... bstr(1) | provenance | Config |
| react.js:23:19:23:40 | documen ... on.hash | react.js:23:19:23:50 | documen ... bstr(1) | provenance | Config |
| react.js:31:43:31:64 | documen ... on.hash | react.js:31:43:31:74 | documen ... bstr(1) | provenance | Config |
| react.js:37:43:37:64 | documen ... on.hash | react.js:37:43:37:74 | documen ... bstr(1) | provenance | Config |
| react.js:43:19:43:40 | documen ... on.hash | react.js:43:19:43:50 | documen ... bstr(1) | provenance | Config |
| regexp-exec.js:4:11:4:20 | [, group1] | regexp-exec.js:4:11:4:57 | group1 | provenance | |
| regexp-exec.js:4:11:4:57 | group1 | regexp-exec.js:5:28:5:33 | group1 | provenance | |
| regexp-exec.js:4:24:4:57 | /#(.*)/ ... n.href) | regexp-exec.js:4:11:4:20 | [, group1] | provenance | |
| regexp-exec.js:4:37:4:56 | window.location.href | regexp-exec.js:4:24:4:57 | /#(.*)/ ... n.href) | provenance | Config |
| regexp-exec.js:9:11:9:20 | [, group1] | regexp-exec.js:9:11:9:58 | group1 | provenance | |
| regexp-exec.js:9:11:9:58 | group1 | regexp-exec.js:10:28:10:33 | group1 | provenance | |
| regexp-exec.js:9:24:9:58 | /\\?(.*) ... n.href) | regexp-exec.js:9:11:9:20 | [, group1] | provenance | |
| regexp-exec.js:9:38:9:57 | window.location.href | regexp-exec.js:9:24:9:58 | /\\?(.*) ... n.href) | provenance | Config |
| regexp-exec.js:29:11:29:20 | [, group1] | regexp-exec.js:29:11:29:58 | group1 | provenance | |
| regexp-exec.js:29:11:29:58 | group1 | regexp-exec.js:30:28:30:33 | group1 | provenance | |
| regexp-exec.js:29:24:29:43 | window.location.href | regexp-exec.js:29:24:29:58 | window. ... #(.*)/) | provenance | Config |
| regexp-exec.js:29:24:29:58 | window. ... #(.*)/) | regexp-exec.js:29:11:29:20 | [, group1] | provenance | |
| regexp-exec.js:34:11:34:20 | [, group1] | regexp-exec.js:34:11:34:64 | group1 | provenance | |
| regexp-exec.js:34:11:34:64 | group1 | regexp-exec.js:35:28:35:33 | group1 | provenance | |
| regexp-exec.js:34:24:34:43 | window.location.href | regexp-exec.js:34:24:34:61 | window. ... #(.*)/) | provenance | Config |
| regexp-exec.js:34:24:34:61 | window. ... #(.*)/) | regexp-exec.js:34:11:34:20 | [, group1] | provenance | |
| regexp-exec.js:39:11:39:20 | [, group1] | regexp-exec.js:39:11:39:71 | group1 | provenance | |
| regexp-exec.js:39:11:39:71 | group1 | regexp-exec.js:40:28:40:33 | group1 | provenance | |
| regexp-exec.js:39:24:39:71 | new Reg ... n.href) | regexp-exec.js:39:11:39:20 | [, group1] | provenance | |
| regexp-exec.js:39:51:39:70 | window.location.href | regexp-exec.js:39:24:39:71 | new Reg ... n.href) | provenance | Config |
| sanitizer.js:2:9:2:25 | url | sanitizer.js:4:27:4:29 | url | provenance | |
| sanitizer.js:2:9:2:25 | url | sanitizer.js:16:27:16:29 | url | provenance | |
| sanitizer.js:2:9:2:25 | url | sanitizer.js:19:27:19:29 | url | provenance | |
@@ -144,21 +229,17 @@ edges
| tst6.js:2:7:2:45 | redirect | tst6.js:6:17:6:24 | redirect | provenance | |
| tst6.js:2:18:2:45 | $locati ... irect') | tst6.js:2:7:2:45 | redirect | provenance | |
| tst6.js:8:21:8:48 | $locati ... irect') | tst6.js:8:21:8:56 | $locati ... + "foo" | provenance | |
| tst9.js:2:21:2:42 | documen ... on.hash | tst9.js:2:21:2:55 | documen ... ring(1) | provenance | |
| tst10.js:5:23:5:46 | documen ... .search | tst10.js:5:17:5:46 | '/' + d ... .search | provenance | |
| tst10.js:8:24:8:47 | documen ... .search | tst10.js:8:17:8:47 | '//' + ... .search | provenance | |
| tst10.js:11:27:11:50 | documen ... .search | tst10.js:11:17:11:50 | '//foo' ... .search | provenance | |
| tst10.js:14:33:14:56 | documen ... .search | tst10.js:14:17:14:56 | 'https: ... .search | provenance | |
| tst12.js:3:9:3:50 | urlParts | tst12.js:4:15:4:22 | urlParts | provenance | |
| tst12.js:3:9:3:50 | urlParts [ArrayElement] | tst12.js:4:15:4:22 | urlParts [ArrayElement] | provenance | |
| tst12.js:3:20:3:39 | window.location.hash | tst12.js:3:20:3:50 | window. ... it('?') | provenance | |
| tst12.js:3:20:3:39 | window.location.hash | tst12.js:3:20:3:50 | window. ... it('?') [ArrayElement] | provenance | |
| tst12.js:3:20:3:50 | window. ... it('?') | tst12.js:3:9:3:50 | urlParts | provenance | |
| tst12.js:3:20:3:50 | window. ... it('?') [ArrayElement] | tst12.js:3:9:3:50 | urlParts [ArrayElement] | provenance | |
| tst12.js:4:9:4:45 | loc | tst12.js:5:23:5:25 | loc | provenance | |
| tst12.js:4:15:4:22 | urlParts | tst12.js:4:9:4:45 | loc | provenance | |
| tst12.js:4:15:4:22 | urlParts [ArrayElement] | tst12.js:4:15:4:25 | urlParts[0] | provenance | |
| tst12.js:4:15:4:25 | urlParts[0] | tst12.js:4:9:4:45 | loc | provenance | |
| tst7.js:2:12:2:35 | documen ... .search | tst7.js:2:12:2:48 | documen ... ring(1) | provenance | Config |
| tst7.js:5:27:5:50 | documen ... .search | tst7.js:5:27:5:63 | documen ... ring(1) | provenance | Config |
| tst9.js:2:21:2:42 | documen ... on.hash | tst9.js:2:21:2:55 | documen ... ring(1) | provenance | Config |
| tst10.js:5:23:5:46 | documen ... .search | tst10.js:5:23:5:59 | documen ... ring(1) | provenance | Config |
| tst10.js:5:23:5:59 | documen ... ring(1) | tst10.js:5:17:5:59 | '/' + d ... ring(1) | provenance | |
| tst10.js:8:24:8:47 | documen ... .search | tst10.js:8:24:8:60 | documen ... ring(1) | provenance | Config |
| tst10.js:8:24:8:60 | documen ... ring(1) | tst10.js:8:17:8:60 | '//' + ... ring(1) | provenance | |
| tst10.js:11:27:11:50 | documen ... .search | tst10.js:11:27:11:63 | documen ... ring(1) | provenance | Config |
| tst10.js:11:27:11:63 | documen ... ring(1) | tst10.js:11:17:11:63 | '//foo' ... ring(1) | provenance | |
| tst10.js:14:33:14:56 | documen ... .search | tst10.js:14:33:14:69 | documen ... ring(1) | provenance | Config |
| tst10.js:14:33:14:69 | documen ... ring(1) | tst10.js:14:17:14:69 | 'https: ... ring(1) | provenance | |
| tst13.js:2:9:2:52 | payload | tst13.js:4:15:4:21 | payload | provenance | |
| tst13.js:2:9:2:52 | payload | tst13.js:8:21:8:27 | payload | provenance | |
| tst13.js:2:9:2:52 | payload | tst13.js:12:14:12:20 | payload | provenance | |
@@ -170,12 +251,12 @@ edges
| tst13.js:2:9:2:52 | payload | tst13.js:36:21:36:27 | payload | provenance | |
| tst13.js:2:9:2:52 | payload | tst13.js:40:15:40:21 | payload | provenance | |
| tst13.js:2:9:2:52 | payload | tst13.js:44:14:44:20 | payload | provenance | |
| tst13.js:2:19:2:42 | documen ... .search | tst13.js:2:19:2:52 | documen ... bstr(1) | provenance | |
| tst13.js:2:19:2:42 | documen ... .search | tst13.js:2:19:2:52 | documen ... bstr(1) | provenance | Config |
| tst13.js:2:19:2:52 | documen ... bstr(1) | tst13.js:2:9:2:52 | payload | provenance | |
| tst13.js:49:32:49:32 | e | tst13.js:50:23:50:23 | e | provenance | |
| tst13.js:52:34:52:34 | e | tst13.js:53:28:53:28 | e | provenance | |
| tst13.js:59:9:59:52 | payload | tst13.js:61:18:61:24 | payload | provenance | |
| tst13.js:59:19:59:42 | documen ... .search | tst13.js:59:19:59:52 | documen ... bstr(1) | provenance | |
| tst13.js:59:19:59:42 | documen ... .search | tst13.js:59:19:59:52 | documen ... bstr(1) | provenance | Config |
| tst13.js:59:19:59:52 | documen ... bstr(1) | tst13.js:59:9:59:52 | payload | provenance | |
| tst13.js:65:9:65:49 | payload | tst13.js:67:21:67:27 | payload | provenance | |
| tst13.js:65:19:65:39 | history ... on.hash | tst13.js:65:19:65:49 | history ... bstr(1) | provenance | |
@@ -187,8 +268,41 @@ edges
| tst13.js:78:9:78:48 | url | tst13.js:81:28:81:30 | url | provenance | |
| tst13.js:78:9:78:48 | url | tst13.js:82:27:82:29 | url | provenance | |
| tst13.js:78:9:78:48 | url | tst13.js:83:22:83:24 | url | provenance | |
| tst13.js:78:15:78:38 | documen ... .search | tst13.js:78:15:78:48 | documen ... bstr(1) | provenance | |
| tst13.js:78:15:78:38 | documen ... .search | tst13.js:78:15:78:48 | documen ... bstr(1) | provenance | Config |
| tst13.js:78:15:78:48 | documen ... bstr(1) | tst13.js:78:9:78:48 | url | provenance | |
| tst15.js:2:9:2:42 | url | tst15.js:3:23:3:25 | url | provenance | |
| tst15.js:2:9:2:42 | url | tst15.js:4:23:4:25 | url | provenance | |
| tst15.js:2:9:2:42 | url | tst15.js:5:23:5:25 | url | provenance | |
| tst15.js:2:15:2:31 | document.location | tst15.js:2:15:2:42 | documen ... tring() | provenance | |
| tst15.js:2:15:2:42 | documen ... tring() | tst15.js:2:9:2:42 | url | provenance | |
| tst15.js:3:23:3:25 | url | tst15.js:3:23:3:38 | url.substring(0) | provenance | |
| tst15.js:3:23:3:38 | url.substring(0) | tst15.js:3:23:3:51 | url.sub ... ring(1) | provenance | Config |
| tst15.js:4:23:4:25 | url | tst15.js:4:23:4:42 | url.substring(0, 10) | provenance | |
| tst15.js:4:23:4:42 | url.substring(0, 10) | tst15.js:4:23:4:55 | url.sub ... ring(1) | provenance | Config |
| tst15.js:5:23:5:25 | url | tst15.js:5:23:5:60 | url.sub ... ', 10)) | provenance | |
| tst15.js:5:23:5:60 | url.sub ... ', 10)) | tst15.js:5:23:5:73 | url.sub ... ring(1) | provenance | Config |
| tst15.js:7:9:7:43 | url2 | tst15.js:8:23:8:26 | url2 | provenance | |
| tst15.js:7:9:7:43 | url2 | tst15.js:9:23:9:26 | url2 | provenance | |
| tst15.js:7:9:7:43 | url2 | tst15.js:10:23:10:26 | url2 | provenance | |
| tst15.js:7:16:7:32 | document.location | tst15.js:7:16:7:43 | documen ... tring() | provenance | |
| tst15.js:7:16:7:43 | documen ... tring() | tst15.js:7:9:7:43 | url2 | provenance | |
| tst15.js:8:23:8:26 | url2 | tst15.js:8:23:8:39 | url2.substring(0) | provenance | |
| tst15.js:8:23:8:39 | url2.substring(0) | tst15.js:8:23:8:60 | url2.su ... nown()) | provenance | Config |
| tst15.js:9:23:9:26 | url2 | tst15.js:9:23:9:43 | url2.su ... (0, 10) | provenance | |
| tst15.js:9:23:9:43 | url2.su ... (0, 10) | tst15.js:9:23:9:64 | url2.su ... nown()) | provenance | Config |
| tst15.js:10:23:10:26 | url2 | tst15.js:10:23:10:62 | url2.su ... ', 10)) | provenance | |
| tst15.js:10:23:10:62 | url2.su ... ', 10)) | tst15.js:10:23:10:83 | url2.su ... nown()) | provenance | Config |
| tst15.js:12:9:12:52 | search | tst15.js:13:23:13:28 | search | provenance | |
| tst15.js:12:9:12:52 | search | tst15.js:14:23:14:28 | search | provenance | |
| tst15.js:12:9:12:52 | search | tst15.js:15:23:15:28 | search | provenance | |
| tst15.js:12:18:12:41 | documen ... .search | tst15.js:12:18:12:52 | documen ... tring() | provenance | |
| tst15.js:12:18:12:52 | documen ... tring() | tst15.js:12:9:12:52 | search | provenance | |
| tst15.js:13:23:13:28 | search | tst15.js:13:23:13:41 | search.substring(0) | provenance | |
| tst15.js:13:23:13:41 | search.substring(0) | tst15.js:13:23:13:54 | search. ... ring(1) | provenance | Config |
| tst15.js:14:23:14:28 | search | tst15.js:14:23:14:45 | search. ... (0, 10) | provenance | |
| tst15.js:14:23:14:45 | search. ... (0, 10) | tst15.js:14:23:14:58 | search. ... ring(1) | provenance | Config |
| tst15.js:15:23:15:28 | search | tst15.js:15:23:15:66 | search. ... ', 10)) | provenance | |
| tst15.js:15:23:15:66 | search. ... ', 10)) | tst15.js:15:23:15:79 | search. ... ring(1) | provenance | Config |
| tst.js:2:19:2:69 | /.*redi ... n.href) | tst.js:2:19:2:72 | /.*redi ... ref)[1] | provenance | |
| tst.js:2:47:2:68 | documen ... on.href | tst.js:2:19:2:69 | /.*redi ... n.href) | provenance | Config |
| tst.js:6:20:6:56 | indirec ... n.href) | tst.js:6:20:6:59 | indirec ... ref)[1] | provenance | |
@@ -203,24 +317,33 @@ edges
| tst.js:22:34:22:55 | documen ... on.href | tst.js:22:20:22:56 | indirec ... n.href) | provenance | Config |
| tst.js:26:22:26:79 | new Reg ... n.href) | tst.js:26:22:26:82 | new Reg ... ref)[1] | provenance | |
| tst.js:26:62:26:78 | win.location.href | tst.js:26:22:26:79 | new Reg ... n.href) | provenance | Config |
| typed.ts:4:13:4:36 | params | typed.ts:5:25:5:30 | params | provenance | |
| typed.ts:4:22:4:36 | location.search | typed.ts:4:13:4:36 | params | provenance | |
| typed.ts:4:13:4:49 | params | typed.ts:5:25:5:30 | params | provenance | |
| typed.ts:4:22:4:36 | location.search | typed.ts:4:22:4:49 | locatio ... ring(1) | provenance | Config |
| typed.ts:4:22:4:49 | locatio ... ring(1) | typed.ts:4:13:4:49 | params | provenance | |
| typed.ts:5:25:5:30 | params | typed.ts:7:24:7:34 | redirectUri | provenance | |
| typed.ts:7:24:7:34 | redirectUri | typed.ts:8:33:8:43 | redirectUri | provenance | |
| typed.ts:25:25:25:34 | loc.search | typed.ts:28:24:28:34 | redirectUri | provenance | |
| typed.ts:25:25:25:34 | loc.search | typed.ts:25:25:25:47 | loc.sea ... ring(1) | provenance | Config |
| typed.ts:25:25:25:47 | loc.sea ... ring(1) | typed.ts:28:24:28:34 | redirectUri | provenance | |
| typed.ts:28:24:28:34 | redirectUri | typed.ts:29:33:29:43 | redirectUri | provenance | |
| typed.ts:47:25:47:34 | loc.search | typed.ts:51:24:51:34 | redirectUri | provenance | |
| typed.ts:48:26:48:36 | loc2.search | typed.ts:55:25:55:35 | redirectUri | provenance | |
| typed.ts:47:25:47:34 | loc.search | typed.ts:47:25:47:47 | loc.sea ... ring(1) | provenance | Config |
| typed.ts:47:25:47:47 | loc.sea ... ring(1) | typed.ts:51:24:51:34 | redirectUri | provenance | |
| typed.ts:48:26:48:36 | loc2.search | typed.ts:48:26:48:49 | loc2.se ... ring(1) | provenance | Config |
| typed.ts:48:26:48:49 | loc2.se ... ring(1) | typed.ts:55:25:55:35 | redirectUri | provenance | |
| typed.ts:51:24:51:34 | redirectUri | typed.ts:52:33:52:43 | redirectUri | provenance | |
| typed.ts:55:25:55:35 | redirectUri | typed.ts:56:33:56:43 | redirectUri | provenance | |
subpaths
#select
| electron.js:7:20:7:29 | getTaint() | electron.js:4:12:4:22 | window.name | electron.js:7:20:7:29 | getTaint() | Untrusted URL redirection depends on a $@. | electron.js:4:12:4:22 | window.name | user-provided value |
| react.js:10:60:10:81 | documen ... on.hash | react.js:10:60:10:81 | documen ... on.hash | react.js:10:60:10:81 | documen ... on.hash | Untrusted URL redirection depends on a $@. | react.js:10:60:10:81 | documen ... on.hash | user-provided value |
| react.js:21:24:21:45 | documen ... on.hash | react.js:21:24:21:45 | documen ... on.hash | react.js:21:24:21:45 | documen ... on.hash | Untrusted URL redirection depends on a $@. | react.js:21:24:21:45 | documen ... on.hash | user-provided value |
| react.js:28:43:28:74 | documen ... bstr(1) | react.js:28:43:28:64 | documen ... on.hash | react.js:28:43:28:74 | documen ... bstr(1) | Untrusted URL redirection depends on a $@. | react.js:28:43:28:64 | documen ... on.hash | user-provided value |
| react.js:34:43:34:74 | documen ... bstr(1) | react.js:34:43:34:64 | documen ... on.hash | react.js:34:43:34:74 | documen ... bstr(1) | Untrusted URL redirection depends on a $@. | react.js:34:43:34:64 | documen ... on.hash | user-provided value |
| react.js:40:19:40:50 | documen ... bstr(1) | react.js:40:19:40:40 | documen ... on.hash | react.js:40:19:40:50 | documen ... bstr(1) | Untrusted URL redirection depends on a $@. | react.js:40:19:40:40 | documen ... on.hash | user-provided value |
| react.js:10:60:10:91 | documen ... bstr(1) | react.js:10:60:10:81 | documen ... on.hash | react.js:10:60:10:91 | documen ... bstr(1) | Untrusted URL redirection depends on a $@. | react.js:10:60:10:81 | documen ... on.hash | user-provided value |
| react.js:23:19:23:50 | documen ... bstr(1) | react.js:23:19:23:40 | documen ... on.hash | react.js:23:19:23:50 | documen ... bstr(1) | Untrusted URL redirection depends on a $@. | react.js:23:19:23:40 | documen ... on.hash | user-provided value |
| react.js:31:43:31:74 | documen ... bstr(1) | react.js:31:43:31:64 | documen ... on.hash | react.js:31:43:31:74 | documen ... bstr(1) | Untrusted URL redirection depends on a $@. | react.js:31:43:31:64 | documen ... on.hash | user-provided value |
| react.js:37:43:37:74 | documen ... bstr(1) | react.js:37:43:37:64 | documen ... on.hash | react.js:37:43:37:74 | documen ... bstr(1) | Untrusted URL redirection depends on a $@. | react.js:37:43:37:64 | documen ... on.hash | user-provided value |
| react.js:43:19:43:50 | documen ... bstr(1) | react.js:43:19:43:40 | documen ... on.hash | react.js:43:19:43:50 | documen ... bstr(1) | Untrusted URL redirection depends on a $@. | react.js:43:19:43:40 | documen ... on.hash | user-provided value |
| regexp-exec.js:5:28:5:33 | group1 | regexp-exec.js:4:37:4:56 | window.location.href | regexp-exec.js:5:28:5:33 | group1 | Untrusted URL redirection depends on a $@. | regexp-exec.js:4:37:4:56 | window.location.href | user-provided value |
| regexp-exec.js:10:28:10:33 | group1 | regexp-exec.js:9:38:9:57 | window.location.href | regexp-exec.js:10:28:10:33 | group1 | Untrusted URL redirection depends on a $@. | regexp-exec.js:9:38:9:57 | window.location.href | user-provided value |
| regexp-exec.js:30:28:30:33 | group1 | regexp-exec.js:29:24:29:43 | window.location.href | regexp-exec.js:30:28:30:33 | group1 | Untrusted URL redirection depends on a $@. | regexp-exec.js:29:24:29:43 | window.location.href | user-provided value |
| regexp-exec.js:35:28:35:33 | group1 | regexp-exec.js:34:24:34:43 | window.location.href | regexp-exec.js:35:28:35:33 | group1 | Untrusted URL redirection depends on a $@. | regexp-exec.js:34:24:34:43 | window.location.href | user-provided value |
| regexp-exec.js:40:28:40:33 | group1 | regexp-exec.js:39:51:39:70 | window.location.href | regexp-exec.js:40:28:40:33 | group1 | Untrusted URL redirection depends on a $@. | regexp-exec.js:39:51:39:70 | window.location.href | user-provided value |
| sanitizer.js:4:27:4:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:4:27:4:29 | url | Untrusted URL redirection depends on a $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
| sanitizer.js:16:27:16:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:16:27:16:29 | url | Untrusted URL redirection depends on a $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
| sanitizer.js:19:27:19:29 | url | sanitizer.js:2:15:2:25 | window.name | sanitizer.js:19:27:19:29 | url | Untrusted URL redirection depends on a $@. | sanitizer.js:2:15:2:25 | window.name | user-provided value |
@@ -233,14 +356,13 @@ subpaths
| tst6.js:4:21:4:28 | redirect | tst6.js:2:18:2:45 | $locati ... irect') | tst6.js:4:21:4:28 | redirect | Untrusted URL redirection depends on a $@. | tst6.js:2:18:2:45 | $locati ... irect') | user-provided value |
| tst6.js:6:17:6:24 | redirect | tst6.js:2:18:2:45 | $locati ... irect') | tst6.js:6:17:6:24 | redirect | Untrusted URL redirection depends on a $@. | tst6.js:2:18:2:45 | $locati ... irect') | user-provided value |
| tst6.js:8:21:8:56 | $locati ... + "foo" | tst6.js:8:21:8:48 | $locati ... irect') | tst6.js:8:21:8:56 | $locati ... + "foo" | Untrusted URL redirection depends on a $@. | tst6.js:8:21:8:48 | $locati ... irect') | user-provided value |
| tst7.js:2:12:2:35 | documen ... .search | tst7.js:2:12:2:35 | documen ... .search | tst7.js:2:12:2:35 | documen ... .search | Untrusted URL redirection depends on a $@. | tst7.js:2:12:2:35 | documen ... .search | user-provided value |
| tst7.js:5:27:5:50 | documen ... .search | tst7.js:5:27:5:50 | documen ... .search | tst7.js:5:27:5:50 | documen ... .search | Untrusted URL redirection depends on a $@. | tst7.js:5:27:5:50 | documen ... .search | user-provided value |
| tst7.js:2:12:2:48 | documen ... ring(1) | tst7.js:2:12:2:35 | documen ... .search | tst7.js:2:12:2:48 | documen ... ring(1) | Untrusted URL redirection depends on a $@. | tst7.js:2:12:2:35 | documen ... .search | user-provided value |
| tst7.js:5:27:5:63 | documen ... ring(1) | tst7.js:5:27:5:50 | documen ... .search | tst7.js:5:27:5:63 | documen ... ring(1) | Untrusted URL redirection depends on a $@. | tst7.js:5:27:5:50 | documen ... .search | user-provided value |
| tst9.js:2:21:2:55 | documen ... ring(1) | tst9.js:2:21:2:42 | documen ... on.hash | tst9.js:2:21:2:55 | documen ... ring(1) | Untrusted URL redirection depends on a $@. | tst9.js:2:21:2:42 | documen ... on.hash | user-provided value |
| tst10.js:5:17:5:46 | '/' + d ... .search | tst10.js:5:23:5:46 | documen ... .search | tst10.js:5:17:5:46 | '/' + d ... .search | Untrusted URL redirection depends on a $@. | tst10.js:5:23:5:46 | documen ... .search | user-provided value |
| tst10.js:8:17:8:47 | '//' + ... .search | tst10.js:8:24:8:47 | documen ... .search | tst10.js:8:17:8:47 | '//' + ... .search | Untrusted URL redirection depends on a $@. | tst10.js:8:24:8:47 | documen ... .search | user-provided value |
| tst10.js:11:17:11:50 | '//foo' ... .search | tst10.js:11:27:11:50 | documen ... .search | tst10.js:11:17:11:50 | '//foo' ... .search | Untrusted URL redirection depends on a $@. | tst10.js:11:27:11:50 | documen ... .search | user-provided value |
| tst10.js:14:17:14:56 | 'https: ... .search | tst10.js:14:33:14:56 | documen ... .search | tst10.js:14:17:14:56 | 'https: ... .search | Untrusted URL redirection depends on a $@. | tst10.js:14:33:14:56 | documen ... .search | user-provided value |
| tst12.js:5:23:5:25 | loc | tst12.js:3:20:3:39 | window.location.hash | tst12.js:5:23:5:25 | loc | Untrusted URL redirection depends on a $@. | tst12.js:3:20:3:39 | window.location.hash | user-provided value |
| tst10.js:5:17:5:59 | '/' + d ... ring(1) | tst10.js:5:23:5:46 | documen ... .search | tst10.js:5:17:5:59 | '/' + d ... ring(1) | Untrusted URL redirection depends on a $@. | tst10.js:5:23:5:46 | documen ... .search | user-provided value |
| tst10.js:8:17:8:60 | '//' + ... ring(1) | tst10.js:8:24:8:47 | documen ... .search | tst10.js:8:17:8:60 | '//' + ... ring(1) | Untrusted URL redirection depends on a $@. | tst10.js:8:24:8:47 | documen ... .search | user-provided value |
| tst10.js:11:17:11:63 | '//foo' ... ring(1) | tst10.js:11:27:11:50 | documen ... .search | tst10.js:11:17:11:63 | '//foo' ... ring(1) | Untrusted URL redirection depends on a $@. | tst10.js:11:27:11:50 | documen ... .search | user-provided value |
| tst10.js:14:17:14:69 | 'https: ... ring(1) | tst10.js:14:33:14:56 | documen ... .search | tst10.js:14:17:14:69 | 'https: ... ring(1) | Untrusted URL redirection depends on a $@. | tst10.js:14:33:14:56 | documen ... .search | user-provided value |
| tst13.js:4:15:4:21 | payload | tst13.js:2:19:2:42 | documen ... .search | tst13.js:4:15:4:21 | payload | Untrusted URL redirection depends on a $@. | tst13.js:2:19:2:42 | documen ... .search | user-provided value |
| tst13.js:8:21:8:27 | payload | tst13.js:2:19:2:42 | documen ... .search | tst13.js:8:21:8:27 | payload | Untrusted URL redirection depends on a $@. | tst13.js:2:19:2:42 | documen ... .search | user-provided value |
| tst13.js:12:14:12:20 | payload | tst13.js:2:19:2:42 | documen ... .search | tst13.js:12:14:12:20 | payload | Untrusted URL redirection depends on a $@. | tst13.js:2:19:2:42 | documen ... .search | user-provided value |
@@ -261,6 +383,15 @@ subpaths
| tst13.js:81:28:81:30 | url | tst13.js:78:15:78:38 | documen ... .search | tst13.js:81:28:81:30 | url | Untrusted URL redirection depends on a $@. | tst13.js:78:15:78:38 | documen ... .search | user-provided value |
| tst13.js:82:27:82:29 | url | tst13.js:78:15:78:38 | documen ... .search | tst13.js:82:27:82:29 | url | Untrusted URL redirection depends on a $@. | tst13.js:78:15:78:38 | documen ... .search | user-provided value |
| tst13.js:83:22:83:24 | url | tst13.js:78:15:78:38 | documen ... .search | tst13.js:83:22:83:24 | url | Untrusted URL redirection depends on a $@. | tst13.js:78:15:78:38 | documen ... .search | user-provided value |
| tst15.js:3:23:3:51 | url.sub ... ring(1) | tst15.js:2:15:2:31 | document.location | tst15.js:3:23:3:51 | url.sub ... ring(1) | Untrusted URL redirection depends on a $@. | tst15.js:2:15:2:31 | document.location | user-provided value |
| tst15.js:4:23:4:55 | url.sub ... ring(1) | tst15.js:2:15:2:31 | document.location | tst15.js:4:23:4:55 | url.sub ... ring(1) | Untrusted URL redirection depends on a $@. | tst15.js:2:15:2:31 | document.location | user-provided value |
| tst15.js:5:23:5:73 | url.sub ... ring(1) | tst15.js:2:15:2:31 | document.location | tst15.js:5:23:5:73 | url.sub ... ring(1) | Untrusted URL redirection depends on a $@. | tst15.js:2:15:2:31 | document.location | user-provided value |
| tst15.js:8:23:8:60 | url2.su ... nown()) | tst15.js:7:16:7:32 | document.location | tst15.js:8:23:8:60 | url2.su ... nown()) | Untrusted URL redirection depends on a $@. | tst15.js:7:16:7:32 | document.location | user-provided value |
| tst15.js:9:23:9:64 | url2.su ... nown()) | tst15.js:7:16:7:32 | document.location | tst15.js:9:23:9:64 | url2.su ... nown()) | Untrusted URL redirection depends on a $@. | tst15.js:7:16:7:32 | document.location | user-provided value |
| tst15.js:10:23:10:83 | url2.su ... nown()) | tst15.js:7:16:7:32 | document.location | tst15.js:10:23:10:83 | url2.su ... nown()) | Untrusted URL redirection depends on a $@. | tst15.js:7:16:7:32 | document.location | user-provided value |
| tst15.js:13:23:13:54 | search. ... ring(1) | tst15.js:12:18:12:41 | documen ... .search | tst15.js:13:23:13:54 | search. ... ring(1) | Untrusted URL redirection depends on a $@. | tst15.js:12:18:12:41 | documen ... .search | user-provided value |
| tst15.js:14:23:14:58 | search. ... ring(1) | tst15.js:12:18:12:41 | documen ... .search | tst15.js:14:23:14:58 | search. ... ring(1) | Untrusted URL redirection depends on a $@. | tst15.js:12:18:12:41 | documen ... .search | user-provided value |
| tst15.js:15:23:15:79 | search. ... ring(1) | tst15.js:12:18:12:41 | documen ... .search | tst15.js:15:23:15:79 | search. ... ring(1) | Untrusted URL redirection depends on a $@. | tst15.js:12:18:12:41 | documen ... .search | user-provided value |
| tst.js:2:19:2:72 | /.*redi ... ref)[1] | tst.js:2:47:2:68 | documen ... on.href | tst.js:2:19:2:72 | /.*redi ... ref)[1] | Untrusted URL redirection depends on a $@. | tst.js:2:47:2:68 | documen ... on.href | user-provided value |
| tst.js:6:20:6:59 | indirec ... ref)[1] | tst.js:6:34:6:55 | documen ... on.href | tst.js:6:20:6:59 | indirec ... ref)[1] | Untrusted URL redirection depends on a $@. | tst.js:6:34:6:55 | documen ... on.href | user-provided value |
| tst.js:10:19:10:84 | new Reg ... ref)[1] | tst.js:10:59:10:80 | documen ... on.href | tst.js:10:19:10:84 | new Reg ... ref)[1] | Untrusted URL redirection depends on a $@. | tst.js:10:59:10:80 | documen ... on.href | user-provided value |

View File

@@ -0,0 +1,9 @@
import javascript
import semmle.javascript.security.dataflow.ClientSideUrlRedirectQuery
import testUtilities.ConsistencyChecking
deprecated class ClientSideUrlRedirectConsistency extends ConsistencyConfiguration {
ClientSideUrlRedirectConsistency() { this = "ClientSideUrlRedirectConsistency" }
override DataFlow::Node getAnAlert() { ClientSideUrlRedirectFlow::flowTo(result) }
}

View File

@@ -1,13 +1,13 @@
import React from "react";
import {Helmet} from "react-helmet";
class Application extends React.Component {
render () {
return (
<div className="application">
<Helmet>
<title>My unsafe app</title>
<script type="application/javascript" src={document.location.hash}/>
<script type="application/javascript" src={document.location.hash.substr(1)}/> {/* NOT OK */}
</Helmet>
</div>
);
@@ -18,28 +18,31 @@ export default Application
import Link from 'next/link'
export function NextLink() {
return <Link href={document.location.hash}><a>this page!</a></Link>;
return <>
<Link href={document.location.hash}><a>safe</a></Link> {/* OK */}
<Link href={document.location.hash.substr(1)}><a>unsafe</a></Link> {/* NOT OK */}
</>;
}
import { useRouter } from 'next/router'
export function nextRouter() {
const router = useRouter();
return <span onClick={() => router.push(document.location.hash.substr(1))}>Click to XSS 1</span>
return <span onClick={() => router.push(document.location.hash.substr(1))}>Click to XSS 1</span> // NOT OK
}
import { withRouter } from 'next/router'
function Page({ router }) {
return <span onClick={() => router.push(document.location.hash.substr(1))}>Click to XSS 2</span>
return <span onClick={() => router.push(document.location.hash.substr(1))}>Click to XSS 2</span> // NOT OK
}
export const pageWithRouter = withRouter(Page);
export function plainLink() {
return <a href={document.location.hash.substr(1)}>my plain link!</a>;
return <a href={document.location.hash.substr(1)}>my plain link!</a>; // NOT OK
}
export function someUnknown() {
return <FOO data={document.location.hash.substr(1)}>is safe.</FOO>;
}
return <FOO data={document.location.hash.substr(1)}>is safe.</FOO>; // OK
}

View File

@@ -0,0 +1,41 @@
import 'dummy';
function extractFromHash() {
const [, group1] = /#(.*)/.exec(window.location.href);
window.location.href = group1; // NOT OK
}
function extractFromQuery() {
const [, group1] = /\?(.*)/.exec(window.location.href);
window.location.href = group1; // NOT OK
}
function extractFromProtocol() {
const [, group1] = /^([a-z]+:)/.exec(window.location.href);
window.location.href = group1; // OK
}
function extractTooMuch() {
const [, group1] = /(.*)/.exec(window.location.href);
window.location.href = group1; // OK
}
function extractNothing() {
const [, group1] = /blah#baz/.exec(window.location.href);
window.location.href = group1; // OK
}
function extractWithMatch() {
const [, group1] = window.location.href.match(/#(.*)/);
window.location.href = group1; // NOT OK
}
function extractWithMatchAll() {
const [, group1] = window.location.href.matchAll(/#(.*)/)[0];
window.location.href = group1; // NOT OK
}
function extractFromUnknownRegExp() {
const [, group1] = new RegExp(unknown()).exec(window.location.href);
window.location.href = group1; // NOT OK
}

View File

@@ -26,4 +26,4 @@ function foo(win) {
win.location.assign(new RegExp(/.*redirect=([^&]*).*/).exec(win.location.href)[1]); // NOT OK
}
foo(window);
foo(window);

View File

@@ -1,14 +1,14 @@
// OK - cannot affect hostname
location.href = '/foo' + document.location.search;
location.href = '/foo' + document.location.search.substring(1);
// NOT OK
location.href = '/' + document.location.search;
location.href = '/' + document.location.search.substring(1);
// NOT OK
location.href = '//' + document.location.search;
location.href = '//' + document.location.search.substring(1);
// NOT OK
location.href = '//foo' + document.location.search;
location.href = '//foo' + document.location.search.substring(1);
// NOT OK
location.href = 'https://foo' + document.location.search;
location.href = 'https://foo' + document.location.search.substring(1);

View File

@@ -1,6 +1,5 @@
// NOT OK
function foo() {
var urlParts = window.location.hash.split('?');
var loc = urlParts[0] + "?" + boxes.value;
window.location = loc
window.location = loc; // OK - always starts with '#'
}

View File

@@ -1,48 +1,48 @@
function foo() {
var payload = document.location.search.substr(1);
var el = document.createElement("a");
el.href = payload;
document.body.appendChild(el); // NOT OK
el.href = payload; // NOT OK
document.body.appendChild(el);
var el = document.createElement("button");
el.formaction = payload;
document.body.appendChild(el); // NOT OK
el.formaction = payload; // NOT OK
document.body.appendChild(el);
var el = document.createElement("embed");
el.src = payload;
document.body.appendChild(el); // NOT OK
el.src = payload; // NOT OK
document.body.appendChild(el);
var el = document.createElement("form");
el.action = payload;
document.body.appendChild(el); // NOT OK
el.action = payload; // NOT OK
document.body.appendChild(el);
var el = document.createElement("frame");
el.src = payload;
document.body.appendChild(el); // NOT OK
el.src = payload; // NOT OK
document.body.appendChild(el);
var el = document.createElement("iframe");
el.src = payload;
document.body.appendChild(el); // NOT OK
el.src = payload; // NOT OK
document.body.appendChild(el);
var el = document.createElement("input");
el.formaction = payload;
document.body.appendChild(el); // NOT OK
el.formaction = payload; // NOT OK
document.body.appendChild(el);
var el = document.createElement("isindex");
el.action = payload;
document.body.appendChild(el); // NOT OK
el.action = payload; // NOT OK
document.body.appendChild(el);
var el = document.createElement("isindex");
el.formaction = payload;
document.body.appendChild(el); // NOT OK
el.formaction = payload; // NOT OK
document.body.appendChild(el);
var el = document.createElement("object");
el.data = payload;
document.body.appendChild(el); // NOT OK
el.data = payload; // NOT OK
document.body.appendChild(el);
var el = document.createElement("script");
el.src = payload;
document.body.appendChild(el); // NOT OK
el.src = payload; // NOT OK
document.body.appendChild(el);
}
(function () {

View File

@@ -1,8 +1,18 @@
function foo() {
var url = document.location.toString();
window.location = url.substring(0).substring(1); // OK
window.location = url.substring(0, 10).substring(1); // OK
window.location = url.substring(0, url.indexOf('/', 10)).substring(1); // OK
window.location = url.substring(0).substring(1); // OK [INCONSISTENCY] - but not important
window.location = url.substring(0, 10).substring(1); // OK [INCONSISTENCY]
window.location = url.substring(0, url.indexOf('/', 10)).substring(1); // OK [INCONSISTENCY]
var url2 = document.location.toString();
window.location = url2.substring(0).substring(unknown()); // NOT OK
window.location = url2.substring(0, 10).substring(unknown()); // NOT OK
window.location = url2.substring(0, url2.indexOf('/', 10)).substring(unknown()); // NOT OK
var search = document.location.search.toString();
window.location = search.substring(0).substring(1); // NOT OK
window.location = search.substring(0, 10).substring(1); // NOT OK
window.location = search.substring(0, search.indexOf('/', 10)).substring(1); // NOT OK
}
function bar() {

View File

@@ -1,5 +1,5 @@
// NOT OK
new Worker(document.location.search);
new Worker(document.location.search.substring(1));
// NOT OK
$("<script>").attr("src", document.location.search);
$("<script>").attr("src", document.location.search.substring(1));

View File

@@ -1,11 +1,11 @@
export class MyComponent {
componentDidMount() {
const { location }: { location: Location } = (this as any).props;
var params = location.search;
var params = location.search.substring(1);
this.doRedirect(params);
}
private doRedirect(redirectUri: string) {
window.location.replace(redirectUri);
window.location.replace(redirectUri); // NOT OK
}
}
@@ -17,16 +17,16 @@ export class MyTrackingComponent {
loc: location
};
var secondLoc = container.loc; // type-tracking step 1 - not the source
this.myIndirectRedirect(secondLoc);
this.myIndirectRedirect(secondLoc);
}
private myIndirectRedirect(loc) { // type-tracking step 2 - also not the source
this.doRedirect(loc.search);
this.doRedirect(loc.search.substring(1));
}
private doRedirect(redirectUri: string) {
window.location.replace(redirectUri);
window.location.replace(redirectUri); // NOT OK
}
}
@@ -38,21 +38,21 @@ export class WeirdTracking {
loc: location
};
var secondLoc = container.loc; // type-tracking step 1 - not the source
this.myIndirectRedirect(secondLoc);
this.myIndirectRedirect(secondLoc);
}
private myIndirectRedirect(loc) { // type-tracking step 2 - also not the source
const loc2 : Location = (loc as any).componentDidMount;
this.doRedirect(loc.search);
this.doRedirect2(loc2.search);
const loc2: Location = (loc as any).componentDidMount;
this.doRedirect(loc.search.substring(1));
this.doRedirect2(loc2.search.substring(1));
}
private doRedirect(redirectUri: string) {
window.location.replace(redirectUri); // NOT OK - and correctly flagged
window.location.replace(redirectUri); // NOT OK
}
private doRedirect2(redirectUri: string) {
window.location.replace(redirectUri); // NOT OK - and correctly flagged
window.location.replace(redirectUri); // NOT OK
}
}
}

View File

@@ -46,10 +46,10 @@ deprecated final private class Conf extends string {
}
/**
* A line-comment that asserts whether a result exists at that line or not.
* A comment that asserts whether a result exists at that line or not.
* Can optionally include `[INCONSISTENCY]` to indicate that a consistency issue is expected at the location
*/
private class AssertionComment extends LineComment {
private class AssertionComment extends Comment {
boolean shouldHaveAlert;
AssertionComment() {