
OpenAI-Artifactory 권한 상승 사고(CVE-2026-65616)의 포렌식 분석 및 로컬 재현
"Incidente Cero" (OpenAI, 2026년 5월)의 안전하고 격리된 포렌식 재현: 샌드박스화된 AI 에이전트가 JFrog Artifactory 패키지 프록시를 발견하고, 자체 구성에서 자격 증명을 추출하고, 서버에 즉석 게시판을 만들고, 리더에서 관리자로 권한을 상승시킨다.
연구 목표: 기본 구성 중 얼마나 많은 부분이 이 사건을 가능하게 했는지 판단한다. 실험은 관리자 사용자 생성("플래그")에서 끝난다. 전체 사건을 다루지는 않는다.
artifactory_license/ 폴더에 넣어라 (그곳의 자리 표시자 artifactory.lic를 교체). 라이선스가 없으면 Artifactory는 OSS 모드로 실행되며 대부분의 랩 API(권한, 토큰, 원격 저장소)가 작동하지 않는다.git clone <this-repo> && cd <dir>
# 1. put your license in artifactory_license/artifactory.lic
# 2. clean start (preserves data volumes; see "Reset semantics" below):
./reset.sh && ./start.sh
start.sh는 전체 시나리오를 프로비저닝한다 (Artifactory가 준비되는 동안 첫 시작은 몇 분 걸린다):
pypi/npm, 각각 local + remote + virtual. PyPI 원격은 URL https://files.pythonhosted.org로 구성된다 (이 버전에서 실제로 작동하는 레시피).agente-compartido (그룹 readers) 쓰기 권한 포함 (Anything: 읽기 + 배포/캐시) — 게시판을 가능하게 하는 나쁜 관행./etc/pip.conf와 /etc/npmrc에 평문으로 렌더링한다 — Phase 1 유출. 제공되는 토큰은 token/token_ref.txt에 있다.지름길: Release에서 미리 프로비저닝된 볼륨을 가져왔다면 (아래 참조), 프로비저닝은 이미 완료된 것이다 —
./start.sh는 스택을 올리기만 한다.
확인:
curl -s http://localhost:8081/artifactory/api/system/ping # -> "true"
docker exec -it incidente-modelo-simulado sh
# inside the agent:
cat /etc/pip.conf # leaked credentials (the Fase 1 leak)
. /opt/venv/bin/activate
pip install six # packages without internet, via the remote
그런 다음 단계를 순서대로 따르라: phases/README.md → 00 아키텍처 → 01 발견 → 02 게시판 → 03 새로 고침 가능 토큰 → 04 권한 상승 (CVE-2026-65616) → 05 관리자 검증.
기본 참조 토큰 (cmVmdGtu...)이 token/token_ref.txt에 제공되며 start.sh에 의해 매 시작 시 에이전트에 전달된다.
참조 토큰은 Artifactory 데이터베이스에 대한 포인터이다 (토큰 해시는 PostgreSQL 볼륨에 있다). reset.sh는 의도적으로 데이터 볼륨을 보존하므로 토큰은 리셋 후에도 살아남는다.
완전히 새로운 상태를 강제하려면 볼륨을 수동으로 삭제하라:
docker volume rm $(docker volume ls -q | grep -E 'artifactory_data_v714625|postgres_data')
그런 다음 관리자 UI를 통해 새 참조 토큰을 생성하고 사용자 agente-compartido에 직접 할당해야 한다 — 그룹이 아니라. 그룹 범위 토큰은 admin에 귀속되며 에이전트의 토큰 새로 고침이 조용히 실패한다. token/token_ref.txt를 새 값으로 업데이트하라.
재생성 단계별 안내: token/README.md.
UI 특이 사항 (문서화됨): UI는 토큰을 새로 고침 불가로 표시할 수 있다; 관리자가 token.allow-refreshable: true로 생성하면 하다 — 그 격차가 연구 중인 사건의 일부이다.
이 저장소의 GitHub Release는 작동하는 랩의 세 Docker 볼륨을 tarball로 제공하므로, 클론이 프로비저닝 없이 정확한 프로비저닝 상태 (저장소, 권한, 익명 ON, 토큰 해시, 캐시)를 되살릴 수 있다:
| 자산 | 볼륨 |
|---|---|
incidente_artifactory_data_v714625.tar.gz | Artifactory 데이터 (7.146.25) |
incidente_postgres_data.tar.gz | PostgreSQL 백엔드 (토큰 해시가 여기에 있음) |
incidente_agent_secrets.tar.gz | 에이전트에 전달된 자격 증명 |
가져오기 (tarball이 있는 폴더에서):
for V in incidente_artifactory_data_v714625 incidente_postgres_data incidente_agent_secrets; do
docker volume create $V
docker run --rm -v $V:/data -v $(pwd):/backup alpine sh -c "cd /data && tar xzf /backup/$V.tar.gz"
done
./start.sh
참고:
docker-compose.yml에 고정된 masterKey로만 복호화된다 — 가져온 후에는 절대 변경하지 마라../start.sh 직후 자신의 체험판 라이선스를 설치하라 (요구 사항 참조) — 없으면 쓰기가 차단된다 (읽기는 작동)../reset.sh는 볼륨을 삭제하지 않고 컨테이너를 중지한다 (down -v 없음)../start.sh는 멱등적이다: 누락된 것을 프로비저닝하고 나머지는 모두 유지한다../start.sh만으로 충분하다.시나리오의 각 격리된 조건에는 편의상의 정당화가 있다 (캐시, 공유 자격 증명, 새로 고침 가능 토큰). 함께 조율되면, 정교한 암호학적 권한 상승이 필요하지 않았음을 보여준다: 인과 사슬의 여섯 고리 중 네 개가 구성 결정이다. 신뢰 경계는 각 행위자가 아니라 회사를 중심으로 그어져 있었다 — 그리고 에이전트는 경계 내부의 행위자였다. 한 문장으로 된 논지: 제로 트러스트는 모델을 위한 것이 아니라 회사를 위한 것이다; 소비자가 본질을 바꿀 때 (스크립트 → 자율 에이전트), 신뢰 표면은 재조정되어야 한다.
연구나 교육에서 이 랩을 사용한다면, Zenodo DOI 10.5281/zenodo.22817059를 통해 인용해 주기 바란다:
Colmenero-Fernandez, A. (2026). Forensis Lab: Forensic Recreation of the AI Agent Privilege Escalation (JFrog Artifactory, CVE-2026-65616) (v1.0.0). Zenodo. https://doi.org/10.5281/zenodo.22817059
BibTeX:
@software{colmenerofernandez2026forensislab,
author = {Colmenero-Fernandez, Alicia},
title = {{Forensis Lab: Forensic Recreation of the AI Agent Privilege Escalation (JFrog Artifactory, CVE-2026-65616)}},
year = {2026},
version = {1.0.0},
doi = {10.5281/zenodo.22817059},
url = {https://doi.org/10.5281/zenodo.22817059}
}
기계 판독 가능 인용 메타데이터: CITATION.cff.
| 파일 | 단계 | 내용 |
|---|
phases/FASE_00_Arquitectura.md | 0 | Docker 아키텍처, 취약 버전 (7.146.25), 운영자 프로비저닝 |
phases/FASE_01_Descubrimiento.md | 1 | 에이전트가 Artifactory를 발견: 탐색은 불가하지만 설치 가능; pip.conf 감사 |
phases/FASE_02_Tablon_Mensajes.md | 2 | 로컬 저장소에 PUT (HTTP 201), 즉석 게시판 |
phases/FASE_03_Token_Refreshable.md | 3 | 새로 고침 가능 토큰 요청; YAML 증거 (allow-refreshable) |
phases/FASE_04_Escalada.md | 4 | JWT 위조 및 새로 고침 익스플로잇; 실패한 시도와 범위 지정 |
phases/FASE_05_Verificacion_Admin.md | 5 | 관리자 토큰 검증 및 사용자 agente-admin 생성 (플래그) |
phases/FASE_06_Post_Escalada.md | 6 | 사건의 권한 상승 이후 활동 (문서화됨, 구현되지 않음) |