# File Browser has a Command Execution Allowlist Bypass via Shell Metacharacter Injection

File Browser's command allowlist checks only the first token, so shell metacharacters in the raw input let an Execute-permission user run arbitrary OS commands as root.

- Payout: Research
- Severity: high
- Program: File Browser
- Found by: RajChowdhury240
- Disclosed: 2026-06-12
- CVE: CVE-2026-54090
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-8c9q-7855-wfxq
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-8c9q-7855-wfxq
- Tags: area:web domain:web impact:privesc impact:rce kind:research platform:ghsa sev:high tech:go technique:source-review vuln:access-control vuln:command-injection

**Target:** WebSocket command execution endpoint (/api/command/) with shell interpreter configured
**Root cause:** ParseCommand extracts only the first token for the allowlist check but passes the entire raw user string to the configured shell (`/bin/sh -c`), so metacharacters chain arbitrary commands after an allowed one.
**Steps:**
1. Configure instance with command execution enabled (`--disable-exec=false`) and shell `/bin/sh -c`, user allowlist e.g. `git,ls,cat`.
2. Authenticate: `POST /api/login` with `{"username":"admin","password":"..."}` to get a JWT.
3. Open WebSocket to `/api/command/` with header `X-Auth: <jwt>`.
4. Send `ls; id; whoami; cat /etc/passwd` — all commands execute and output returns; `whoami` alone returns "Command not allowed."
**How found:** Noticed the allowlist validates only the first token from SplitCommandAndArgs while the full raw string is appended to the shell invocation, then confirmed by sending a semicolon-chained payload versus a bare disallowed command.
**Exploitation:** Any user holding Execute permission plus one allowlisted command sends a metacharacter-chained payload over the authenticated command WebSocket; the shell runs the trailing commands at the server process privilege (root in the default container) and returns combined output.
**Insight:** When an allowlist is enforced on a parsed token but the raw string reaches a shell, test whether the check and the execution consume different representations — semicolons, pipes, backticks, `$()` after a permitted first token.

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

**WebSocket payload chaining commands after allowed 'ls'**

```
ls; id; whoami; cat /etc/passwd
```

