@@ -12,19 +12,15 @@ module TaintedPath {
12
12
*/
13
13
abstract class Source extends DataFlow:: Node {
14
14
/** Gets a flow label denoting the type of value for which this is a source. */
15
- DataFlow:: FlowLabel getAFlowLabel ( ) {
16
- result instanceof Label:: PosixPath
17
- }
15
+ DataFlow:: FlowLabel getAFlowLabel ( ) { result instanceof Label:: PosixPath }
18
16
}
19
17
20
18
/**
21
19
* A data flow sink for tainted-path vulnerabilities.
22
20
*/
23
21
abstract class Sink extends DataFlow:: Node {
24
22
/** Gets a flow label denoting the type of value for which this is a sink. */
25
- DataFlow:: FlowLabel getAFlowLabel ( ) {
26
- result instanceof Label:: PosixPath
27
- }
23
+ DataFlow:: FlowLabel getAFlowLabel ( ) { result instanceof Label:: PosixPath }
28
24
}
29
25
30
26
/**
@@ -364,6 +360,42 @@ module TaintedPath {
364
360
}
365
361
}
366
362
363
+ /**
364
+ * A sanitizer that recognizes the following pattern:
365
+ * ```
366
+ * var relative = path.relative(webroot, pathname);
367
+ * if(relative.startsWith(".." + path.sep) || relative == "..") {
368
+ * // pathname is unsafe
369
+ * } else {
370
+ * // pathname is safe
371
+ * }
372
+ * ```
373
+ */
374
+ class RelativePathStartsWithDotDotSanitizer extends DataFlow:: BarrierGuardNode {
375
+ StringOps:: StartsWith startsWith ;
376
+ DataFlow:: CallNode relativeCall ;
377
+
378
+ RelativePathStartsWithDotDotSanitizer ( ) {
379
+ this = startsWith and
380
+ relativeCall = NodeJSLib:: Path:: moduleMember ( "relative" ) .getACall ( ) and
381
+ (
382
+ startsWith .getBaseString ( ) .getALocalSource ( ) = relativeCall
383
+ or
384
+ startsWith
385
+ .getBaseString ( )
386
+ .getALocalSource ( )
387
+ .( NormalizingPathCall )
388
+ .getInput ( )
389
+ .getALocalSource ( ) = relativeCall
390
+ ) and
391
+ isDotDotSlashPrefix ( startsWith .getSubstring ( ) )
392
+ }
393
+
394
+ override predicate blocks ( boolean outcome , Expr e ) {
395
+ e = relativeCall .getArgument ( 1 ) .asExpr ( ) and outcome = startsWith .getPolarity ( ) .booleanNot ( )
396
+ }
397
+ }
398
+
367
399
/**
368
400
* A guard node for a variable in a negative condition, such as `x` in `if(!x)`.
369
401
*/
@@ -443,9 +475,7 @@ module TaintedPath {
443
475
* A path argument to a file system access, which disallows upward navigation.
444
476
*/
445
477
private class FsPathSinkWithoutUpwardNavigation extends FsPathSink {
446
- FsPathSinkWithoutUpwardNavigation ( ) {
447
- fileSystemAccess .isUpwardNavigationRejected ( this )
448
- }
478
+ FsPathSinkWithoutUpwardNavigation ( ) { fileSystemAccess .isUpwardNavigationRejected ( this ) }
449
479
450
480
override DataFlow:: FlowLabel getAFlowLabel ( ) {
451
481
// The protection is ineffective if the ../ segments have already
0 commit comments