
CVE-2026-77521(MaxKB 프롬프트 주입 가능 명령 실행)의 무해하고 자체 완결적인 재현
GHSA-f36j-f34j-h3rx
/ CVE-2026-77521을 재현하는 자체 포함형의 무해한 실습 환경입니다: MaxKB(오픈소스 엔터프라이즈 AI 어시스턴트 / RAG 플랫폼)에서 도구, MCP 도구, 스킬 또는 하위 애플리케이션을 가진 모든 어시스턴트에는 인간 승인 게이트 뒤에 있지 않은 셸 execute 도구가 자동 주입됩니다 — 따라서 프롬프트 주입(채팅 또는 수집된 문서로부터)이 셸에 도달합니다. 샌드박스가 이를 격리할 예정이었지만, shell=True 문자열 때문에 메타문자가 샌드박스를 탈출할 수 있었습니다.
| 보안 공지 | GHSA-f36j-f34j-h3rx |
| CVE | CVE-2026-77521 |
| 프로젝트 | 1Panel-dev/MaxKB |
| 영향 받는 버전 | < 2.10.5-lts |
| 패치 버전 | 2.10.5-lts (커밋 594f50f) — 부분적, 아래 참조 |
| CVSS | 10.0 CRITICAL (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) |
| 취약점 유형 | CWE-78 (OS 명령 주입) · CWE-250 (불필요한 권한) · CWE-749 (위험한 메서드 노출) |
이 실습은 교육 및 방어 목적으로 패치되었고 공개적으로 공개된 취약점을 재현합니다. 전적으로 로컬에서 무해하게 실행됩니다:
id, PoC가 삭제하는 마커 파일 작성). 실제 gosu/샌드박스/root는 관여하지 않습니다 — 권한 강등 래퍼는 무해한 env 마커로 대체되어 어디서든 데모가 실행됩니다.어떤 기능이든 연결된 MaxKB 어시스턴트는 SandboxShellBackend와 함께 deepagents 위에 구축됩니다. deepagents는 셸 execute 도구(및 read_file/write_file/…)를 자동 주입하며, MaxKB는 excluded_tools를 사용하지 않으므로 execute는 항상 존재합니다. 인간 승인이 필요한 항목을 결정하는 interrupt_on 설정은 {"write_file": False, "read_file": False, "edit_file": False}입니다: execute가 여기에 없으므로 승인 없이 실행됩니다. 모델을 조종할 수 있는 모든 텍스트(채팅 메시지 또는 RAG 파이프라인이 수집한 오염된 문서)는 따라서 에이전트가 셸 명령을 실행하도록 만들 수 있습니다. 소스 설치에서는 SANDBOX가 기본적으로 꺼져 있어 명령이 앱 사용자로 실행됩니다; 공식(root) 컨테이너에서는 샌드박스 래퍼가 shell=True 문자열이어서 ;/>/$()가 gosu 외부에서 root로 실행되었습니다.
interrupt_on에서는 주입된 execute 호출이 승인 없이 실행됩니다; "execute": True를 추가하면 게이트가 적용됩니다. → poc/01_missing_hitl_gate.py;+리다이렉트가 단일 문자열 gosu 접두사를 탈출합니다; 2.10.5-lts의 _build_sandbox_command() 재인용이 이를 무력화합니다. → poc/02_sandbox_escape.pyexecute를 호출합니다(깨끗한 문서에서는 호출하지 않음). → poc/03_real_llm.py배포된 2.10.5-lts 패치(커밋 594f50f)는
샌드박스 탈출만 강화합니다 — _build_sandbox_command()를 추가하는데, 이 함수는
셸 연산자를 기준으로 분할하고, 모든 토큰을 shlex.quote로 다시 인용하며,
각 단순 명령을 gosu 접두사로 감쌉니다.
v2.10.5-lts 소스와 대조하여 검증한 결과,
에이전시 코어는 변경되지 않았습니다: interrupt_on은 여전히 execute를 생략하고,
백엔드는 여전히 SandboxShellBackend이며, SANDBOX는 여전히 기본값이 0입니다. 따라서
수정 이후에도 프롬프트 인젝션된 execute는 여전히 사람의 승인 없이 실행됩니다 —
내부 벽은 보강되었지만 게이트는 열린 채로 남아 있는 것입니다. PoC 1은
벤더가 배포하지 않은 권장 완화책(execute 게이팅)을 보여줍니다.
PoC 1/2에는 의존성이 없습니다 (Python 3.9+):
./run.sh # all three (PoC 3 skips without an endpoint)
python3 poc/01_missing_hitl_gate.py # missing approval gate
python3 poc/02_sandbox_escape.py # metacharacter sandbox escape
모든 OpenAI 호환 엔드포인트(자체 호스팅 또는 호스팅된 오픈 모델). 예시(Groq):
export OPENAI_BASE_URL=https://api.groq.com/openai/v1
export OPENAI_API_KEY=$GROQ_API_KEY # read from env only; never logged
MODEL="openai/gpt-oss-20b" python3 poc/03_real_llm.py
TLS 검사 프록시 뒤에서는 경고와 함께 검증 없이 재시도합니다
(INSECURE_SSL=1로 강제). 엔드포인트가 설정되지 않은 경우에는 깔끔하게 건너뜁니다.
| 경로 | 설명 |
|---|---|
sandbox_shell.py | MaxKB의 execute() 명령 구성에 대한 무해한 모델 — 취약한 문자열 vs 패치된 _build_sandbox_command() |
agent_sim.py | deepagents interrupt_on 인간 승인 게이트의 최소 모델 |
payloads/poisoned-document.md | 공격자가 오염시킨 KB 문서 (간접 주입) |
poc/01_missing_hitl_gate.py | 주입된 execute가 승인 없이 실행됨; 게이팅이 이를 차단 |
poc/02_sandbox_escape.py | 메타문자가 gosu 접두사를 탈출함; 2.10.5 파서는 이를 포함함 |
poc/03_real_llm.py | 실제 모델이 오염된 문서로부터 execute를 호출함 (정상 vs 오염) |
DEMO.md / demo.sh | 발표자 런북 및 페이스 조절 데모 드라이버 |
assets/attack-flow.{svg,png} | 공격 흐름 다이어그램 (블로그 히어로) |
assets/poc3-groq-sample.txt | 기록된 PoC 3 출력 (데모 폴백) |