JFrog Artifactory 预认证全链 RCE 复现项目(CVE-2026-42018 / CVE-2026-65616 / CVE-2026-65615):完整攻击链报告、7.146.7 Docker 复现交付物(EXP / 部署 / 基线验证 / payload 样本 / 恢复工具)
For authorized security testing, defensive research, and security education only. This vulnerability chain has been fixed by the vendor (upgrading to 7.161.15+ is recommended). Please reproduce only in a disposable, isolated lab environment. Performing any of the operations described in this repository against systems you do not own or have authorization to test is illegal, and the operator bears all consequences arising therefrom.
This repository is the complete reproduction deliverable for the JFrog Artifactory pre-auth RCE vulnerability chain disclosed by edrabb.fr: a fully automated reproduction of the 5-step attack chain based on the official image releases-docker.jfrog.io/jfrog/artifactory-oss:7.146.7 (the only official deployment form for 7.146.x: external PostgreSQL), with the authenticity of the reproduction proven through a baseline experiment of "achieving RCE directly in a fresh environment" (see attack-chain-package/baseline/BASELINE-VERIFIED.md).
| Step | Stage | CVE |
|---|---|---|
| Step 1 | Trailing slash authentication bypass, obtain anonymous JWT (aud=*@*) | CVE-2026-42018 |
| Step 2 | Exchange for access + refresh token pair | CVE-2026-42018 |
| Step 3 | Router discovers jfrt@ service ID → forge admin JWT refresh → genuinely signed admin token | CVE-2026-65616 |
| Step 4 | systemUpload uploads payload.zip → system import extracts and writes malicious logback.xml | — |
| Step 5 | Logback fileHeader writes web.xml / CGI components to disk → Tomcat CGI pre-auth RCE | CVE-2026-65615 |
├── 漏洞攻击链完整报告.md ← Master report (reproduction authenticity baseline verification, principles, comparison with disclosure article, remediation recommendations)
├── 复现报告.md ← 744-line detailed technical reproduction report (source-level principles + manual steps)
└── attack-chain-package/
├── README.md ← Quick start (deploy lab / launch attack / restore environment)
├── exploit/
│ ├── exp.py ← Full-chain automated EXP (Python 3 standard library, zero third-party dependencies)
│ └── forge_jwt.py ← Step 3 manual JWT forgery script (independent of exp.py)
├── deploy/system.yaml ← Artifactory 7.146.7 container mount configuration (official image strictly requires PostgreSQL)
├── baseline/ ← Reproduction authenticity baseline verification (experiment records and configuration for achieving RCE directly in a fresh environment)
├── payload-sample/ ← Offline-generated payload component samples (output of exp.py --dump-payload)
└── recovery/ ← Environment recovery and verification scripts (incident response reference)
# 1. Deploy the lab (see attack-chain-package/README.md for details; requires approximately 6 GB disk and 8 GB available memory)
docker network create jfrog-net
docker run -d --name artifactory-pg --network jfrog-net \
-e POSTGRES_DB=artifactory -e POSTGRES_USER=artifactory -e POSTGRES_PASSWORD=artifactory \
postgres:15
docker run -d --name artifactory-rce --network jfrog-net -p 8081:8081 -p 8082:8082 \
-v <ABS_PATH>/attack-chain-package/deploy/system.yaml:/opt/jfrog/artifactory/var/etc/system.yaml \
releases-docker.jfrog.io/jfrog/artifactory-oss:7.146.7
# Wait 2–4 minutes; ready when ping returns OK
curl -s http://127.0.0.1:8082/artifactory/api/system/ping
# 2. Launch the attack (one-shot mode, executes id by default; on Windows hosts where python is 2.x, use py -3)
python3 attack-chain-package/exploit/exp.py --target http://127.0.0.1:8082
# 3. Restore the environment (simplest: destroy and rebuild; for in-place recovery see recovery/recover5.sh)
docker rm -f artifactory-rce
The attack is a one-time destructive action against the webapp: Artifactory's original web functionality is killed the moment RCE lands, so be sure to use a disposable lab container.
attack-chain-package/payload-sample/payload.zip (the final upload artifact, whose import triggers RCE) is stored as base64 text in payload.zip.b64:
# Windows PowerShell
[IO.File]::WriteAllBytes("payload.zip", [Convert]::FromBase64String((Get-Content "payload.zip.b64" -Raw).Trim()))
# Linux / macOS
base64 -d payload.zip.b64 > payload.zip
admin / password (JFrog default initial account; this attack chain is pre-auth throughout and uses no credentials)