REPRO-2026-00355: Verified Reproduction
REPRO-2026-00355: ArangoDB full-chain: unauthenticated %5f URL auth bypass GHSA-rrgq-978q-36mq + client-controlled isSystem task escalation GHSA-rvhw-4hpw-9vrx - root-context file write - host RCE
REPRO-2026-00355 is verified against ArangoDB server · other. Affected versions: Official advisories list ArangoDB <= 3.12.10.1 as affected. Fixed in ArangoDB 3.12.11 is patched for both advisories. Vulnerability class: RCE. This critical reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00355.
What Is REPRO-2026-00355?
REPRO-2026-00355 is a critical-severity RCE vulnerability affecting ArangoDB server Official advisories list ArangoDB <= 3.12.10.1 as affected.. Pruva has independently reproduced it and publishes a verified, runnable proof-of-concept (reproduction REPRO-2026-00355).
REPRO-2026-00355 Severity
REPRO-2026-00355 is rated critical severity.
Critical — the most severe class — typically remotely exploitable with severe impact. Treat as an emergency.
Affected ArangoDB server Versions
ArangoDB server · other versions Official advisories list ArangoDB <= 3.12.10.1 as affected. are affected.
How to Reproduce REPRO-2026-00355
pruva-verify REPRO-2026-00355 curl -O https://www.pruva.dev/api/v1/reproductions/REPRO-2026-00355/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh Proof of Reproduction for REPRO-2026-00355
- reached the target end-to-end
- full exploit chain demonstrated
- on the real production code path
- high confidence
- the upstream fix blocks the same trigger
Unauthenticated raw HTTP paths containing %5f, simple-action JSON selecting _users, recovered root credential, and authenticated task JSON with isSystem:true plus attacker JavaScript/cron command
- arangod HTTP listener
- encoded /_db/_system/%5fapi/simple actions
- leaked weak root authData
- /_open/auth
- PUT /_api/tasks/{id} isSystem:true
- Internal JS root crontab write
- crond execution
How the agent worked
Root Cause and Exploit Chain for REPRO-2026-00355
ArangoDB 3.12.10.1 contains two independently vulnerable trust boundaries that can be composed into unauthenticated root-context command execution. First, in the default server.authentication-system-only=true mode, authentication evaluates the raw URL while JavaScript action dispatch uses URL-decoded suffixes. Encoding the leading underscore as %5f therefore makes a protected /_api/simple/* action appear public to the authentication gate but dispatches it as the privileged system action, allowing an unauthenticated attacker to read and modify _users. Second, the authenticated REST task handler accepts a client-controlled Boolean isSystem:true without requiring superuser authority and creates an Internal JavaScript task. In the official image, arangod runs as UID 0, so that task can write root-only host/container files. This run composed the two defects through a validated weak-password credential-acquisition hop and observed a root cron consumer execute an attacker-selected command twice.
- Affected package/component: ArangoDB HTTP server, principally
RestActionHandler/action dispatch for the encoded-path bypass andRestTasksHandler/task creation for Internal-context escalation. - Affected versions: ArangoDB releases through 3.12.10.1. Both flaws are fixed in 3.12.11.
- Tested vulnerable target: official
arangodb:3.12.10.1linux/amd64 image at immutable digestsha256:01be938f3a8d3e82725d365ca6750e4cafd092ec78a33a027588cfac37be4e51. - Tested fixed target: official
arangodb:3.12.11linux/amd64 image at immutable digestsha256:39bbca489179ea03f2b24b7ea4e4c4cb5258f6474f8c1c4d9bd65f7cd6d211a5. - Risk: Critical. The first flaw provides unauthenticated superuser document read/write, including disclosure and persistent modification of authentication records. Once the attacker has an authenticated database-write identity, the second flaw provides arbitrary root-context file read/write and, when a privileged file consumer exists, host/container command execution.
Impact Parity
- Disclosed/claimed maximum impact: Unauthenticated remote code execution as the
arangodoperating-system user, root in the tested official container. - Reproduced impact from this run: Two clean vulnerable product instances accepted unauthenticated encoded HTTP requests, disclosed root's salted password hash, allowed attacker-controlled
_userspersistence, authenticated root with a password recovered from the leaked weak single-round hash, accepted an authenticatedisSystem:truetask, wrote a root crontab, and produced attacker-selectedid/whoami/marker output as UID 0 throughcrond. - Parity:
full. - Not demonstrated: No escape from the Docker container namespace was attempted. The demonstrated execution is root inside the official product container, consistent with the exercised target. The chain depends on the explicitly tested weak-password condition for immediate login; arbitrary
_userspersistence was also shown, but direct collection writes do not invalidate the already-loaded UserManager cache during the current process lifetime.
Root Cause
The chain has two roots:
Raw-versus-decoded authorization differential (GHSA-rrgq-978q-36mq).
RestActionHandler::hasAllowedUnauthenticatedPath()decides whether a request is an unauthenticated application route from the rawrequestPath(). With the default system-only mode,/%5fapi/...does not begin with literal/_and is treated as unauthenticated. Later action lookup uses URL-decoded suffixes, turning%5fapiinto_apiand dispatching a privileged JavaScript simple action under the superuser execution scope. The action itself assumes that the outer handler already enforced authorization.Missing authorization for privileged task mode (GHSA-rvhw-4hpw-9vrx).
RestTasksHandlerreadsisSystemdirectly from attacker JSON and passes it into task creation after checking only database-write access. Boolean true selects the Internal JavaScript security context, which can access arbitrary filesystem paths. The equivalent JavaScript-side system-task API has an internal-context guard, but the REST path did not replicate that guard. In the official image the server process is UID 0, amplifying Internal-context file access to root.
For credential acquisition, the first defect discloses authData.simple, which uses one round of SHA256(salt || password) with a short salt. This run explicitly configured and then recovered test1234 from a bounded dictionary, satisfying rather than assuming the weak-password precondition. The encoded update-by-example route also replaced root's stored hash with attacker-selected bytes and read those bytes back. Source inspection at vulnerable tag v3.12.10.1 (95ea088...) showed why that direct collection change does not immediately authenticate the new password: UserManager reload follows its global-version notification path, whereas generic simple actions do not invoke that API.
The exact fix commit was not identified in the submitted ticket. The authoritative fixed release is 3.12.11; remediation should preserve one canonical path representation for both authorization and routing and reject client selection of Internal task context unless the caller is already a superuser/internal principal.
Reproduction Steps
- Run
bundle/repro/reproduction_steps.shfrom any directory. The script derives portable paths from its own location and acceptsPRUVA_ROOT. - The script executes immutable official Docker image digests, starts the real
arangodHTTP service, waits for health, and seeds a protected marker plus a weak-password deployment condition through legitimate administration. - For each of two vulnerable instances, it retains exact raw HTTP requests and full raw responses for:
- literal protected-path
401control; - unauthenticated
%5fprotected-document and root-authData reads; - bounded password recovery from the leaked hash;
- unauthenticated attacker-selected root-authData update/read-back;
- real
/ _open/authlogin (without the space; exact path is/_open/auth); - authenticated
PUT /_api/tasks/{id}with BooleanisSystem:true; - root-only task file/crontab evidence; and
crondcommand output containinguid=0(root),root, and a per-attempt marker.
- literal protected-path
- For each of two fixed 3.12.11 instances, the script proves the encoded read and update fail with
401, then authenticates a database-RW non-superuser and proves the realisSystem:truetask request reaches the endpoint but fails with403and creates no root marker. - Expected final output is
SUCCESS: full unauthenticated-to-root-command-execution chain reproduced twice; fixed controls passed twice.and exit status 0.
Evidence
- Runtime evidence manifest:
bundle/repro/runtime_manifest.json. - Consolidated result:
bundle/repro/proof/summary.json. - Diagnostic session log:
bundle/logs/reproduction_steps.log(not manifest-hashed while active). - Immutable image binding:
bundle/repro/proof/image-identities.txt. - Vulnerable attempt directories:
bundle/repro/proof/vulnerable-1/andbundle/repro/proof/vulnerable-2/. - Fixed attempt directories:
bundle/repro/proof/fixed-1/andbundle/repro/proof/fixed-2/.
Key current-run observations include:
vulnerable attempt 1: FULL CHAIN CONFIRMED
vulnerable attempt 2: FULL CHAIN CONFIRMED
fixed attempt 1: ALL CONTROLS PASSED
fixed attempt 2: ALL CONTROLS PASSED
vulnerable-1/hop4-command-execution.txt contains:
uid=0(root) gid=0(root) ...
root
COMMAND_EXEC_<run-tag>_1
The fixed task control records:
target_path_reached=true
status=403
root_marker_present=false
Every artifact listed by runtime_manifest.json existed after execution and its SHA-256 matched the manifest. The manifest binds 72 finalized proof artifacts from the successful run and identifies the vulnerable target by immutable image digest. Raw login responses include ephemeral JWTs because the ticket requires retaining the complete authentication hop; they are unique throwaway credentials for deleted test containers, not reusable secrets.
Recommendations / Next Steps
- Upgrade all affected deployments to ArangoDB 3.12.11 or later.
- Canonicalize/decode the route once, reject ambiguous encodings, and use exactly that representation for authentication, authorization, and dispatch.
- Make privileged task context a server-side authorization decision. Ignore or reject client
isSystem:trueunless the caller holds explicit superuser/internal authority. - Run
arangodas a dedicated non-root operating-system user and constrain its writable filesystem paths; this reduces consequences but does not replace the code fixes. - Until upgrade, disable system-only authentication (
--server.authentication-system-only false) so every route requires authentication. - Treat credentials and JWT material on previously exposed servers as compromised; rotate user passwords and server JWT secrets.
- Add integration tests that send raw percent-encoded request targets through the HTTP listener and compare vulnerable/fixed outcomes, plus tests proving database-RW users cannot create Internal-context tasks.
- Add chain tests that retain every request/response and use a privileged file consumer negative control, preventing regressions in cross-boundary composition.
Additional Notes
- The final script is self-contained except for standard sandbox tools (
docker,curl,jq, Python 3,sha256sum, andtimeout) and creates its raw-socket helper at runtime. It does not execute files from the prepared source checkout. - The script is idempotent: it uses unique container names, ports, task IDs, and markers, removes containers on exit, and rebuilds the four proof-attempt directories per run.
- Runtime can take roughly two minutes because each vulnerable attempt waits for a genuine minute-boundary cron tick, bounded to 95 seconds.
- Empty-reply messages during readiness are expected while
arangodstarts; the health loop requires a valid HTTP status before proceeding. - The setup root password is intentionally weak solely to validate the ticket's documented fallback precondition. There is no claim that every affected real deployment uses a weak password. The unauthenticated data compromise and persistent
_usersmodification do not require that condition, while this immediate authenticated continuation does.
REPRO-2026-00355 Reproduction Transcript
The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.
Full session Replay every step — scrub the timeline or play it back.
docker ps --format '{{.ID}} {{.Image}} {{.Names}}'; docker image ls --digests --format '{{.Repository}}:{{.Tag}} {{.Digest}} {{.ID}}' | grep -E 'arangodb|REPOSITORY' || true; git --version; uname -mgit version 2.55.0 x86_64
Artifacts and Evidence for REPRO-2026-00355
Scripts, logs, diffs, and output captured during the reproduction.
How to Fix REPRO-2026-00355
Upgrade ArangoDB server · other to ArangoDB 3.12.11 is patched for both advisories. or later.
FAQ: REPRO-2026-00355
Is REPRO-2026-00355 exploitable?
How severe is REPRO-2026-00355?
What type of vulnerability is REPRO-2026-00355?
Which versions of ArangoDB server are affected by REPRO-2026-00355?
Is there a fix for REPRO-2026-00355?
How can I reproduce REPRO-2026-00355?
Is the REPRO-2026-00355 reproduction verified?
References for REPRO-2026-00355
Authoritative sources for REPRO-2026-00355 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.