mirror of
https://github.com/github/codeql.git
synced 2026-04-25 08:45:14 +02:00
Merge pull request #3197 from erik-krogh/NormalPathSanitizer
Approved by asgerf
This commit is contained in:
@@ -206,6 +206,20 @@ module TaintedPath {
|
||||
dstlabel.isNormalized()
|
||||
)
|
||||
or
|
||||
// foo.replace(/(\.\.\/)*/, "") and similar
|
||||
exists(DotDotSlashPrefixRemovingReplace call |
|
||||
src = call.getInput() and
|
||||
dst = call.getOutput()
|
||||
|
|
||||
// the 4 possible combinations of normalized + relative for `srclabel`, and the possible values for `dstlabel` in each case.
|
||||
srclabel.isNonNormalized() and srclabel.isRelative() // raw + relative -> any()
|
||||
or
|
||||
srclabel.isNormalized() and srclabel.isAbsolute() and srclabel = dstlabel // normalized + absolute -> normalized + absolute
|
||||
or
|
||||
srclabel.isNonNormalized() and srclabel.isAbsolute() and dstlabel.isAbsolute() // raw + absolute -> raw/normalized + absolute
|
||||
// normalized + relative -> none()
|
||||
)
|
||||
or
|
||||
// path.join()
|
||||
exists(DataFlow::CallNode join, int n |
|
||||
join = NodeJSLib::Path::moduleMember("join").getACall()
|
||||
|
||||
@@ -225,7 +225,8 @@ module TaintedPath {
|
||||
term.getAMatchedString() = "/" or
|
||||
term.getAMatchedString() = "." or
|
||||
term.getAMatchedString() = ".."
|
||||
)
|
||||
) and
|
||||
not this instanceof DotDotSlashPrefixRemovingReplace
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,6 +240,57 @@ module TaintedPath {
|
||||
DataFlow::Node getOutput() { result = output }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call that removes all instances of "../" in the prefix of the string.
|
||||
*/
|
||||
class DotDotSlashPrefixRemovingReplace extends DataFlow::CallNode {
|
||||
DataFlow::Node input;
|
||||
DataFlow::Node output;
|
||||
|
||||
DotDotSlashPrefixRemovingReplace() {
|
||||
this.getCalleeName() = "replace" and
|
||||
input = getReceiver() and
|
||||
output = this and
|
||||
exists(RegExpLiteral literal, RegExpTerm term |
|
||||
getArgument(0).getALocalSource().asExpr() = literal and
|
||||
(term instanceof RegExpStar or term instanceof RegExpPlus) and
|
||||
term.getChild(0) = getADotDotSlashMatcher()
|
||||
|
|
||||
literal.getRoot() = term
|
||||
or
|
||||
exists(RegExpSequence seq | seq.getNumChild() = 2 and literal.getRoot() = seq |
|
||||
seq.getChild(0) instanceof RegExpCaret and
|
||||
seq.getChild(1) = term
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the input path to be sanitized.
|
||||
*/
|
||||
DataFlow::Node getInput() { result = input }
|
||||
|
||||
/**
|
||||
* Gets the path where prefix "../" has been removed.
|
||||
*/
|
||||
DataFlow::Node getOutput() { result = output }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a RegExpTerm that matches a variation of "../".
|
||||
*/
|
||||
private RegExpTerm getADotDotSlashMatcher() {
|
||||
result.getAMatchedString() = "../"
|
||||
or
|
||||
exists(RegExpSequence seq | seq = result |
|
||||
seq.getChild(0).getConstantValue() = "." and
|
||||
seq.getChild(1).getConstantValue() = "." and
|
||||
seq.getAChild().getAMatchedString() = "/"
|
||||
)
|
||||
or
|
||||
exists(RegExpGroup group | result = group | group.getChild(0) = getADotDotSlashMatcher())
|
||||
}
|
||||
|
||||
/**
|
||||
* A call that removes all "." or ".." from a path, without also removing all forward slashes.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user