Notebook · 2026-06-11 · rev. 2026-06-12
Incomplete-fix siblings on the AI and agent surface: a class-agnostic sibling-diff detection method and a public instance index
A reproducible sibling-diff and incomplete-fix procedure, and a mapped corpus, for the residual a security patch leaves behind on the fresh AI, agent, and MCP application surface. These are not new bug classes. They are already-named ones (CWE-918 SSRF, OWASP API1/API5:2023 and CWE-284/285/862/863/639 for authorization, CWE-79 for XSS, the confused deputy, MITRE ATLAS AML.T0053); the contribution is the systematization across them, a runtime oracle, and a measured loss, with the case studies linked as instances.
What this page is
This is the connective spine for work that already exists: a cross-user confused deputy in GitHub's own MCP server, a grant that skipped dex's connector allow-list, and a measurement essay that asks whether the method beats a naive frontier-model call, alongside the public disclosure corpus on the home page. This page does not re-derive their code or re-run their experiments. It states the detection method as a reproducible procedure, a taxonomy of its sub-patterns, and a public index of live-published instances mapped onto recognized labels. The unifying thread is the method, not a single vulnerability class: the same sibling-diff procedure produced findings across server-side request forgery, authorization, auth-bypass, and cross-site scripting. The case studies are the instances; this is the systematization.
The classes, and the honest framing (prior art)
Nothing on this page is a new vulnerability class. A patch for an authorization, request-forgery, or injection bug routinely closes one sink, route, or resource while a sibling path to the same dangerous action survives. That residual, the incomplete-fix sibling, belongs to whichever class the original bug did: a redirect followed without re-validation is SSRF; a check skipped on one dispatch path is authorization-confusion or a confused deputy; an input that reaches a dangerous sink on an unguarded peer is injection. The honest framing is the one Orange Tsai used for SSRF: he did not invent SSRF; his contribution was the definitive systematization of an inconsistency that was already known. The contribution here is the same shape, a reproducible method plus a public corpus and a measured baseline, not the invention of a class. The established labels the instances map onto:
- OWASP API1:2023, Broken Object Level Authorization (BOLA): an attacker manipulates object identifiers to reach objects belonging to other principals. The cross-user variant of this class is a BOLA at the dispatch layer.
- OWASP API5:2023, Broken Function Level Authorization (BFLA): a caller reaches a function or action they should not be authorized to invoke; the fix is deny-by-default with explicit grants. The missing-guard variant maps here.
- CWE-284 Improper Access Control (the broad parent), CWE-285 Improper Authorization (a check absent or performed incorrectly, the broad authorization parent, with CWE-862 Missing Authorization (a check absent entirely) and CWE-863 Incorrect Authorization (a check performed but performed wrong) as its missing/incorrect children), and CWE-639 Authorization Bypass Through User-Controlled Key (the IDOR-style key swap).
- CWE-918 Server-Side Request Forgery (a server is induced to make a request to an attacker-chosen destination) and CWE-79 Cross-site Scripting (improper neutralization of input rendered into a page): the request-forgery and injection labels the SSRF and XSS instances below map onto, reached here as incomplete-fix siblings of a prior patch.
- The confused deputy itself: Norman Hardy's 1988 note describing a privileged program tricked into misusing its authority on behalf of a less-privileged caller. That is the root concept, and the cross-user instance is a literal one.
- MITRE ATLAS AML.T0053, AI Agent Tool Invocation: an adversary uses access to an AI agent to invoke tools the agent can reach, including tools not directly accessible to users, to gain increased privilege or data access. The note about tools the user cannot reach directly is exactly the dispatch-layer authorization surface this method targets.
To be explicit about provenance: ATLAS AML.T0053 is cited under its current MITRE canonical name, AI Agent Tool Invocation; an older mirror labeled the same identifier differently before a 2025 rename, and the canonical name is the one used here. The CWE titles are quoted without their live version suffixes. None of these is asserted beyond what its primary source says.
The detection method
The procedure is deliberately cheap to run and front-loaded with kill gates, so that most candidates die before any proof-of-concept work begins. It has three parts: a starting move, a sequence of gates, and a two-tier oracle.
STEP-0, the sibling-diff. Start from a recently-merged security fix on a fresh, recognizable target, and enumerate the recently-shipped, security-relevant surfaces around it. For each candidate action, find the sibling path that already enforces the invariant the candidate appears to be missing, decide on the wrong identity, or reuse. Then diff them. The sibling is the control: a peer handler that does the right thing makes the deviation legible and tells you what the correct check looks like. If there is no sibling that enforces it, the surface is probably uniformly missing the check (a different, simpler finding) or the check genuinely lives elsewhere.
Cheap-kill gates, in order. Run them in sequence and stop at the first failure:
- Duplicate: query OSV.dev and the GitHub advisory database for the exact surface. A known, fixed, or already-reported issue is dead here.
- By-design and reachability: is the default configuration already secure, so the path is only reachable under a non-default, self-inflicted setting? Is this a deliberate shared-capability carve-out rather than a confusion? If the secure posture is the default, the candidate dies.
- Impact triad: does the action cross to a lower trust boundary (a different user, tenant, or privilege level)? Does it touch a sensitive artifact? Is there a practical consequence a reporter can state in one sentence? All three are required; failing any one demotes the finding.
- Upstream-gating runtime trace: trace the actual runtime object that performs the dispatch and the check, not the import chain or the call graph as written. A guard that looks present in source can be bypassed, shadowed, or bound to the wrong identity at runtime; only the runtime object settles it.
The two-tier PoC oracle. A candidate that survives the gates earns a proof of concept with two independent tiers:
- Tier-A, sibling-control denial: show the same principal denied on the sibling path, yet reaching the same action through the dispatch surface. The sibling denial is the control that proves the dispatch path is the leak, not a misconfiguration.
- Tier-B, fresh-CSPRNG sentinel: mint a fresh cryptographically-random sentinel value and drive it through the dispatch sink, then observe it emerge on the wrong side of the boundary. A fresh sentinel rules out replay, caching, and coincidence, and dates the proof.
The discriminator of this method is the runtime check, and I am honest about that because I measured it. A static-prompt proxy of the sibling-guard heuristic, the version that reads source rather than tracing the runtime object, lost to a naive single frontier-model call on the authorization class (recall 0.667 versus 0.833, a signed Δ of −0.167 on the pinned set), and the runtime oracle recovered the case the static proxy missed, on the small subset I could stand up and re-run live; whether that recovery generalizes beyond that subset is not established. The full measured result, including that loss and which runtime cases were truly live-reran versus settled on recorded evidence, is in the measurement writeup. The loss, not the recovery, is the headline: the instrument is credible because it scores its own method honestly, including where the method underperforms a naive call.
A taxonomy of sub-patterns
The method has several variants, separated by where the residual sits and which invariant the patch failed to extend to it. Each named variant is anchored to a published instance; the variants I can describe only generically are coordinated disclosures still in progress, and are not pinned to any named target here.
- Incomplete-fix sibling sink. A patch closed the reported entry points but a peer path to the same dangerous action survives, so the original class persists behind a patched-looking surface. Published instance: open-webui CVE-2026-54008 (CWE-918 SSRF), where a five-reporter parent fix patched five redirect-following sinks and the method found the sixth, which followed a redirect to an internal target without re-validating it. This is the flagship instance and the canonical shape.
- Cross-user / global-identity confused deputy. The guard runs, but its identity context is process-global, so one principal's access silently stands in for another's. The deputy acts with authority that is not the caller's. Published instance: github-mcp-server, where a lockdown-mode access cache was a singleton bound to the first authenticated user's client.
- Guard skipped on a sibling grant or dispatch path. The check is present and correct on the peer entry points but absent on one of them, so that single path grants what its siblings would deny. Published instance: dex, where the token-exchange grant omitted the connector allow-list check that its sibling OAuth handlers enforce.
- Validator applied to the wrong value, or only once. A validator exists but runs on an input other than the one that reaches the sink, or runs a single time before a redirect or a transformation. The SSRF flagship is also an instance of this; the open-webui stored-XSS sibling (GHSA-3wgj-c2hg-vm6q, CWE-79) is another, where a profile-image content allowlist did not cover a sibling write to the same field.
- Guard present on REST, missing on the agent or tool path (generic). A capability is correctly gated on the conventional API but the newly-shipped agent or tool-dispatch surface reaches the same action without that gate. This is the canonical agent-surface shape STEP-0 hunts; instances of it are among the coordinated disclosures in progress and are not named here.
The public instance index
One method, many classes. The unifying thread is the sibling-diff procedure, not a single CWE. The rows are grouped by severity tier (HIGH, then MEDIUM); a CVSS number is shown only where the advisory itself carries one, and the two self-assessed severities (dex and Outline, neither of which has a CVSS on its advisory) are marked as such. The flagship is the first row, open-webui CVE-2026-54008, the sole-lead HIGH SSRF and the highest published CVSS here, where the method found the redirect sink a five-reporter parent fix missed. One honesty note carried up front: the narrow agent and MCP tool-dispatch authorization sub-axis is still thin (its only published, credited instance is github-mcp, co-reported), and the class-agnostic framing is honest precisely because the flagship is an SSRF, off that narrow axis. Further coordinated disclosures are in progress and are added to this index on publication, not before.
| instance | class label | sub-pattern | severity | identifier | sibling-diff |
|---|---|---|---|---|---|
| open-webui (FLAGSHIP) | CWE-918 SSRF | incomplete-fix redirect sink | HIGH, CVSS 8.5 | CVE-2026-54008 | the parent fix patched five redirect sinks; the sixth followed a redirect to an internal target without re-validating |
| dex (auth surface) | CWE-285 / API5:2023 | guard skipped on a sibling grant path | HIGH, self-assessed (no CVSS or CVE on the advisory; master-only) | GHSA-7qjx-gp9h-65qj | sibling handlers call isConnectorAllowed; the token-exchange grant did not |
| open-webui (XSS sibling) | CWE-79 stored XSS | validator-bypass on a sibling write | HIGH, CVSS 7.3 (no CVE; cite GHSA) | GHSA-3wgj-c2hg-vm6q | a profile-image content allowlist did not cover a sibling path writing the same field |
| MCP Registry | CWE-918 SSRF | allowlist bypass (6to4 / NAT64) | MEDIUM, CVSS 6.3 (v4) | CVE-2026-44430 | the private-address allowlist did not account for 6to4 and NAT64 address forms |
| github-mcp-server (CORE, agent/MCP) | CWE-284 | cross-user confused deputy | MEDIUM, CVSS 6.0 | CVE-2026-48529 | per-request clients enforce identity; the singleton access cache reused the first user's client |
| Kirby (web surface) | CWE-862 / API5:2023 | missing authorization | MEDIUM, CVSS 5.3 (v4) | CVE-2026-45334 | content-lock info disclosure on a missing authz check; web surface |
| Outline (web surface) | CWE-639 / API1:2023 (BOLA) | user-controlled key, cross-tenant | MEDIUM per the GHSA (no CVSS on it; NVD lists 7.7) | CVE-2026-43890 | cross-tenant IDOR in subscription creation; web app, not agent/MCP |
Honesty and scope
A few things stated plainly so the index is not read as more than it is. The flagship open-webui finding is a sole-lead HIGH (CVSS 8.5) and a published CVE; the github-mcp finding was co-reported, MEDIUM (CVSS 6.0), and I do not claim sole discovery there; dex was assessed HIGH but carries no CVE because the bug existed only on master and no released tag ever shipped it; the open-webui XSS sibling has no CVE assigned and is cited as a GHSA. Two scores here are mine, not an advisory's: dex and Outline carry no CVSS on their GitHub advisories, so dex is shown as self-assessed and Outline at the GHSA's qualitative MEDIUM (NVD separately lists a 7.7 via a GitHub-supplied vector), and neither is presented as a published metric. These severity facts cut both ways, and I keep them visible rather than rounding toward the more impressive number. The page is prior-art-led on purpose: every label above is recognized, the classes are named, and the contribution is systematization across them plus a measured baseline, not novelty. The one measured result that bears on the method is a loss, the static proxy losing to a naive model call, and it is linked rather than buried. The narrow agent and MCP tool-dispatch authorization sub-axis is genuinely thin today (one co-reported MEDIUM); the class-agnostic framing is honest because it does not lean on that axis, the flagship being an SSRF. Several further instances are coordinated disclosures still under embargo; they are referred to only generically here and named when their advisories publish. Those embargoed instances are not yet independently checkable by a reader and are claimed only as forthcoming, not as present evidence, so the verifiable base today is just the published rows in the index above. No statistics on this page are asserted beyond what the cited advisories and the linked measurement record support.
References
- OWASP API Security Top 10, API1:2023 Broken Object Level Authorization (owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/). link ↗
- OWASP API Security Top 10, API5:2023 Broken Function Level Authorization (owasp.org/API-Security/editions/2023/en/0xa5-broken-function-level-authorization/). link ↗
- CWE-284 Improper Access Control; CWE-285 Improper Authorization; CWE-862 Missing Authorization; CWE-863 Incorrect Authorization; CWE-639 Authorization Bypass Through User-Controlled Key; CWE-918 Server-Side Request Forgery; CWE-79 Improper Neutralization of Input During Web Page Generation (cwe.mitre.org). link ↗
- Hardy, N. "The Confused Deputy: (or why capabilities might have been invented)." ACM SIGOPS Operating Systems Review, Vol. 22, No. 4, pp. 36 to 38, October 1988. DOI 10.1145/54289.871709. link ↗
- MITRE ATLAS, AML.T0053 AI Agent Tool Invocation (canonical atlas-data, modified 2025-11-04). link ↗
- Tsai, O. "A New Era of SSRF: Exploiting URL Parsers in Trending Programming Languages." Black Hat USA 2017 (framing analogy for systematization, not a label). link ↗
- Instance (FLAGSHIP): open-webui, CVE-2026-54008 / GHSA-226f-f24g-524w, CWE-918 SSRF, sole-lead HIGH (the incomplete-fix redirect sink). link ↗
- Instance: dex, GHSA-7qjx-gp9h-65qj, CWE-285, fix PR #4784 (master-only, no CVE). link ↗
- Instance: open-webui, GHSA-3wgj-c2hg-vm6q, CWE-79 stored XSS, sole (no CVE). link ↗
- Instance: modelcontextprotocol/registry, CVE-2026-44430 / GHSA-r48c-v28r-pf6v, CWE-918 SSRF (private-address allowlist bypass). link ↗
- Instance: github-mcp-server, CVE-2026-48529 / GHSA-pjp5-fpmr-3349, CWE-284, fixed 1.1.2 (co-reported). link ↗
- The measured static-proxy loss and the runtime oracle: "Measuring whether my method beats a naive frontier-model call" (this site).
- The open benchmark and non-LLM scorer: sota_bench (github.com/matte1782/sota-bench). link ↗