
PraisonAIのレガシーFlask APIにおけるCVE-2026-44338の認証バイパスを実演するDockerベースのラボです。ローカルでのセキュリティ研究用に、脆弱なサービスと修正済みサービス、PoCスクリプトを含んでいます。
CVE-2026-44338 のローカル Docker ラボ。PraisonAI のレガシー Flask API サーバーにおける認証バイパスです。
このラボは、レガシー 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() returns True
↓
GET /agents is allowed
POST /chat is allowed
↓
unauthenticated caller can access agent metadata and reach the workflow trigger route
敏感な部分は、/chat が単なるステータスエンドポイントではなかったことです。ユーザーメッセージを受け入れ、agents.yaml を使用して PraisonAI ワークフローランナーを呼び出しました。
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 by default
↓
request must include a valid Bearer token
↓
missing or invalid token returns 401
↓
/agents and /chat are no longer reachable anonymously
このラボはそのソースレベルの違いを反映しています:
vuln -> auth disabled by default, unauthenticated requests return 200
patched -> auth required by default, unauthenticated requests return 401
ラボには 2 つのローカルサービスが含まれています:
| Service | URL | Behavior |
|---|---|---|
vuln | http://127.0.0.1:8081 | 脆弱なフェイルオープン認証動作を再現 |
patched | http://127.0.0.1:8082 | ベアラートークン認証が必要 |
両方のサービスは 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 アドバイザリ: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