diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll index f8d5c798e1e..b1ff0edbbd8 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ClientSideUrlRedirectCustomizations.qll @@ -51,9 +51,7 @@ module ClientSideUrlRedirect { exists(MethodCallExpr mce, string methodName | mce = queryAccess.asExpr() and mce.calls(nd.asExpr(), methodName) | - methodName = "split" and - // exclude `location.href.split('?')[0]`, which can never refer to the query string - not exists(PropAccess pacc | mce = pacc.getBase() | pacc.getPropertyName() = "0") + methodName = "split" or (methodName = "substring" or methodName = "substr" or methodName = "slice") and // exclude `location.href.substring(0, ...)` and similar, which can @@ -68,6 +66,23 @@ module ClientSideUrlRedirect { ) } + /** + * A sanitizer that reads the first part a location split by "?", e.g. `location.href.split('?')[0]`. + */ + class QueryPrefixSanitizer extends Sanitizer { + DataFlow::PropRead read; + + QueryPrefixSanitizer() { + this = read and + read.getPropertyName() = "0" and + exists(DataFlow::MethodCallNode splitCall | splitCall = read.getBase().getALocalSource() | + splitCall.getMethodName() = "split" and + splitCall.getArgument(0).mayHaveStringValue("?") and + splitCall.getReceiver() = [DOM::locationRef(), DOM::locationRef().getAPropertyRead("href")] + ) + } + } + /** * A sink which is used to set the window location. */