flawopen.com/Teardowns/cve-2026-104873-langgraph-sdk-auth-action-bypass
LangGraph CVE-2026-104873: Autorisierungsumgehung
LangGraph SDK 0.1.45–0.4.3 ignorierte Aktionsfilter in drei Python-Dekoratoren. Aktualisieren Sie auf 0.4.4.[1]
Stellen Sie sich einen Empfang vor, der nur Lieferungen annehmen soll, während das Leitsystem alle Besucher dorthin schickt. Prüft er nur den Zutritt, kann jemand Räume erreichen, die ein anderer Schalter verschlossen hätte. Das SDK ignorierte actions= beim Registrieren eines Ressourcen-Handlers; dadurch erhielt er auch Lese-, Änderungs- oder Löschvorgänge. Ein Risiko entsteht nur, wenn der Handler nötige Berechtigungen nicht selbst prüft.[1]
Kernkonzepte & Begriffe
CWE-863- Fehlerhafte Autorisierung: Die Prüfung setzt die Berechtigung nicht durch.[1]
Framework-Zuordnungen
- CWE-Referenz für die in diesem Leitfaden beschriebene Schwachstelle: CWE-863
- OWASP API Security Top 10 — API5:2023 Fehlerhafte Autorisierung auf Funktionsebene
Ursachenanalyse
Versionen 0.1.45–0.4.3 akzeptierten actions=, registrierten den Handler aber unter dem Ressourcen-Wildcard *. LangGraph konnte ihn vor einem allgemeinen Fallback auswählen. Prüfte die Funktion nur die vorgesehene Aktion, konnte sie andere ohne Fallback-Prüfung erhalten. Zugriff auf fremde Ressourcen setzte voraus, dass die Anwendung von ausgelassenen Prüfungen abhing und der Handler Aktion sowie Eigentümer nicht selbst kontrollierte. 0.4.4 validiert die Liste und registriert jede Aktion einzeln; ohne actions= bleibt der Wildcard absichtlich bestehen. Der Hinweis nennt CWE-863 und CVSS 4.0 7.6 High. Der Fehler hängt von der Konfiguration ab, ist weder unauthentifiziert noch in jeder LangGraph-Installation vorhanden. Betroffen sind die Dekoratoren: @auth.on.threads / @auth.on.assistants / @auth.on.crons. Wichtige Grenze des Fixes: Die SDK-Änderung beschränkt Registrierungen auf deklarierte Aktionen. Nicht abgedeckte Pfade der benutzerdefinierten Autorisierung bleiben jedoch erlaubt, sofern die Anwendung keinen globalen Deny-by-default-Handler einrichtet. Laut Changelog 0.4.4 warnt langgraph-api 0.10+ beim Start vor nicht abgedeckten Pfaden; diese Warnung dient der Erkennung, nicht der Durchsetzung.[1], [2], [5]
Schritt-für-Schritt Angriffsablauf
Quellcode: Verwundbar vs. Sicher
Der verwundbare Ausschnitt zeigt das frühere Verhalten: _ResourceOn.__call__ verwendete unabhängig von actions= den Schlüssel *. Die Korrektur validiert und registriert jede Aktion einzeln. Dies ist ein Ausschnitt, kein Ersatz des Moduls. Aktualisieren Sie und lassen Sie Handler Aktion und Eigentümer prüfen. Quellcodepfad: libs/sdk-py/langgraph_sdk/auth/__init__.py, method _ResourceOn.__call__.[1], [2]
Quelltextauszug: Handler-Registrierung nach Aktion
def __call__(self, fn=None, *, resources=None, actions=None):
if fn is not None:
_validate_handler(fn)
return typing.cast("_ActionHandler", _register_handler(
self.auth, self.resource, "*", fn
))
def decorator(handler):
_validate_handler(handler)
return typing.cast("_ActionHandler", _register_handler(
self.auth, self.resource, "*", handler
))
return decorator
def __call__(self, fn=None, *, resources=None, actions=None):
def decorator(handler):
_validate_handler(handler)
if resources is None:
resource_list = [self.resource]
elif isinstance(resources, str):
resource_list = [resources]
elif isinstance(resources, Sequence):
resource_list = list(resources)
else:
raise TypeError("resources must be a string or sequence of strings")
if resource_list != [self.resource]:
raise ValueError("use @auth.on(...) for other resources")
if actions is None:
action_list = ["*"]
elif isinstance(actions, str):
action_list = [actions]
elif isinstance(actions, Sequence):
action_list = list(actions)
else:
raise TypeError("actions must be a string or sequence of strings")
if not action_list:
raise ValueError("actions must not be empty")
if not all(isinstance(action, str) for action in action_list):
raise TypeError("actions must be strings")
valid_actions = {
value.action for value in vars(self).values()
if isinstance(value, _ResourceActionOn)
}
invalid_actions = (
sorted(set(action_list) - valid_actions) if actions is not None else []
)
if invalid_actions:
raise ValueError("invalid action for this resource")
if len(action_list) != len(set(action_list)):
raise ValueError("actions must not contain duplicates")
for action in action_list:
if (self.resource, action) in self.auth._handlers:
raise ValueError("handler already registered for action")
for action in action_list:
_register_handler(self.auth, self.resource, action, handler)
return handler
if fn is not None:
return decorator(typing.cast("_ActionHandler", fn))
return decorator
Checkliste für Engineering & Systemsicherheit
- ✓Aktualisieren Sie SDK 0.1.45–0.4.3 auf 0.4.4+.[1], [3]
- ✓Suchen Sie die drei betroffenen Dekoratoren mit
actions=.[1], [2] - ✓Prüfen Sie Aktion und Zugriff auf die genaue Ressourcen-ID.[1]
- ✓Testen Sie deklarierte und nicht deklarierte, auch abgelehnte Aktionen.[2]
- ✓Testen Sie benutzerübergreifende Zugriffe auf Threads, Assistenten und Crons.[1]
- ✓Lehnen Sie doppelte, leere oder unbekannte Listen beim Start ab.[2]
- ✓Setzen Sie Anmeldung nicht mit ausdrücklicher Autorisierung gleich.
- ✓Richten Sie für alle nicht durch aktionsgebundene Handler abgedeckten Pfade der benutzerdefinierten Autorisierung einen globalen Deny-by-default-Handler ein. langgraph-api 0.10+ warnt vor solchen Pfaden, aber eine Startwarnung weist keine Anfragen ab.[5], [1]