Skip to content

Commit 06d812a

Browse files
authored
Merge pull request #2556 from erik-krogh/RegexpVoidCxt
Approved by max-schaefer
2 parents 564013d + d1a77d6 commit 06d812a

File tree

3 files changed

+35
-5
lines changed

3 files changed

+35
-5
lines changed

javascript/ql/src/semmle/javascript/Regexp.qll

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,16 @@ class RegExpParseError extends Error, @regexp_parse_error {
798798
override string toString() { result = getMessage() }
799799
}
800800

801+
/**
802+
* Holds if `func` is a method defined on `String.prototype` with name `name`.
803+
*/
804+
private predicate isNativeStringMethod(Function func, string name) {
805+
exists(ExternalInstanceMemberDecl decl |
806+
decl.hasQualifiedName("String", name) and
807+
func = decl.getInit()
808+
)
809+
}
810+
801811
/**
802812
* Holds if `source` may be interpreted as a regular expression.
803813
*/
@@ -808,18 +818,23 @@ predicate isInterpretedAsRegExp(DataFlow::Node source) {
808818
source = DataFlow::globalVarRef("RegExp").getAnInvocation().getArgument(0)
809819
or
810820
// The argument of a call that coerces the argument to a regular expression.
811-
exists(MethodCallExpr mce, string methodName |
821+
exists(DataFlow::MethodCallNode mce, string methodName |
812822
mce.getReceiver().analyze().getAType() = TTString() and
813-
mce.getMethodName() = methodName
823+
mce.getMethodName() = methodName and
824+
not exists(Function func |
825+
func = mce.getACallee()
826+
|
827+
not isNativeStringMethod(func, methodName)
828+
)
814829
|
815-
methodName = "match" and source.asExpr() = mce.getArgument(0) and mce.getNumArgument() = 1
830+
methodName = "match" and source = mce.getArgument(0) and mce.getNumArgument() = 1
816831
or
817832
methodName = "search" and
818-
source.asExpr() = mce.getArgument(0) and
833+
source = mce.getArgument(0) and
819834
mce.getNumArgument() = 1 and
820835
// "search" is a common method name, and so we exclude chained accesses
821836
// because `String.prototype.search` returns a number
822-
not exists(PropAccess p | p.getBase() = mce)
837+
not exists(PropAccess p | p.getBase() = mce.getEnclosingExpr())
823838
)
824839
)
825840
}

javascript/ql/test/query-tests/Security/CWE-730/RegExpInjection.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,13 @@ app.get('/findKey', function(req, res) {
5050
URI(`${protocol}://${host}${path}`).search(input); // OK, but still flagged
5151
URI(`${protocol}://${host}${path}`).search(input).href(); // OK
5252
unknown.search(input).unknown; // OK
53+
54+
});
55+
56+
import * as Search from './search';
57+
58+
app.get('/findKey', function(req, res) {
59+
var key = req.param("key"), input = req.param("input");
60+
61+
Search.search(input); // OK!
5362
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module.someOtherExport = true;
2+
3+
4+
export function search(query) {
5+
// Do nothing!
6+
}

0 commit comments

Comments
 (0)