Skip to content

Commit 07d508d

Browse files
committed
JS: Track taint through .replace()
1 parent 1ec3475 commit 07d508d

File tree

3 files changed

+33
-0
lines changed

3 files changed

+33
-0
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,19 @@ module TaintedPath {
369369
input = getAnArgument() and
370370
output = this
371371
)
372+
or
373+
// non-global replace or replace of something other than /\.\./g
374+
this.getCalleeName() = "replace" and
375+
input = getReceiver() and
376+
output = this and
377+
not exists(RegExpLiteral literal, RegExpSequence seq |
378+
getArgument(0).asExpr() = literal and
379+
literal.isGlobal() and
380+
literal.getRoot() = seq and
381+
seq.getChild(0).(RegExpConstant).getValue() = "." and
382+
seq.getChild(1).(RegExpConstant).getValue() = "." and
383+
seq.getNumChild() = 2
384+
)
372385
}
373386

374387
/**

javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,11 @@ nodes
239239
| normalizedPaths.js:219:29:219:32 | path |
240240
| normalizedPaths.js:219:29:219:32 | path |
241241
| normalizedPaths.js:222:18:222:21 | path |
242+
| normalizedPaths.js:226:9:226:72 | path |
243+
| normalizedPaths.js:226:16:226:51 | pathMod ... y.path) |
244+
| normalizedPaths.js:226:16:226:72 | pathMod ... g, ' ') |
245+
| normalizedPaths.js:226:37:226:50 | req.query.path |
246+
| normalizedPaths.js:228:22:228:25 | path |
242247
| tainted-array-steps.js:9:7:9:48 | path |
243248
| tainted-array-steps.js:9:14:9:37 | url.par ... , true) |
244249
| tainted-array-steps.js:9:14:9:43 | url.par ... ).query |
@@ -707,6 +712,10 @@ edges
707712
| normalizedPaths.js:219:10:219:33 | decodeU ... t(path) | normalizedPaths.js:219:10:219:33 | decodeU ... t(path) |
708713
| normalizedPaths.js:219:29:219:32 | path | normalizedPaths.js:219:10:219:33 | decodeU ... t(path) |
709714
| normalizedPaths.js:219:29:219:32 | path | normalizedPaths.js:219:10:219:33 | decodeU ... t(path) |
715+
| normalizedPaths.js:226:9:226:72 | path | normalizedPaths.js:228:22:228:25 | path |
716+
| normalizedPaths.js:226:16:226:51 | pathMod ... y.path) | normalizedPaths.js:226:16:226:72 | pathMod ... g, ' ') |
717+
| normalizedPaths.js:226:16:226:72 | pathMod ... g, ' ') | normalizedPaths.js:226:9:226:72 | path |
718+
| normalizedPaths.js:226:37:226:50 | req.query.path | normalizedPaths.js:226:16:226:51 | pathMod ... y.path) |
710719
| tainted-array-steps.js:9:7:9:48 | path | tainted-array-steps.js:11:40:11:43 | path |
711720
| tainted-array-steps.js:9:7:9:48 | path | tainted-array-steps.js:13:26:13:29 | path |
712721
| tainted-array-steps.js:9:14:9:37 | url.par ... , true) | tainted-array-steps.js:9:14:9:43 | url.par ... ).query |
@@ -858,6 +867,7 @@ edges
858867
| normalizedPaths.js:210:18:210:31 | normalizedPath | normalizedPaths.js:174:14:174:27 | req.query.path | normalizedPaths.js:210:18:210:31 | normalizedPath | This path depends on $@. | normalizedPaths.js:174:14:174:27 | req.query.path | a user-provided value |
859868
| normalizedPaths.js:210:18:210:31 | normalizedPath | normalizedPaths.js:174:14:174:27 | req.query.path | normalizedPaths.js:210:18:210:31 | normalizedPath | This path depends on $@. | normalizedPaths.js:174:14:174:27 | req.query.path | a user-provided value |
860869
| normalizedPaths.js:222:18:222:21 | path | normalizedPaths.js:214:35:214:48 | req.query.path | normalizedPaths.js:222:18:222:21 | path | This path depends on $@. | normalizedPaths.js:214:35:214:48 | req.query.path | a user-provided value |
870+
| normalizedPaths.js:228:22:228:25 | path | normalizedPaths.js:226:37:226:50 | req.query.path | normalizedPaths.js:228:22:228:25 | path | This path depends on $@. | normalizedPaths.js:226:37:226:50 | req.query.path | a user-provided value |
861871
| tainted-array-steps.js:11:29:11:54 | ['publi ... in('/') | tainted-array-steps.js:9:24:9:30 | req.url | tainted-array-steps.js:11:29:11:54 | ['publi ... in('/') | This path depends on $@. | tainted-array-steps.js:9:24:9:30 | req.url | a user-provided value |
862872
| tainted-array-steps.js:15:29:15:43 | parts.join('/') | tainted-array-steps.js:9:24:9:30 | req.url | tainted-array-steps.js:15:29:15:43 | parts.join('/') | This path depends on $@. | tainted-array-steps.js:9:24:9:30 | req.url | a user-provided value |
863873
| tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | tainted-require.js:7:19:7:37 | req.param("module") | This path depends on $@. | tainted-require.js:7:19:7:37 | req.param("module") | a user-provided value |

javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,13 @@ app.get('/decode-after-normalization', (req, res) => {
221221
if (!pathModule.isAbsolute(path) && !path.startsWith('..'))
222222
res.sendFile(path); // NOT OK - not normalized
223223
});
224+
225+
app.get('/replace', (req, res) => {
226+
let path = pathModule.normalize(req.query.path).replace(/%20/g, ' ');
227+
if (!pathModule.isAbsolute(path)) {
228+
res.sendFile(path); // NOT OK
229+
230+
path = path.replace(/\.\./g, '');
231+
res.sendFile(path); // OK
232+
}
233+
});

0 commit comments

Comments
 (0)