diff --git a/src/openultrasast/cpg/queries/taint.sc b/src/openultrasast/cpg/queries/taint.sc index 49e73ff..0a6b26f 100644 --- a/src/openultrasast/cpg/queries/taint.sc +++ b/src/openultrasast/cpg/queries/taint.sc @@ -93,6 +93,7 @@ dispatchApplyS: String, functionS: String, paramSrc: String, + fieldParamSrc: String, fieldSrc: String, evidenceS: String, fileS: String, @@ -358,19 +359,19 @@ // reason: an arbitrary helper's parameters carry whatever its caller happened to have. def seedsIn(fileName: String) = seedsByFile.getOrElseUpdate( - (sourcesS, paramSrc, fileName), { + (sourcesS, fieldParamSrc, fileName), { val methods = methodsIn(fileName) val framework: List[io.shiftleft.codepropertygraph.generated.nodes.CfgNode] = methods.flatMap(_.ast.isCall.filter(c => sourcePatterns.exists(p => c.code.contains(p))).l) val params: List[io.shiftleft.codepropertygraph.generated.nodes.CfgNode] = - if (parameterSources == "true") methods.flatMap(_.parameter.l) else Nil + if (fieldParamSrc == "true") methods.flatMap(_.parameter.l) else Nil framework ++ params } ) def fieldIsTainted(fileName: String, fieldCode: String): Boolean = fieldTaintMemo.getOrElseUpdate( - (sourcesS, paramSrc, sanitizersS, fileName, fieldCode), { + (sourcesS, fieldParamSrc, sanitizersS, fileName, fieldCode), { val seeds = seedsIn(fileName) if (seeds.isEmpty) false else @@ -1025,6 +1026,7 @@ val started = System.nanoTime() def field(name: String): String = req.obj.get(name).map(_.str).getOrElse("") val paramSrc = req.obj.get("parameterSources").map(_.str).getOrElse("false") + val fieldParamSrc = req.obj.get("fieldParameterSources").map(_.str).getOrElse(paramSrc) val fieldSrc = req.obj.get("fieldSources").map(_.str).getOrElse("true") val evidence = req.obj.get("evidenceOnly").map(_.str).getOrElse("false") val rows = ujson.Arr( @@ -1039,6 +1041,7 @@ if (field("dispatchApply").nonEmpty) field("dispatchApply") else dispatchApply, field("function"), paramSrc, + fieldParamSrc, fieldSrc, evidence, field("file"), @@ -1060,7 +1063,7 @@ } else { println("---OUSAST-CPG-BEGIN---") println( - ujson.write(ujson.Arr(rowsFor(sources, sinks, sanitizers, hookCallbacks, dispatchApply, function, parameterSources, fieldSources, evidenceOnly, file, callDepth, boundedSinks): _*)) + ujson.write(ujson.Arr(rowsFor(sources, sinks, sanitizers, hookCallbacks, dispatchApply, function, parameterSources, parameterSources, fieldSources, evidenceOnly, file, callDepth, boundedSinks): _*)) ) } println("---OUSAST-CPG-END---") diff --git a/src/openultrasast/model/scan.py b/src/openultrasast/model/scan.py index 708ef7b..c5dbc1e 100644 --- a/src/openultrasast/model/scan.py +++ b/src/openultrasast/model/scan.py @@ -1459,6 +1459,7 @@ def _grouped( parameter_sources=_parameters_are_input(region), call_depth=ENTRY_POINT_CALL_DEPTH if entry else 0, hook_callbacks=hook_callbacks, + field_parameter_sources=entry, ), ) grouped.setdefault(kind, {})[rid] = params diff --git a/src/openultrasast/model/taint.py b/src/openultrasast/model/taint.py index 15fd6ee..b1a612c 100644 --- a/src/openultrasast/model/taint.py +++ b/src/openultrasast/model/taint.py @@ -27,6 +27,7 @@ def request_params( parameter_sources: bool = False, call_depth: int = 0, hook_callbacks: str = "", + field_parameter_sources: bool | None = None, ) -> dict[str, object]: """The query parameters this arbiter sends. Shared with the batcher so there is one definition, not two. @@ -45,6 +46,10 @@ def request_params( "function": function, "file": file, "parameterSources": "true" if parameter_sources else "false", + # The FIELD join's parameter seeds, apart from the region's own parameters: a constructor handed the + # uploads stores them in a field another method reads (MW WP Form, CVE-2023-6559), whatever kind of + # entry the reading method is. Defaults to the region's own rule, so a caller that sets one sets both. + "fieldParameterSources": "true" if (parameter_sources if field_parameter_sources is None else field_parameter_sources) else "false", "callDepth": str(call_depth), "boundedSinks": spec.bounded_sinks, # The hook link table, `hook:callback;hook:callback`. Read out of the source text rather than the