Skip to content

Commit 7c6e28d

Browse files
author
Esben Sparre Andreasen
committed
JS: introduce near-empty RegularExpressions.qll
1 parent 994fe1b commit 7c6e28d

File tree

3 files changed

+32
-31
lines changed

3 files changed

+32
-31
lines changed

javascript/ql/src/Security/CWE-020/IncompleteUrlRegExp.ql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
*/
1212

1313
import javascript
14-
import semmle.javascript.security.dataflow.RegExpInjection
1514

1615
module IncompleteUrlRegExpTracking {
1716

@@ -28,7 +27,7 @@ module IncompleteUrlRegExpTracking {
2827

2928
override
3029
predicate isSink(DataFlow::Node sink) {
31-
sink instanceof RegExpInjection::Sink
30+
isInterpretedAsRegExp(sink)
3231
}
3332

3433
}

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
/**
2-
* Provides classes for working with regular expression literals.
2+
* Provides classes for working with regular expressions.
33
*
4-
* Regular expressions are represented as an abstract syntax tree of regular expression
4+
* Regular expression literals are represented as an abstract syntax tree of regular expression
55
* terms.
66
*/
77

88
import javascript
9+
private import semmle.javascript.dataflow.InferredTypes
910

1011
/**
1112
* An element containing a regular expression term, that is, either
@@ -484,3 +485,27 @@ class RegExpParseError extends Error, @regexp_parse_error {
484485
result = getMessage()
485486
}
486487
}
488+
489+
/**
490+
* Holds if `source` may be interpreted as a regular expression.
491+
*/
492+
predicate isInterpretedAsRegExp(DataFlow::Node source) {
493+
// The first argument to an invocation of `RegExp` (with or without `new`).
494+
source = DataFlow::globalVarRef("RegExp").getAnInvocation().getArgument(0)
495+
or
496+
// The argument of a call that coerces the argument to a regular expression.
497+
exists(MethodCallExpr mce, string methodName |
498+
mce.getReceiver().analyze().getAType() = TTString() and
499+
mce.getMethodName() = methodName
500+
|
501+
(methodName = "match" and source.asExpr() = mce.getArgument(0) and mce.getNumArgument() = 1)
502+
or
503+
(
504+
methodName = "search" and
505+
source.asExpr() = mce.getArgument(0) and
506+
mce.getNumArgument() = 1 and
507+
// `String.prototype.search` returns a number, so exclude chained accesses
508+
not exists(PropAccess p | p.getBase() = mce)
509+
)
510+
)
511+
}

javascript/ql/src/semmle/javascript/security/dataflow/RegExpInjection.qll

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55

66
import javascript
7-
private import semmle.javascript.dataflow.InferredTypes
87

98
module RegExpInjection {
109
/**
@@ -51,36 +50,14 @@ module RegExpInjection {
5150
}
5251

5352
/**
54-
* The first argument to an invocation of `RegExp` (with or without `new`).
53+
* The source string of a regular expression.
5554
*/
56-
class RegExpObjectCreationSink extends Sink, DataFlow::ValueNode {
57-
RegExpObjectCreationSink() {
58-
this = DataFlow::globalVarRef("RegExp").getAnInvocation().getArgument(0)
55+
class RegularExpressionSourceAsSink extends Sink {
56+
RegularExpressionSourceAsSink() {
57+
isInterpretedAsRegExp(this)
5958
}
6059
}
6160

62-
/**
63-
* The argument of a call that coerces the argument to a regular expression.
64-
*/
65-
class RegExpObjectCoercionSink extends Sink {
66-
67-
RegExpObjectCoercionSink() {
68-
exists (MethodCallExpr mce, string methodName |
69-
mce.getReceiver().analyze().getAType() = TTString() and
70-
mce.getMethodName() = methodName |
71-
(methodName = "match" and this.asExpr() = mce.getArgument(0) and mce.getNumArgument() = 1) or
72-
(
73-
methodName = "search" and
74-
this.asExpr() = mce.getArgument(0) and
75-
mce.getNumArgument() = 1 and
76-
// `String.prototype.search` returns a number, so exclude chained accesses
77-
not exists(PropAccess p | p.getBase() = mce)
78-
)
79-
)
80-
}
81-
82-
}
83-
8461
/**
8562
* A call to a function whose name suggests that it escapes regular
8663
* expression meta-characters.

0 commit comments

Comments
 (0)