The Argument That Did Nothing: CVE-2026-104873 Turns a LangGraph Allowlist Into a Wildcard

NVD received CVE-2026-104873 on 2 October 2026. The underlying advisory, GHSA-fvww-7h3r-vfhp, has been published on the LangGraph repository since 28 August 2026, and the fix shipped in langgraph-sdk 0.4.4 on 27 August 2026. Severity is high, CVSS v4.0 7.6 (CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:H/VI:H/VA:N), CWE-863, Incorrect Authorization. Affected: 0.1.45 through 0.4.3.

The bug is one of the purest examples we have seen of a vulnerability class that barely has a name: an API that accepts a security-narrowing argument and silently discards it.

The code that looks right

LangGraph’s custom-auth system lets you register handlers scoped to a resource and, you would reasonably assume, to specific actions on that resource. The advisory quotes the intended usage directly:

@auth.on.threads(actions=["create"])
async def allow_thread_create(ctx, value):
    return None

Read that as an engineer reviewing a pull request. It says: for the create action on threads, allow. Everything else falls through to whatever broader handler the application defined — the one that checks ownership, tenancy, or role.

In affected versions, the actions= argument was ignored. The advisory states the consequence precisely: a decorator “intended to register a handler for selected actions instead registers that handler for every action on the resource.” Three decorators are named: @auth.on.threads, @auth.on.assistants and @auth.on.crons.

Why ignoring an argument becomes a privilege escalation

An ignored parameter is usually a bug, not a vulnerability. What converts this one is the resolution order. From the advisory: “Because the resource-wide handler is selected before broader fallback handlers, authorization checks implemented in those fallback handlers may not run.”

So the failure compounds in exactly the wrong direction. The developer writes a narrow, permissive handler for one safe action. The SDK widens it to all actions on that resource. The dispatcher then prefers that now-wildcard handler over the fallback that contains the real security logic. A rule written to grant a little ends up granting everything, specifically by shadowing the rule written to deny.

NVD’s description names the outcome: an authenticated user “may bypass fallback action, ownership, or permission checks and read, update, or delete another user’s resource.” In LangGraph terms, a thread is a user’s conversation history with an agent and an assistant is a configured agent; cross-tenant read and delete over those is a serious outcome for any multi-user deployment.

The CVSS v4.0 vector is worth reading rather than skimming. PR:L — you need a legitimate low-privileged account, so this is an insider or any-signup threat, not an internet-wide one. AT:P — attack requirements present, reflecting that the deployment must actually use actions= on an affected decorator. VC:H/VI:H — full confidentiality and integrity impact on other users’ resources once those conditions hold.

The honest scoping in the advisory

To the maintainers’ credit, the advisory does not overclaim. It states that exploitability “depend[s] on the affected handler’s behavior” and that “deployments remain protected if that handler independently enforces the necessary action, ownership, or permission checks for every request it receives.” Only Python deployments using actions= on those decorators are affected.

That caveat is also the trap. A handler registered for actions=["create"] has no reason to re-verify ownership — it was scoped to creation, where there is no existing owner to check. The handlers most likely to be written without defensive checks are exactly the narrowly-scoped ones, which are exactly the ones this bug widens. The safe case described by the advisory is real, but it is the case where the developer did redundant work for no stated reason.

The advisory lists workarounds as, simply, “No.” Upgrade to 0.4.4 or later; langgraph-sdk is at 0.4.5 as of 21 September 2026. The flaw was reported by a security researcher credited in the advisory as Grg0rry, and the fix landed through a merge from a fork touching libs/sdk-py/langgraph_sdk/auth/__init__.py and its test file on 27 August 2026.

Five weeks from advisory to CVE — and still nowhere a scanner looks

The sequencing here is the operational story. The fix was released 27 August. The GHSA was published 28 August. The CVE identifier arrived 2 October, roughly five weeks later, and NVD still lists the record in Received status.

We checked whether a dependency scanner would have caught it in the interim. Querying OSV for langgraph-sdk at version 0.4.3 — inside the affected range — returns zero vulnerabilities, and GHSA-fvww-7h3r-vfhp is not resolvable in OSV at all. The GitHub REST global advisory endpoint returns 404 for it; it is visible only through the repository’s own advisory endpoint. A search of the global database for advisories affecting langgraph-sdk returns one record, CVE-2026-48776 from June, and not this one.

That makes this the second case we are documenting today, alongside the three MCP SDK advisories published on 2 October that are equally invisible to OSV and npm audit. Different vendor, different language, same failure mode: the advisory exists, the metadata is accurate, and the distribution to the databases that security tooling actually queries did not happen. A CVE number arriving five weeks later does not retroactively protect the deployments that upgraded on schedule but never knew why they should hurry.

The design lesson, which is the reusable part

Authorization APIs should fail closed on their own inputs. If actions= cannot be honoured — because the dispatch layer does not support per-action registration — the correct behaviour is to raise at import time, not to register a wildcard and continue. A security decorator that accepts a narrowing argument and quietly ignores it produces code that passes review precisely because it reads correctly.

This is the same structural shape as the authorization gaps we catalogued in Obot’s MCP gateway and the ordering bug behind Zscaler’s cross-resource approval replay: the check is present, the code looks defensive, and the dispatch layer decides it never runs. Agent frameworks are accumulating these faster than most teams are auditing them, because the policy surface — threads, assistants, crons, tools, sessions — is larger than anything a traditional web app exposes.

What to do

  • Upgrade langgraph-sdk to 0.4.4 or later (current: 0.4.5). There is no workaround.
  • Grep for the pattern, not the version. Search your codebase for actions= on @auth.on.threads, @auth.on.assistants and @auth.on.crons. Every such handler ran against all actions on that resource for as long as you were on an affected release.
  • Re-read those handlers as if unscoped. For each one, ask what it would have permitted if invoked for read, update, delete and search. That is what it was permitting.
  • Treat the fallback handlers as untested. If a resource-scoped handler shadowed them, your ownership checks may never have executed in production. Add tests that assert denial, not just tests that assert the happy path — this class of bug is invisible to tests that only check that allowed operations succeed.
  • Check logs for cross-user access on threads and assistants during your exposure window, if you retain them. The advisory offers no indicators of compromise, and absence of evidence here is weak, but it is the only retrospective signal available.
  • Do not wait on the CVE feed for agent frameworks. This record spent five weeks as a repository-only advisory. Monitor the /security-advisories endpoints of the frameworks in your agent stack directly.

Our verification was primary-source-led. We read GHSA-fvww-7h3r-vfhp through the GitHub REST API from the langchain-ai/langgraph repository advisory endpoint, and quote its impact text, affected range, patched version, workaround statement and credited reporter as returned. The CVSS v4.0 vector, CWE and severity are taken from that record. We read the NVD 2.0 API record for CVE-2026-104873 for the publication timestamp, status and description. We confirmed the fix commit (5a77be5, authored 27 August 2026) and the files it touched through the GitHub commits API, and the sdk==0.4.4 release timestamp through the releases API and PyPI metadata. We confirmed the advisory’s absence from OSV and from the global GitHub Advisory Database by direct lookup, and that an OSV version query for langgraph-sdk 0.4.3 returns no vulnerabilities. We did not test exploitation against any deployment.

Sources: