
AutoGpt에서 세션 하이재킹을 허용하는 CVE-2026-30950에 대한 POC
CVE-2026-30950에 대한 개념 증명(PoC) 데모입니다. AutoGPT Platform에서 인증된 IDOR(권한 누락) 취약점으로, 로그인한 사용자가 세션에 대한 사전 접근 권한 없이 단일 PATCH 요청을 통해 다른 사용자의 채팅 세션을 재할당하여 가로챌 수 있습니다.
AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L)autogpt-platform-backend >= 0.6.36채팅 세션 API는 사용자가 자신의 계정을 세션 레코드에 연결할 수 있는 라우트를 노출합니다. 이 라우트는 JWT 인증으로 보호되지만, 호출자가 현재 수정 중인 세션을 소유하고 있는지 확인하지 않습니다 — 오직 인증된 사용자임만 확인합니다. 피해자의 session_id와 공격자의 JWT를 사용한 직접 호출은 세션의 소유권을 공격자에게 이전합니다.
취약점은 세 가지 계층으로 구성되며, 각 계층에서 우회가 이루어집니다:
# 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"}
이 라우트는 인증된 모든 호출자를 수락합니다. 이후 서비스로 전달됩니다:
# 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
서비스는 호출자의 사용자 ID를 전달하는 대신 의도적으로 user_id=None을 데이터 접근자에 전달합니다. 데이터 접근자는 None을 관리자 모드로 간주하고 소유권 필터를 건너뜁니다:
# 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
user_id is None일 때, 조건문이 단락 평가되어 불일치 검사가 수행되지 않습니다 — 모든 세션이 모든 호출자에게 반환됩니다. 그런 다음 서비스는 session.user_id를 호출자의 ID로 덮어쓰고 결과를 Redis에 캐시하므로, 원래 소유자의 후속 조회는 방금 우회된 동일한 불일치 검사에 의해 거부됩니다.
채팅(코파일럿) 기능이 활성화된 autogpt-platform-backend >= 0.6.36 및 < 0.6.51 을 실행하는 모든 AutoGPT Platform 인스턴스가 공격 가능합니다. 익스플로잇에 필요한 조건:
세션당 영향, 가로챈 각 세션마다 확대됩니다:
CVSS 점수(C:H / I:N / A:L)는 세션별 범위를 반영합니다: 가로챈 세션에 대한 높은 기밀성 영향, 기존 메시지 콘텐츠에 대한 무결성 손상 없음, 정당한 소유자에 대한 가용성 영향(잠금).
이 저장소는 하나의 PoC를 제공합니다: 알려진 session_id에 대한 공격자의 JWT로 단일 PATCH 요청을 보내는 직접 트리거를 다룹니다. 설정 스크립트는 새로 부트스트랩된 AutoGPT 스택에서 두 명의 사용자(공격자 + 피해자)를 생성하고 준비 상태를 선언하기 전에 전제 조건을 확인합니다.
setup/ — Docker Compose 환경.
setup.sh은 마지막 취약 버전 태그(autogpt-platform-beta-v0.6.50)에서 AutoGPT를 setup/AutoGPT-src/로 클론하고, 업스트림의 docker-compose.yml에서 최소 서비스(rest_server, copilot_executor, database_manager, migrate 및 전이 종속성: Postgres, Redis, RabbitMQ, Supabase Kong + GoTrue)를 시작하며, 두 명의 테스트 사용자를 생성하고 취약한 엔드포인트가 라우팅되는지 확인합니다.teardown.sh은 스택을 종료하고 볼륨을 삭제합니다.pocs/session_hijack.py — 자체 포함 익스플로잇. 피해자와 공격자로 로그인하고, 피해자로 세션을 생성하고, 공격자가 사전 익스플로잇 읽기 접근 권한이 없는지 확인하고, 단일 PATCH 요청을 보낸 후 소유권이 이전되었고 피해자가 잠겼음을 증명합니다.
필수 조건: Docker, Git, Python 3.10+ 및 uv.
cd setup
./setup.sh
첫 번째 실행은 취약한 태그에서 AutoGPT를 클론하고 백엔드 이미지를 빌드합니다(약 3-5분). 이후 실행은 빠릅니다. 설정이 완료되면 복사하여 사용할 수 있는 PoC 호출 명령어를 출력합니다.
PoC 실행:
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!'
왜 높은 포트를 사용하나요? 업스트림의 Compose 파일은 컨테이너 이름을 하드코딩하고 기본 포트(5432, 8000 등)를 게시합니다. 사용자가 이미 실행 중인 다른 Supabase/Postgres/RabbitMQ 스택과 공존하기 위해
setup/docker-compose.override.yml은 컨테이너 이름을 변경하고, 고유한 프로젝트 이름(autogpt-cve-2026-30950)으로 네트워크를 격리하며, 외부에 노출된 두 포트를 58000 범위로 올립니다. 다른 내부 서비스는 프로젝트의 Docker 네트워크에만 바인딩됩니다.
예상 출력은 다음으로 끝납니다:
[PASS] AUTHENTICATED SESSION HIJACK CONFIRMED
종료:
cd setup
./teardown.sh
setup/AutoGPT-src/에 클론된 AutoGPT 소스는 종료 후에도 보존되므로 재실행 시 다시 다운로드하지 않습니다. 완전히 제거하려면 setup/AutoGPT-src/를 삭제하세요.