mirror of
https://github.com/github/codeql.git
synced 2026-05-02 20:25:13 +02:00
introduce model for JSON.stringify and similar libraries
This commit is contained in:
@@ -67,7 +67,7 @@ predicate isBackslashEscape(StringReplaceCall mce, DataFlow::RegExpLiteralNode r
|
||||
*/
|
||||
predicate allBackslashesEscaped(DataFlow::Node nd) {
|
||||
// `JSON.stringify` escapes backslashes
|
||||
nd = DataFlow::globalVarRef("JSON").getAMemberCall("stringify")
|
||||
nd instanceof JsonSerializeCall
|
||||
or
|
||||
// check whether `nd` itself escapes backslashes
|
||||
exists(DataFlow::RegExpLiteralNode rel | isBackslashEscape(nd, rel) |
|
||||
|
||||
@@ -34,6 +34,7 @@ import semmle.javascript.InclusionTests
|
||||
import semmle.javascript.JSDoc
|
||||
import semmle.javascript.JSON
|
||||
import semmle.javascript.JsonParsers
|
||||
import semmle.javascript.JsonSerializers
|
||||
import semmle.javascript.JSX
|
||||
import semmle.javascript.Lines
|
||||
import semmle.javascript.Locations
|
||||
|
||||
34
javascript/ql/src/semmle/javascript/JsonSerializers.qll
Normal file
34
javascript/ql/src/semmle/javascript/JsonSerializers.qll
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Provides classes for working with JSON serializers.
|
||||
*/
|
||||
|
||||
import javascript
|
||||
|
||||
/**
|
||||
* A call to a JSON serializer such as `JSON.stringify` or `require("util").inspect`.
|
||||
*/
|
||||
class JsonSerializeCall extends DataFlow::CallNode {
|
||||
JsonSerializeCall() {
|
||||
exists(DataFlow::SourceNode callee | this = callee.getACall() |
|
||||
callee = DataFlow::globalVarRef("JSON").getAPropertyRead("stringify") or
|
||||
callee = DataFlow::moduleMember("json3", "stringify") or
|
||||
callee =
|
||||
DataFlow::moduleImport(["json-stringify-safe", "json-stable-stringify", "stringify-object",
|
||||
"fast-json-stable-stringify", "fast-safe-stringify", "javascript-stringify",
|
||||
"js-stringify"]) or
|
||||
// require("util").inspect() and similar
|
||||
callee = DataFlow::moduleMember("util", "inspect") or
|
||||
callee = DataFlow::moduleImport(["pretty-format", "object-inspect"])
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data flow node holding the input object to be serialized.
|
||||
*/
|
||||
DataFlow::Node getInput() { result = getArgument(0) }
|
||||
|
||||
/**
|
||||
* Gets the data flow node holding the resulting string.
|
||||
*/
|
||||
DataFlow::SourceNode getOutput() { result = this }
|
||||
}
|
||||
@@ -543,8 +543,8 @@ module TaintTracking {
|
||||
/**
|
||||
* A taint propagating data flow edge arising from JSON unparsing.
|
||||
*/
|
||||
private class JsonStringifyTaintStep extends AdditionalTaintStep, DataFlow::MethodCallNode {
|
||||
JsonStringifyTaintStep() { this = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") }
|
||||
private class JsonStringifyTaintStep extends AdditionalTaintStep, DataFlow::CallNode {
|
||||
JsonStringifyTaintStep() { this instanceof JsonSerializeCall }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
pred = getArgument(0) and succ = this
|
||||
@@ -693,18 +693,6 @@ module TaintTracking {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A taint step through the Node.JS function `util.inspect(..)`.
|
||||
*/
|
||||
class UtilInspectTaintStep extends AdditionalTaintStep, DataFlow::InvokeNode {
|
||||
UtilInspectTaintStep() { this = DataFlow::moduleImport("util").getAMemberCall("inspect") }
|
||||
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
succ = this and
|
||||
this.getAnArgument() = pred
|
||||
}
|
||||
}
|
||||
|
||||
private module RegExpCaptureSteps {
|
||||
/** Gets a reference to a string derived from the most recent RegExp match, such as `RegExp.$1`. */
|
||||
private DataFlow::PropRead getAStaticCaptureRef() {
|
||||
|
||||
@@ -28,9 +28,7 @@ private class RemoteFlowPassword extends HeuristicSource, RemoteFlowSource {
|
||||
*/
|
||||
private class JSONStringifyAsCommandInjectionSource extends HeuristicSource,
|
||||
CommandInjection::Source {
|
||||
JSONStringifyAsCommandInjectionSource() {
|
||||
this = DataFlow::globalVarRef("JSON").getAMemberCall("stringify")
|
||||
}
|
||||
JSONStringifyAsCommandInjectionSource() { this instanceof JsonSerializeCall }
|
||||
|
||||
override string getSourceType() { result = "a string from JSON.stringify" }
|
||||
}
|
||||
|
||||
@@ -202,10 +202,9 @@ module CleartextLogging {
|
||||
exists(DataFlow::PropWrite write, DataFlow::PropRead read |
|
||||
read = write.getRhs()
|
||||
or
|
||||
exists(DataFlow::MethodCallNode stringify |
|
||||
stringify = write.getRhs() and
|
||||
stringify = DataFlow::globalVarRef("JSON").getAMethodCall("stringify") and
|
||||
stringify.getArgument(0) = read
|
||||
exists(JsonSerializeCall stringify |
|
||||
stringify.getOutput() = write.getRhs() and
|
||||
stringify.getInput() = read
|
||||
)
|
||||
|
|
||||
not exists(write.getPropertyName()) and
|
||||
|
||||
@@ -36,7 +36,7 @@ module ImproperCodeSanitization {
|
||||
* A call to `JSON.stringify()` seen as a source for improper code sanitization
|
||||
*/
|
||||
class JSONStringifyAsSource extends Source {
|
||||
JSONStringifyAsSource() { this = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") }
|
||||
JSONStringifyAsSource() { this instanceof JsonSerializeCall }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,8 +49,7 @@ module PostMessageStar {
|
||||
exists(DataFlow::InvokeNode toString | toString = trg |
|
||||
toString.(DataFlow::MethodCallNode).calls(src, "toString")
|
||||
or
|
||||
toString = DataFlow::globalVarRef("JSON").getAMemberCall("stringify") and
|
||||
src = toString.getArgument(0)
|
||||
src = toString.(JsonSerializeCall).getInput()
|
||||
) and
|
||||
inlbl instanceof PartiallyTaintedObject and
|
||||
outlbl.isTaint()
|
||||
|
||||
Reference in New Issue
Block a user