
POC für CVE-2026-30950, der Session-Hijacking in AutoGpt ermöglicht.
Proof-of-Concept-Demonstration für CVE-2026-30950, eine authentifizierte IDOR (Fehlende Autorisierung) in der AutoGPT-Plattform, die es jedem angemeldeten Benutzer ermöglicht, die Chat-Sitzung eines anderen Benutzers über eine einzige PATCH-Anfrage neu zuzuweisen — und damit zu übernehmen —, ohne vorherigen Zugriff auf die Sitzung.
AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L)autogpt-platform-backend >= 0.6.36Die Chat-Session-API stellt eine Route bereit, mit der ein Benutzer sein
eigenes Konto einem Sitzungsdatensatz zuordnen kann. Die Route ist durch
JWT-Authentifizierung geschützt, führt aber keine Prüfung durch, ob der
Aufrufer die Sitzung derzeit besitzt — es wird nur geprüft, dass er
irgendein authentifizierter Benutzer ist. Ein direkter Aufruf mit der
session_id des Opfers und dem JWT des Angreifers überträgt das Eigentum
an der Sitzung auf den Angreifer.
Die Schwachstelle hat drei Ebenen, und der Bypass wird auf jeder einzelnen hergestellt:
# autogpt_platform/backend/backend/api/features/chat/routes.py:753-776
@router.patch(
"/sessions/{session_id}/assign-user",
dependencies=[Security(auth.requires_user)],
status_code=200,
)
async def session_assign_user(
session_id: str,
user_id: Annotated[str, Security(auth.get_user_id)],
) -> dict:
await chat_service.assign_user_to_session(session_id, user_id)
return {"status": "ok"}
Die Route akzeptiert jeden authentifizierten Aufrufer. Sie übergibt an den Dienst:
# autogpt_platform/backend/backend/copilot/service.py:291-303
async def assign_user_to_session(session_id: str, user_id: str) -> ChatSessionInfo:
session = await get_chat_session(session_id, None) # ← user_id=None
if not session:
raise NotFoundError(f"Session {session_id} not found")
session.user_id = user_id
session = await upsert_chat_session(session)
return session
Der Dienst übergibt dem Datenzugriff bewusst user_id=None,
anstatt die Benutzer-ID des Aufrufers weiterzuleiten. Der Datenzugriff
behandelt None daraufhin als Admin-Modus und überspringt den
Eigentümerfilter:
# autogpt_platform/backend/backend/copilot/model.py:355-366
session = await _get_session_from_cache(session_id)
if session:
if user_id is not None and session.user_id != user_id:
logger.warning(f"Session {session_id} user id mismatch")
return None
return session
Wenn user_id is None ist, wird die Und-Verknüpfung kurzgeschlossen und
die Abweichungsprüfung nie ausgeführt — jede Sitzung wird an jeden Aufrufer
zurückgegeben. Der Dienst überschreibt dann session.user_id mit der ID
des Aufrufers und speichert das Ergebnis in Redis zwischen, sodass spätere
Abfragen durch den ursprünglichen Eigentümer von derselben Abweichungsprüfung
abgewiesen werden, die gerade umgangen wurde.
Jede AutoGPT-Plattform-Instanz, die autogpt-platform-backend
>= 0.6.36 und < 0.6.51 mit aktiviertem Chat- (Copilot-) Feature
ausführt, ist ausnutzbar. Der Exploit erfordert:
Auswirkung pro Sitzung, die mit jeder übernommenen Sitzung zunimmt:
Der CVSS-Score (C:H / I:N / A:L) spiegelt die Pro-Sitzungs-Reichweite wider: hohe Vertraulichkeits-Auswirkung auf übernommene Sitzungen, keine Integritäts-Schädigung bestehender Nachrichteninhalte und eine Verfügbarkeits-Auswirkung (Aussperrung) auf den rechtmäßigen Eigentümer.
Dieses Repository enthält einen POC, der den direkten Auslöser abdeckt:
eine einzelne PATCH-Anfrage mit dem JWT eines Angreifers gegen eine bekannte
session_id. Das Setup-Skript erstellt zwei Benutzer (Angreifer + Opfer)
in einem frisch aufgesetzten AutoGPT-Stack und prüft die Vorbedingungen,
bevor es die Bereitschaft erklärt.
setup/ — Docker-Compose-Umgebung.
setup.sh klont AutoGPT beim letzten verwundbaren Tag
(autogpt-platform-beta-v0.6.50) nach setup/AutoGPT-src/, startet
die Mindestdienste aus dem Upstream-docker-compose.yml
(rest_server, copilot_executor, database_manager, migrate,
sowie deren transitive Abhängigkeiten: Postgres, Redis, RabbitMQ,
Supabase Kong + GoTrue), erstellt zwei Testbenutzer und prüft,
dass der verwundbare Endpunkt geroutet ist.teardown.sh fährt den Stack herunter und löscht die Volumes.pocs/session_hijack.py — In sich geschlossener Exploit. Meldet
sich als Opfer und Angreifer an, erstellt eine Sitzung als Opfer,
bestätigt, dass der Angreifer vor dem Exploit keinen Lesezugriff hat,
feuert die einzelne PATCH-Anfrage ab und beweist dann, dass das
Eigentum übertragen wurde und das Opfer ausgesperrt ist.
Voraussetzungen: Docker, Git, Python 3.10+ und uv.
cd setup
./setup.sh
Der erste Lauf klont AutoGPT am verwundbaren Tag und baut das Backend-Image (~3-5 Min.). Spätere Läufe sind schnell. Wenn das Setup abgeschlossen ist, gibt es den fertig zum Einfügen bereiten POC-Aufruf aus.
POC ausführen:
uv run --no-project --with requests \
pocs/session_hijack.py \
--api-url http://localhost:58006 \
--auth-url http://localhost:58000 \
--attacker-email [email protected] \
--attacker-password 'Attacker123!' \
--victim-email [email protected] \
--victim-password 'Victim123!'
Warum die hohen Ports? Das Upstream-Compose legt Containernamen fest (
supabase-db,rabbitmq, ...) und veröffentlicht Standardports (5432, 8000, ...). Um mit beliebigen anderen Supabase-/Postgres-/RabbitMQ-Stacks koexistieren zu können, die der Benutzer möglicherweise bereits ausführt, benenntsetup/docker-compose.override.ymldie Container um, isoliert die Netzwerke unter einem eindeutigen Projektnamen (autogpt-cve-2026-30950) und hebt die beiden extern erreichbaren Ports in den 58000er-Bereich. Die anderen internen Dienste binden nur an das Docker-Netzwerk des Projekts.
Die erwartete Ausgabe endet mit:
[PASS] AUTHENTICATED SESSION HIJACK CONFIRMED
Herunterfahren:
cd setup
./teardown.sh
Der geklonte AutoGPT-Quellcode in setup/AutoGPT-src/ bleibt über
mehrere Teardowns hinweg erhalten, sodass erneute Läufe nichts erneut
herunterladen. Um ihn vollständig zu entfernen, lösche setup/AutoGPT-src/.