PraisonAI: Praisonai의 OS 명령('OS 명령 주입')에 사용되는 중요 기능에 대한 인증 누락 및 특수 요소의 부적절한 무력화
PraisonAI v4.6.48은 인증 없이 기본 UI 호스트 앱을 통해 PraisonAIUI MCP 클라이언트 관리 API를 노출합니다. 인증되지 않은 원격 클라이언트는 command 및 args 필드와 함께 POST /api/mcp/connect를 보낼 수 있습니다. 엔드포인트는 해당 값을 MCP stdio 클라이언트에 전달하고, 이는 공격자가 PraisonAI UI 서비스 사용자로 선택한 로컬 프로세스를 시작합니다.
이 문제는 PraisonAI의 호스팅 UI 통합(praisonai ui, praisonai ui Agent, praisonai Claw 및 praisonai.integration.host_app.create_host_app() / build_host_app()을 사용하는 모든 앱)을 통해 도달할 수 있습니다. praisonai ui 및 관련 Typer UI 명령은 기본적으로 0.0.0.0에 바인딩됩니다.
영향을 받은 것으로 확인됨:
praisonai v4.6.48d5f1114aaf1a2e9f121a6e66b929149ca2201f1dv4.6.48src/praisonai/uv.lock의 aiui==0.3.121영향을 받을 가능성이 있는 항목:
추론:
AV: 취약한 엔드포인트는 HTTP API 경로입니다.AC: 단일 POST 요청으로 충분합니다.PR: 옵트인 인증이 구성되지 않은 경우 기본 UI 호스트 앱에는 자격 증명이 필요하지 않습니다.UI: 서버가 실행된 후에는 피해자 상호작용이 필요하지 않습니다.S: PraisonAI UI 서버 프로세스 컨텍스트에서 코드가 실행됩니다.C/I/A: 임의의 로컬 명령 실행으로 비밀 유출, 파일 변조 및 서비스 중단이 허용됩니다.PraisonAI는 기본적으로 MCP에 의존하며 선택적 UI 추가 기능을 통해 PraisonAIUI를 노출합니다.
src/praisonai/pyproject.toml:11에는 기본 종속성이 포함되어 있습니다.src/praisonai/pyproject.toml:19에는 mcp>=1.20.0이 포함됩니다.src/praisonai/pyproject.toml:25는 aiui>=0.3.121,<0.4로 ui 추가를 정의합니다.src/praisonai/pyproject.toml:197은 aiui[all]>=0.3.121,<0.4로 claw 추가를 정의합니다.PraisonAI의 UI 명령은 기본적으로 외부에 바인딩되어 'aiui run'을 시작합니다.
src/praisonai/praisonai/cli/commands/ui.py:114는 praisonai ui에 대해 host="0.0.0.0"을 설정합니다.src/praisonai/praisonai/cli/commands/ui.py:163은 해당 호스트를 aiui run으로 전달합니다.src/praisonai/praisonai/cli/commands/ui.py:186, :204 및 :222도 기본 하위 명령인 0.0.0.0을 사용합니다.src/praisonai/praisonai/cli/commands/claw.py:41은 전체 대시보드 명령을 정의합니다.src/praisonai/praisonai/cli/commands/claw.py:93은 선택한 호스트로 aiui run을 시작합니다.PraisonAI의 기본 앱은 인증을 강요하지 않고 PraisonAIUI Starlette 앱을 생성합니다.
src/praisonai/praisonai/ui_chat/default_app.py:18은 configure_host(...)를 호출합니다.src/praisonai/praisonai/ui_chat/default_app.py:142는 app = create_host_app()을 내보냅니다.src/praisonai/praisonai/claw/default_app.py:63은 configure_host(...)를 호출합니다.src/praisonai/praisonai/claw/default_app.py:128은 app = create_host_app()을 내보냅니다.src/praisonai/praisonai/integration/host_app.py:174는 praisonaiui.server.create_app을 가져옵니다.src/praisonai/praisonai/integration/host_app.py:180은 create_app()을 반환합니다.aiui==0.3.121에서 노출된 서버는 MCP 경로를 등록하고 인증은 옵트인됩니다.
praisonaiui/server.py:1483은 api_mcp_connect를 정의합니다.praisonaiui/server.py:1488은 공격자가 제어하는 JSON을 읽습니다.praisonaiui/server.py:1491은 command 또는 url을 허용합니다.praisonaiui/server.py:1496은 connect_mcp_server(body)를 호출합니다.praisonaiui/server.py:2516은 create_app(..., require_auth=False, ...)을 정의합니다.praisonaiui/server.py:2550은 AuthEnforcementMiddleware를 추가하지만 AUTH_ENFORCE=true인 경우에만 인증을 시행합니다.praisonaiui/server.py:2769는 /api/mcp/servers를 등록합니다.praisonaiui/server.py:2770은 /api/mcp/connect를 등록합니다.MCP 기능은 요청 본문을 로컬 프로세스 시작으로 변환합니다.
praisonaiui/features/mcp.py:325는 connect_server(self, server_config)를 정의합니다.praisonaiui/features/mcp.py:330은 command가 있을 때 stdio 전송을 선택합니다.praisonaiui/features/mcp.py:332는 StdioMCPClient(command=server_config["command"], args=server_config.get("args", []))를 구성합니다.praisonaiui/features/mcp.py:360은 MCP stdio 전송을 호출하고 프로세스를 시작하는 client.connect()를 호출합니다.PoC 파일: poc/praisonai-aiui-mcp-connect-rce.py
PoC는 PraisonAI 호스트 앱을 in-process로 실행하고, 인증되지 않은 HTTP 요청을 보내고, 서버에 /usr/bin/touch /tmp/praisonai_host_app_mcp_touch_marker.txt를 실행하도록 요청합니다. LLM 제공업체에 연락하지 않으며 자격 증명을 사용하지 않습니다.
aiui==0.3.121 및 mcp==1.25.0을 사용하여 테스트된 체크아웃에서 관찰된 출력은 다음과 같습니다.
``텍스트 [19:19:55] server.py:229 경고 게이트웨이 서버에 auth_token이 제공되지 않았습니다. 생성된 임시 토큰: gw_****650a. 프로덕션의 경우 GATEWAY_AUTH_TOKEN을 설정합니다. [19:19:55] mcp.py:135 오류 MCP stdio 서버에 연결하지 못했습니다. 'tuple' 개체에 'initialize' 속성이 없습니다. HTTP_STATUS= 200 RESPONSE= {"서버":{"이름":"poc-stdio-process-0","transport":"stdio","status":"error","tools":[],"last_error":"연결 실패"}} SUCCESS_AT_ATTEMPT= 0 MARKER_EXISTS= 참 MARKER_PATH= /tmp/praisonai_host_app_mcp_touch_marker.txt
`aiui==0.3.121`이 잠긴 `mcp==1.25.0` 반환 형태와 호환되지 않기 때문에 MCP 핸드셰이크가 실패하지만 공격자가 선택한 프로세스가 이미 시작되었습니다. 프로세스 시작은 이 버전 불일치로 인한 즉각적인 해체를 경주할 수 있으므로 체크인된 PoC는 `/usr/bin/touch`가 스케줄링을 획득하고 마커를 생성할 때까지 동일한 인증되지 않은 요청을 다시 시도합니다. 마커 파일은 보고된 MCP 연결 오류에도 불구하고 로컬 명령 실행을 증명합니다.
## 익스플로잇 시나리오
운영자는 다음을 실행합니다.
``배쉬
pip 설치 "praisonai[ui]"
프라이소나이 UI
praisonai ui는 기본적으로 0.0.0.0에 바인딩되고 생성된 앱은 기본적으로 인증을 요구하지 않으므로 UI 포트에 도달할 수 있는 모든 호스트는 다음을 보낼 수 있습니다.
``http POST /api/mcp/connect 콘텐츠 유형: 애플리케이션/json
{ "이름": "악", "명령": "/usr/bin/터치", "args": ["/tmp/pwned-by-ui-mcp"] }
실제 공격에서는 해당 명령을 PraisonAI UI 서버 사용자로서 셸, 자격 증명 추출 명령, 파일 수정 명령 또는 장기 프로세스를 시작하는 페이로드로 대체할 수 있습니다.
## 참신함 / 중복되지 않는 분석
검색된 소스:
- PyPI 'praisonai'에 대한 OSV 쿼리: 51개의 권고가 반환되었습니다.
- PyPI `aiui`에 대한 OSV 쿼리: 0개의 권고가 반환되었습니다.
- PyPI `praisonaiui`에 대한 OSV 쿼리: 0개의 권고가 반환되었습니다.
- 정확한 `/api/mcp/connect`, `api_mcp_connect`, `StdioMCPClient`, `connect_mcp_server` 및 `praisonaiui.features.mcp`에 대한 GitHub 자문 데이터베이스를 검색합니다.
- NVD API는 `PraisonAI StdioMCPClient`, `PraisonAI api_mcp_connect`, `PraisonAI /api/mcp/connect`, `PraisonAIUI /api/mcp/connect` 및 `aiui StdioMCPClient`를 검색합니다. 결과는 0개입니다.
- GitHub 이슈/PR은 'MervinPraison/PraisonAI'에서 정확한 엔드포인트/함수/클래스 용어를 검색합니다. `/api/mcp/connect`에 대해 관련 없는 PR이 하나만 반환되었습니다. 문제/PR이 `api_mcp_connect`, `StdioMCPClient`, `connect_mcp_server` 또는 `praisonaiui.features.mcp`와 일치하지 않습니다.
- 정확한 엔드포인트, 파일, 클래스 및 기능 용어에 대한 광범위한 웹 검색에서 일치하는 공개 취약성 보고서가 반환되지 않았습니다.
이것이 알려진 PraisonAI 권고와 다른 이유는 다음과 같습니다.
- 제외된 `praisonai Serve Agent --api-key` `/agents` 인증 우회가 아닙니다. 이 보고서는 PraisonAIUI 호스트 앱의 `POST /api/mcp/connect`를 대상으로 합니다.
- GHSA-9gm9-c8mq-vq7m / CVE-2026-34935 또는 GHSA-9qhq-v63v-fv3j / CVE-2026-41497이 아닙니다. 여기에는 `MCPHandler.parse_mcp_command()` 명령 구문 분석이 포함됩니다. 이 결과는 `praisonaiui.server.api_mcp_connect -> praisonaiui.features.mcp.connect_mcp_server -> StdioMCPClient`를 사용합니다.
- GHSA-pj2r-f9mw-vrcq / CVE-2026-40159가 아닙니다. 해당 권고는 신뢰할 수 없는 MCP 하위 프로세스에 의해 상속된 민감한 환경 변수에 관한 것입니다. 이 발견 항목은 인증되지 않은 네트워크에서 트리거된 로컬 프로세스 실행입니다.
- GHSA-6rmh-7xcm-cpxj 또는 GHSA-8444-4fhq-fxpq가 아닙니다. 이는 인증되지 않은 레거시/생성된 에이전트 서버와 관련이 있습니다. 이는 임의의 로컬 프로세스를 시작하는 고유한 UI 경로이자 고유한 싱크입니다.
- GHSA-9cr9-25q5-8prj, GHSA-9mqq-jqxf-grvw 또는 기타 MCP 서버 파일 읽기/경로 통과 권고가 아닙니다. 이 경로는 PraisonAI의 MCP 서버 도구 디스패처가 아닌 UI MCP 클라이언트 커넥터입니다.
## 권장 수정 사항
1. 원격 HTTP API에서 임의의 `command`/`args`를 제거합니다. MCP stdio 서버는 호출자가 제공한 JSON이 아닌 신뢰할 수 있는 로컬 구성에서만 구성해야 합니다.
2. `AUTH_ENFORCE`에 관계없이 `/api/mcp/connect`, `/api/mcp/disconnect/*` 및 `/api/mcp/servers`에 대한 인증 및 권한 부여가 필요합니다.
3. UI 명령 기본값을 `0.0.0.0`에서 `127.0.0.1`로 변경하거나, 인증 없이 외부에 바인딩할 때 명시적인 `--unsafe-expose` 스타일 플래그를 요구합니다.
4. 원격 MCP 등록이 필수 기능인 경우 SSRF 보호가 포함된 URL 기반 전송만 허용하거나 관리자가 구성한 명령 허용 목록을 유지합니다.
5. `AUTH_ENFORCE`가 설정되지 않은 경우를 포함하여 `/api/mcp/connect`에 대한 인증되지 않은 요청이 하위 프로세스를 시작할 수 없다는 회귀 테스트를 추가합니다.
왜 이 VPI인가 (설명가능 · 실험적)
VPI 산정 기준
| 영향도 | 98.00 |
| 악용 신호(추가 악용신호 없음) | ×1.00 |
| VPI | 98.00 |
VPI 공식 vpi-v1 기준