
Лаборатория на базе Docker, демонстрирующая обход аутентификации CVE-2026-44338 в устаревшем Flask API PraisonAI. Включает уязвимые и исправленные сервисы с PoC-скриптом для локального исследования безопасности.
Локальная Docker-лаборатория для CVE-2026-44338 — обхода аутентификации в устаревшем Flask API сервере PraisonAI.
Данная лаборатория демонстрирует состояние неаутентифицированного доступа на устаревших маршрутах API. Она намеренно использует безопасное воспроизведение на уровне маршрутов вместо полного развёртывания PraisonAI, чтобы доказательство оставалось сфокусированным на ошибке аутентификации и не вызывало реальных рабочих процессов агентов или внешних вызовов LLM.
CVE-2026-44338 затрагивает версии PraisonAI >= 2.5.6 и <= 4.6.33.
В уязвимом устаревшем API сервере аутентификация была отключена по умолчанию. В результате неаутентифицированный вызывающий, имеющий доступ к API серверу, мог получить доступ к /agents и маршруту рабочего процесса /chat без токена-носителя.
Проблема была исправлена в PraisonAI 4.6.34 путём изменения поведения по умолчанию на требование аутентификации, если она не отключена явно.
В уязвимой версии устаревший API сервер использовал небезопасные настройки аутентификации по умолчанию:
AUTH_ENABLED = False
AUTH_TOKEN = None
def check_auth():
if not AUTH_ENABLED:
return True
Поскольку check_auth() возвращал True, когда аутентификация была отключена, защищённые маршруты оставались открытыми.
Затронутые маршруты включали:
GET /agentsPOST /chatИсправленная версия изменяет стандартное положение так, что аутентификация включена, если не отключена явно через конфигурацию.
Основная проблема не была сложным примитивом эксплуатации. Она возникла из-за небезопасных настроек по умолчанию в устаревшем Flask API сервере.
v4.6.33В v4.6.33 аутентификация была отключена по умолчанию:
AUTH_ENABLED = False
AUTH_TOKEN = None
Затем проверка аутентификации давала сбой:
def check_auth():
if not AUTH_ENABLED:
return True
Это означает, что запрос принимался всякий раз, когда аутентификация была отключена, даже если вызывающий не отправлял заголовок Authorization.
Уязвимый поток был:
AUTH_ENABLED = False
↓
check_auth() возвращает True
↓
GET /agents разрешён
POST /chat разрешён
↓
неаутентифицированный вызывающий может получить доступ к метаданным агента и достичь маршрута запуска рабочего процесса
Важная часть: /chat был не просто конечной точкой статуса. Он принимал сообщение пользователя и затем вызывал исполнитель рабочего процесса PraisonAI, используя agents.yaml.
v4.6.34В v4.6.34 поведение по умолчанию было изменено на требование аутентификации, если оператор явно её не отключает:
AUTH_ENABLED = os.environ.get("PRAISONAI_API_AUTH", "enabled").strip().lower() != "disabled"
AUTH_TOKEN = os.environ.get("PRAISONAI_API_TOKEN") or None
Исправленная версия также улучшает обработку токенов:
secrets.compare_digest()127.0.0.1, а не открывается на всех интерфейсахИсправленный поток:
AUTH_ENABLED = True по умолчанию
↓
запрос должен содержать действительный Bearer токен
↓
отсутствие или неверный токен возвращает 401
↓
/agents и /chat больше недоступны анонимно
Эта лаборатория отражает ту разницу на уровне исходного кода:
vuln -> аутентификация отключена по умолчанию, неаутентифицированные запросы возвращают 200
patched -> аутентификация требуется по умолчанию, неаутентифицированные запросы возвращают 401
Лаборатория содержит два локальных сервиса:
| Сервис | URL | Поведение |
|---|---|---|
vuln | http://127.0.0.1:8081 | Воспроизводит уязвимое поведение с открытым доступом |
patched | http://127.0.0.1:8082 | Требует аутентификации через bearer-токен |
Оба сервиса привязаны только к 127.0.0.1.
Маршрут /chat использует фиктивный исполнитель вместо реального рабочего процесса PraisonAI. Это предоставляет наблюдаемое доказательство того, что неаутентифицированный запрос достигает пути запуска рабочего процесса, не вызывая внешних побочных эффектов.
.
├── docker-compose.yml
├── vuln
│ ├── Dockerfile
│ └── start_server.py
├── patched
│ ├── Dockerfile
│ └── start_server.py
├── poc
│ └── poc.py
└── .gitignore
└── README.md
docker compose up --build -d
python3 poc/poc.py
Уязвимый сервис разрешает неаутентифицированный доступ:
=== vuln ===
[unauthenticated] GET /agents
status: 200
[unauthenticated] POST /chat
status: 200
verdict: LIKELY_VULNERABLE
Исправленный сервис блокирует неаутентифицированный доступ:
=== patched ===
[unauthenticated] GET /agents
status: 401
[unauthenticated] POST /chat
status: 401
verdict: NOT_VULNERABLE_OR_PROTECTED
Итоговая ожидаемая сводка:
vuln: LIKELY_VULNERABLE
patched: NOT_VULNERABLE_OR_PROTECTED
Проверьте уязвимый маршрут:
curl -i http://127.0.0.1:8081/agents
Ожидаемый уязвимый ответ:
HTTP/1.1 200 OK
Проверьте исправленный маршрут:
curl -i http://127.0.0.1:8082/agents
Ожидаемый исправленный ответ:
HTTP/1.1 401 UNAUTHORIZED
Журналы сервера должны чётко показать разницу:
vuln: "GET /agents HTTP/1.1" 200
patched: "GET /agents HTTP/1.1" 401
docker compose down -v
Эта лаборатория предназначена только для локального исследования безопасности.
PoC не выполняет:
GitHub Advisory: GHSA-6rmh-7xcm-cpxj https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-6rmh-7xcm-cpxj
NVD: CVE-2026-44338 https://nvd.nist.gov/vuln/detail/CVE-2026-44338
OSV: GHSA-6rmh-7xcm-cpxj https://osv.dev/vulnerability/GHSA-6rmh-7xcm-cpxj
Уязвимый исходник: PraisonAI v4.6.33 src/praisonai/api_server.py
https://raw.githubusercontent.com/MervinPraison/PraisonAI/v4.6.33/src/praisonai/api_server.py
Исправленный исходник: PraisonAI v4.6.34 src/praisonai/api_server.py
https://raw.githubusercontent.com/MervinPraison/PraisonAI/v4.6.34/src/praisonai/api_server.py