diff --git a/javascript/ql/lib/semmle/javascript/security/regexp/HostnameRegexp.qll b/javascript/ql/lib/semmle/javascript/security/regexp/HostnameRegexp.qll index c9853ce35f1..c59f1459544 100644 --- a/javascript/ql/lib/semmle/javascript/security/regexp/HostnameRegexp.qll +++ b/javascript/ql/lib/semmle/javascript/security/regexp/HostnameRegexp.qll @@ -12,7 +12,19 @@ private import codeql.regex.HostnameRegexp as Shared module Impl implements Shared::HostnameRegexpSig { class DataFlowNode = JS::DataFlow::Node; - class RegExpPatternSource = RegExp::RegExpPatternSource; + class RegExpPatternSource extends JS::DataFlow::Node instanceof RegExp::RegExpPatternSource { + RegExpPatternSource() { + not super.escapes(_) + } + + RegExp::RegExpTerm getRegExpTerm() { + result = super.getRegExpTerm() + } + + JS::DataFlow::Node getAParse() { + result = super.getAParse() + } + } } import Shared::Make diff --git a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.js b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.js index ddc267ebdd7..308d935d505 100644 --- a/javascript/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.js +++ b/javascript/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.js @@ -57,4 +57,9 @@ /^http:\/\/(..|...)\.example\.com\/index\.html/; // OK, wildcards are intentional /^http:\/\/.\.example\.com\/index\.html/; // OK, the wildcard is intentional /^(foo.example\.com|whatever)$/; // kinda OK - one disjunction doesn't even look like a hostname + + function makeHostnameRegExp(hostname) { + return new RegExp(`^https://${hostname.replace(/[\.\\]/g, '\\$&')}$`); + } + makeHostnameRegExp('test.example.com'); // OK });