
CVE-2026-44338 인증 우회를 시연하는 Docker 기반 실습 환경입니다. PraisonAI의 레거시 Flask API에 대한 취약점을 포함하며, 로컬 보안 연구를 위한 PoC 스크립트와 취약한 서비스 및 패치된 서비스를 제공합니다.
PraisonAI의 레거시 Flask API 서버에서 발생한 인증 우회 취약점인 CVE-2026-44338을 위한 로컬 Docker 실습 환경입니다.
이 실습 환경은 레거시 API 경로에 대한 인증되지 않은 접근 조건을 시연합니다. 실제 PraisonAI 배포 대신 안전한 경로 수준 재현을 의도적으로 사용하여, 증명이 인증 결함에 집중되고 실제 에이전트 워크플로우나 외부 LLM 호출을 트리거하지 않도록 합니다.
CVE-2026-44338은 PraisonAI 버전 >= 2.5.6 및 <= 4.6.33에 영향을 미칩니다.
취약한 레거시 API 서버에서는 인증이 기본적으로 비활성화되어 있었습니다. 결과적으로 API 서버에 도달할 수 있는 인증되지 않은 호출자는 Bearer 토큰 없이 /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 허용됨
POST /chat 허용됨
↓
인증되지 않은 호출자가 에이전트 메타데이터에 접근하고 워크플로우 트리거 경로에 도달할 수 있음
민감한 부분은 /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 (기본값)
↓
요청에 유효한 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