-
Notifications
You must be signed in to change notification settings - Fork 1.8k
JS: add sanitizer for relative ".." in js/path-injection #2846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice. I think we can generalise this a bit more.
(The unrelated formatting and feature addition should have gone into a separate commit or PR IMO)
relativeCall = DataFlow::moduleImport("path").getAMemberCall("relative") and | ||
startsWith.getBaseString().getALocalSource() = relativeCall and | ||
exists(DataFlow::Node subString | subString = startsWith.getSubstring() | | ||
subString.mayHaveStringValue("..") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and below. Lets support the "../"
prefixes as well.
} | ||
|
||
/** | ||
* A data flow sink for tainted-path vulnerabilities. | ||
*/ | ||
abstract class Sink extends DataFlow::Node { | ||
Sink() { not this instanceof Sanitizer } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems out of place for this PR, and if we want it, then it is perhaps something that should be implemented in Configuration.qll
as something like isReallySink(Node sink) { isSink(sink) and not isBarrier(sink) }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was part of my testing for the PR and it should have been removed, but I forgot.
} | ||
|
||
let newpath = pathModule.normalize(p); | ||
var relativePath = path.relative(path.normalize(workspaceDir), newpath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In QL, do we want to support the pattern of path.normalize(path.relative(x, newpath));
? Programmers may want to be extra safe that they are doing the right thing, so the redundancy is not completely unrealistic IMO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't find anyone using that pattern, but it doesn't sound unreasonable, so I added support for it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice!
This sanitizer does not work with Windows drive letters
That's fine. This query deliberately does not deal with Window-specific path problems. My take is that we should handle Windows-specific issues in a separate query so it can easily be disabled for codebases that don't support Windows anyway.
| | ||
subString.mayHaveStringValue(prefix) | ||
or | ||
subString.(StringOps::ConcatenationRoot).getFirstLeaf().mayHaveStringValue(prefix) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we use isDotDotSlashPrefix
here, like in StartsWithDotDotSanitizer
?
@@ -355,6 +351,47 @@ module TaintedPath { | |||
} | |||
} | |||
|
|||
/** | |||
* A sanitizer that recognizes the following pattern: | |||
* var relative = path.relative(webroot, pathname); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add triple backticks around the code block.
|
||
RelativePathContainsDotDotGuard() { | ||
this = startsWith and | ||
relativeCall = DataFlow::moduleImport("path").getAMemberCall("relative") and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use NodeJSLib::Path::moduleMember("relative")
instead
} | ||
|
||
override predicate blocks(boolean outcome, Expr e) { | ||
e = relativeCall.getArgument(1).asExpr() and outcome = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
StartsWith checks have a polarity, so we need to check that here:
outcome = startsWith.getPolarity().booleanNot()
Could you also add a test that uses a negative starts-with check:
if (x.indexOf(y)) { ... } else { sanitized }
* // pathname is safe | ||
* } | ||
*/ | ||
class RelativePathContainsDotDotGuard extends DataFlow::BarrierGuardNode { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RelativePathContainsDotDotGuard
-> RelativePathStartsWithDotDotSanitizer
The other guards are called Sanitizer
so we might as well be consistent, and this handles StartsWith
checks, not inclusion checks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, sorry for not following up earlier.
LGTM now, but will unfortunately need conflict resolution now.
@esbena any more comments? (you're still requesting changes) |
This PR adds the following sanitizer in
js/path-injection
:This sanitizer does not work with Windows drive letters (a relative path from
C:\foo\bar
toD:\baz\bla
is justD:\baz\bla
). But I still think it is good enough for us to use it as a sanitizer.The sanitizer is used in the fix for CVE-2018-3787, and adding the sanitizer fixes all the new FPs that arose as part of #2810.
An evaluation look OK performance wise .