mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 11:49:28 +00:00
feat(model): v4 measured; a parameter-fed field becomes strong carried only when the exact flow confirms it
v4 (provenance split): pmpro 69 and wpstatistics 172 unchanged -- their tier-4 members are source-fed through same-file helpers that read the request; mwwpform 68 -> 248, because its CVE's region is fed by a constructor parameter, the shape the split demotes and the exact flow had put at 30. v5 asks the flow for exactly the parameter-fed fields a sink-bearing region reads, memoised per (family, file, field), and reports carriedBy for diagnosis. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
20d53f1c4d
commit
983eda5886
@@ -647,8 +647,24 @@
|
||||
// flow form was a wall. It puts `_delete_files()` (fed by `$this->attachments`) and `record()` (fed by
|
||||
// a filter) where their sources say, instead of one tier below every region with a `$_GET` in its own
|
||||
// body. Asked only where there is a sink to carry to, so a plugin's 21,000 tier-0 pairs pay nothing.
|
||||
val carriedKind = if (sinkList.nonEmpty && familyInRepo) strongest(List(fieldCarriedKind, hookCarriedKind)) else ""
|
||||
val carried = carriedKind.nonEmpty
|
||||
// Weak becomes strong only when the FLOW says so. A parameter-fed field is what every constructor
|
||||
// makes and what MW WP Form's `_delete_files()` is actually fed by; structure cannot tell the two
|
||||
// apart, the join can. So the exact form is asked here for exactly the parameter-fed fields a
|
||||
// sink-bearing region reads -- memoised per (family, file, field) for the batch -- and nowhere else.
|
||||
// That bounds the flow queries to the cases the structure could not settle, instead of the 1,040
|
||||
// sink-bearing pairs that did not finish in 1,800 s.
|
||||
val structuralKind = if (sinkList.nonEmpty && familyInRepo) strongest(List(fieldCarriedKind, hookCarriedKind)) else ""
|
||||
val carriedKind =
|
||||
if (structuralKind != "parameter") structuralKind
|
||||
else {
|
||||
val confirmed = cpg.call
|
||||
.nameExact(FIELD_ACCESS)
|
||||
.filter(c => inScope(c.method))
|
||||
.l
|
||||
.exists(r => prefixKind(r.code.trim, fedFields(r.method.filename)) == "parameter" && taintedPrefixes(r.code.trim, r.method.filename))
|
||||
if (confirmed) "source" else "parameter"
|
||||
}
|
||||
val carried = carriedKind.nonEmpty
|
||||
val summary = ujson.Obj(
|
||||
"kind" -> "summary",
|
||||
"sinks" -> sinkList.size,
|
||||
@@ -656,6 +672,7 @@
|
||||
"sourceNear" -> sourceNear,
|
||||
"carried" -> carried,
|
||||
"carriedKind" -> carriedKind,
|
||||
"carriedBy" -> (if (structuralKind.isEmpty) "" else if (fieldCarriedKind == structuralKind) "field" else "hook"),
|
||||
"familyInRepo" -> familyInRepo
|
||||
)
|
||||
val perSink = sinkList.map { sink =>
|
||||
|
||||
Reference in New Issue
Block a user