Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions javascript/ql/src/Security/CWE-020/MissingRegExpAnchor.ql
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,23 @@ import MissingRegExpAnchor::Make<TreeImpl, HostnameRegexp::Impl, Impl>

from DataFlow::Node nd, string msg
where
isUnanchoredHostnameRegExp(nd, msg)
or
isSemiAnchoredHostnameRegExp(nd, msg)
or
hasMisleadingAnchorPrecedence(nd, msg)
// isLineAnchoredHostnameRegExp is not used here, as it is not relevant to JS.
(
isUnanchoredHostnameRegExp(nd, msg)
or
isSemiAnchoredHostnameRegExp(nd, msg)
or
hasMisleadingAnchorPrecedence(nd, msg)
) and
// Exclude patterns used with .test() where unanchored alternatives are simple words
// (no dots), indicating intentional partial matching for role/type checks, not URL validation
not exists(DataFlow::MethodCallNode testCall |
testCall.getMethodName() = "test" and
nd.(DataFlow::RegExpCreationNode).getARegExpObject().flowsTo(testCall.getReceiver()) and
forall(RegExpTerm alt |
alt = nd.(DataFlow::RegExpCreationNode).getRoot().(RegExpAlt).getAChild() and
not alt.getAChild*() instanceof RegExpAnchor
|
not alt.getAChild*().(RegExpConstant).getValue().matches("%.%")
)
)
select nd, msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
(function() {
// GOOD: simple word alternation used with .test() for role checking
// These are intentional partial matches, not URL validation
var rolePattern = /^admin|user|guest/;
if (rolePattern.test(role)) { /* ... */ }

// BAD: hostname pattern with misleading anchor precedence
var urlCheck = /^https?:\/\/good.com|https?:\/\/evil.com/; // $ Alert
if (urlCheck.test(url)) { /* ... */ }
});
Loading