mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
fix(scan): keep the field join's parameter seeds when a region's own parameters are not input
da0ee57 turned parameter sources off for the mapper's catch-all `function`
entries, and with them the field join's seeds, which read the same flag:
MW WP Form's CVE-2023-6559 ($this->Data, filled by a constructor) was lost
(10 -> 3). The field join now has its own request field,
`fieldParameterSources`, set by the old entry rule; a region's own
parameters follow the new one. Both known CVEs are found again (MW WP Form
10 -> 4, WP Statistics 39 -> 18, 91/91 and 774/774 completed). The dropped
findings sampled against their call sites all take internal values:
ExistTable('useronline'), wp_statistics_visit('today'), remove() on the
plugin's own temp directory, _render('text', ...).
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
da0ee576f8
commit
7bc7acbf52
@@ -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---")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user