Skip to content

Commit b020044

Browse files
committed
prune results that end with newline, where the input cannot contain newlines
1 parent ebc4856 commit b020044

File tree

5 files changed

+38
-2
lines changed

5 files changed

+38
-2
lines changed

javascript/ql/src/Performance/PolynomialReDoS.ql

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,15 @@
1414

1515
import javascript
1616
import semmle.javascript.security.performance.PolynomialReDoS::PolynomialReDoS
17+
import semmle.javascript.security.performance.SuperlinearBackTracking
1718
import DataFlow::PathGraph
1819

1920
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
20-
where cfg.hasFlowPath(source, sink)
21+
where
22+
cfg.hasFlowPath(source, sink) and
23+
not (
24+
source.getNode().(Source).getKind() = "url" and
25+
sink.getNode().(Sink).getRegExp().(PolynomialBackTrackingTerm).isAtEndLine()
26+
)
2127
select sink.getNode(), source, sink, "This expensive $@ use depends on $@.",
2228
sink.getNode().(Sink).getRegExp(), "regular expression", source.getNode(), "a user-provided value"

javascript/ql/src/semmle/javascript/security/performance/PolynomialReDoSCustomizations.qll

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ module PolynomialReDoS {
1111
/**
1212
* A data flow source node for polynomial regular expression denial-of-service vulnerabilities.
1313
*/
14-
abstract class Source extends DataFlow::Node { }
14+
abstract class Source extends DataFlow::Node {
15+
/**
16+
* Gets the kind of source that is being accesed. See `HTTP::RequestInputAccess::getKind()`.
17+
* Can be one of "parameter", "header", "body", "url", "cookie".
18+
*/
19+
abstract string getKind();
20+
}
1521

1622
/**
1723
* A data flow sink node for polynomial regular expression denial-of-service vulnerabilities.
@@ -31,6 +37,10 @@ module PolynomialReDoS {
3137
*/
3238
class RequestInputAccessAsSource extends Source {
3339
RequestInputAccessAsSource() { this instanceof HTTP::RequestInputAccess }
40+
41+
override string getKind() {
42+
result = this.(HTTP::RequestInputAccess).getKind()
43+
}
3444
}
3545

3646
/**

javascript/ql/src/semmle/javascript/security/performance/SuperlinearBackTracking.qll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,15 @@ class PolynomialBackTrackingTerm extends InfiniteRepetitionQuantifier {
146146
not this.getParent*() instanceof RegExpSubPattern // too many corner cases
147147
}
148148

149+
/**
150+
* Holds if all non-empty successors to the polynimial backtracking term matches the end of the line.
151+
*/
152+
predicate isAtEndLine() {
153+
forall(RegExpTerm succ | this.getSuccessor+() = succ and not matchesEpsilon(succ) |
154+
succ instanceof RegExpDollar
155+
)
156+
}
157+
149158
/**
150159
* Gets the reason for the number of match attempts.
151160
*/

javascript/ql/test/query-tests/Performance/ReDoS/PolynomialReDoS.expected

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ nodes
6666
| polynomial-redos.js:66:19:66:25 | tainted |
6767
| polynomial-redos.js:67:18:67:24 | tainted |
6868
| polynomial-redos.js:67:18:67:24 | tainted |
69+
| polynomial-redos.js:68:18:68:24 | req.url |
70+
| polynomial-redos.js:68:18:68:24 | req.url |
71+
| polynomial-redos.js:68:18:68:24 | req.url |
72+
| polynomial-redos.js:69:18:69:25 | req.body |
73+
| polynomial-redos.js:69:18:69:25 | req.body |
74+
| polynomial-redos.js:69:18:69:25 | req.body |
6975
edges
7076
| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:7:2:7:8 | tainted |
7177
| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:7:2:7:8 | tainted |
@@ -133,6 +139,8 @@ edges
133139
| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:67:18:67:24 | tainted |
134140
| polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:5:6:5:32 | tainted |
135141
| polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:5:6:5:32 | tainted |
142+
| polynomial-redos.js:68:18:68:24 | req.url | polynomial-redos.js:68:18:68:24 | req.url |
143+
| polynomial-redos.js:69:18:69:25 | req.body | polynomial-redos.js:69:18:69:25 | req.body |
136144
#select
137145
| polynomial-redos.js:7:2:7:8 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:7:2:7:8 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:7:24:7:26 | \\s+ | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |
138146
| polynomial-redos.js:8:2:8:8 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:8:2:8:8 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:8:17:8:18 | * | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |
@@ -170,3 +178,4 @@ edges
170178
| polynomial-redos.js:65:24:65:30 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:65:24:65:30 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:65:14:65:15 | .* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |
171179
| polynomial-redos.js:66:19:66:25 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:66:19:66:25 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:66:9:66:10 | .* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |
172180
| polynomial-redos.js:67:18:67:24 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:67:18:67:24 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:67:8:67:9 | .* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |
181+
| polynomial-redos.js:69:18:69:25 | req.body | polynomial-redos.js:69:18:69:25 | req.body | polynomial-redos.js:69:18:69:25 | req.body | This expensive $@ use depends on $@. | polynomial-redos.js:69:8:69:9 | .* | regular expression | polynomial-redos.js:69:18:69:25 | req.body | a user-provided value |

javascript/ql/test/query-tests/Performance/ReDoS/polynomial-redos.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,6 @@ app.use(function(req, res) {
6565
(/^foo(K|Y)+.*X/.test(tainted)); // NOT OK
6666
(/(K|Y).*X/.test(tainted)); // NOT OK
6767
(/[^Y].*X/.test(tainted)); // NOT OK
68+
(/[^Y].*$/.test(req.url)); // OK - the input cannot contain newlines.
69+
(/[^Y].*$/.test(req.body)); // NOT OK
6870
});

0 commit comments

Comments
 (0)