## Summary

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.

## Impact

- **Affected package/component:** ArangoDB HTTP server, principally `RestActionHandler`/action dispatch for the encoded-path bypass and `RestTasksHandler`/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.1` linux/amd64 image at immutable digest `sha256:01be938f3a8d3e82725d365ca6750e4cafd092ec78a33a027588cfac37be4e51`.
- **Tested fixed target:** official `arangodb:3.12.11` linux/amd64 image at immutable digest `sha256: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 `arangod` operating-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 `_users` persistence, authenticated root with a password recovered from the leaked weak single-round hash, accepted an authenticated `isSystem:true` task, wrote a root crontab, and produced attacker-selected `id`/`whoami`/marker output as UID 0 through `crond`.
- **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 `_users` persistence 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:

1. **Raw-versus-decoded authorization differential (GHSA-rrgq-978q-36mq).** `RestActionHandler::hasAllowedUnauthenticatedPath()` decides whether a request is an unauthenticated application route from the raw `requestPath()`. 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 `%5fapi` into `_api` and dispatching a privileged JavaScript simple action under the superuser execution scope. The action itself assumes that the outer handler already enforced authorization.

2. **Missing authorization for privileged task mode (GHSA-rvhw-4hpw-9vrx).** `RestTasksHandler` reads `isSystem` directly 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

1. Run `bundle/repro/reproduction_steps.sh` from any directory. The script derives portable paths from its own location and accepts `PRUVA_ROOT`.
2. The script executes immutable official Docker image digests, starts the real `arangod` HTTP service, waits for health, and seeds a protected marker plus a weak-password deployment condition through legitimate administration.
3. For each of two vulnerable instances, it retains exact raw HTTP requests and full raw responses for:
   - literal protected-path `401` control;
   - unauthenticated `%5f` protected-document and root-authData reads;
   - bounded password recovery from the leaked hash;
   - unauthenticated attacker-selected root-authData update/read-back;
   - real `/ _open/auth` login (without the space; exact path is `/_open/auth`);
   - authenticated `PUT /_api/tasks/{id}` with Boolean `isSystem:true`;
   - root-only task file/crontab evidence; and
   - `crond` command output containing `uid=0(root)`, `root`, and a per-attempt marker.
4. 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 real `isSystem:true` task request reaches the endpoint but fails with `403` and creates no root marker.
5. 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/` and `bundle/repro/proof/vulnerable-2/`.
- Fixed attempt directories: `bundle/repro/proof/fixed-1/` and `bundle/repro/proof/fixed-2/`.

Key current-run observations include:

```text
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:

```text
uid=0(root) gid=0(root) ...
root
COMMAND_EXEC_<run-tag>_1
```

The fixed task control records:

```text
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:true` unless the caller holds explicit superuser/internal authority.
- Run `arangod` as 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`, and `timeout`) 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 `arangod` starts; 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 `_users` modification do not require that condition, while this immediate authenticated continuation does.
