{"id":"GHSA-g3hq-hphg-8fhh","title":"Pheditor: Terminal command-allowlist bypass via argument injection leads to RCE — surviving vector after the metacharacter-sanitization fixes","summary":"Pheditor: Terminal command-allowlist bypass via argument injection leads to RCE — surviving vector after the metacharacter-sanitization fixes","severity":"high","cvss":8.8,"cwe":["CWE-78","CWE-88"],"vendor":"pheditor","product":"pheditor/pheditor","ecosystem":"composer","affected":["pheditor/pheditor <= 2.0.6"],"patched":["pheditor/pheditor 2.0.7"],"published":"2026-07-24","updated":"2026-07-24","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-g3hq-hphg-8fhh","references":[{"url":"https://github.com/pheditor/pheditor/security/advisories/GHSA-g3hq-hphg-8fhh"},{"url":"https://github.com/pheditor/pheditor/commit/f40f5070d5a171b65359bc87568734d31de498e1"},{"url":"https://github.com/pheditor/pheditor/releases/tag/2.0.7"},{"url":"https://github.com/advisories/GHSA-g3hq-hphg-8fhh"}],"tags":["ghsa","composer"],"ingestedAt":"2026-07-24T22:40:27.178Z","slug":"GHSA-g3hq-hphg-8fhh","body":"## Overview\n\n### Summary\n\npheditor's terminal feature restricts callers to an allowlist of commands (`TERMINAL_COMMANDS`) and rejects shell metacharacters. The allowlist is enforced as a PREFIX match with no argument validation, and the allowlist includes binaries that grant arbitrary command execution through their own options (`find`, `git`, `php`, `tar`, `grep`). A caller can therefore run any command using only allowlisted binaries and no rejected metacharacter, escaping the allowlist restriction the terminal feature relies on.\n\n### Relationship to the prior terminal advisories (this is a surviving, distinct vector)\n\nThe prior terminal advisories were all shell-metacharacter injections: GHSA-9643-6xjp-vx57 (`$()`), GHSA-wg4w-wr5q-6vjc (`|`, backtick, newline), GHSA-jvc5-58fv-w8cq (`;` via the dir field). The current code rejects those characters. This report is a different class — CWE-88 argument injection through an allowlisted binary's flags — which the metacharacter denylist does not address.\n\n### Root cause (HEAD, v2.0.6)\n\nIn the `terminal` action handler of `pheditor.php`:\n1. `:588` rejects `&`, `;`, `|`, `$`, backtick, `\\n`, `\\r`. It does NOT reject space, `-`, `{`, `}`, `+`, `/`, `.`.\n2. `:595-605` checks the command against `TERMINAL_COMMANDS` (defined `:25`: `ls,...,php,...,git,find,grep,...,tar,...,composer,exit`) using a PREFIX match: `strlen($command) >= strlen($value) && substr($command, 0, strlen($value)) == $value`. There is no word boundary and no validation of the arguments that follow.\n3. `:617` runs the command through the shell unchanged: `shell_exec((empty($dir) ? null : 'cd ' . escapeshellarg($dir) . ' && ') . $command . ' && echo \\ ; pwd')`.\n\nSo a command beginning with an allowlisted binary, carrying a code-exec flag, and containing none of the rejected characters reaches `shell_exec` intact.\n\n### Proof of concept (reproduced)\n\nPOST to the terminal action with:\n  command = `find . -maxdepth 0 -exec touch /tmp/PWNED {} +`\n  dir = (any)\n\nThis contains no rejected metacharacter, prefix-matches the allowlisted `find`, and `find -exec` runs an arbitrary program. A faithful harness mirroring the three guards (`poc/reproduction.sh`, `poc/transcript.txt`) creates the marker file. Other allowlisted-binary payloads with the same property: `git -c alias.x='!touch /tmp/PWNED' x`, `php -r 'system(\"id\");'`, `tar -cf /dev/null --checkpoint=1 --checkpoint-action=exec=\"touch /tmp/PWNED\" .`.\n\n### Impact\n\nArbitrary command execution on the host, under the web server's privileges, for a caller with the `terminal` permission (enabled in the default configuration). The exposure is amplified by GHSA-p4h7-p9rj-2pq2 (hardcoded default `admin` password with no forced change): a default deployment grants the authenticated access needed to reach the terminal action with a single known credential, making the chain effectively unauthenticated RCE.\n\n### Remediation\n\nValidate the FULL command, not just its prefix: tokenize and require the program to be an allowlisted binary AND constrain its arguments (reject `-exec`/`-execdir` for `find`, `-c`/`--upload-pack` for `git`, `-r`/`-d` for `php`, `--checkpoint-action`/`--to-command` for `tar`, `-f`/`--file` program forms, etc.), or run each command as an argv array through a restricted launcher with no shell, or remove the code-exec-capable binaries from the allowlist. A prefix allowlist over a shell sink cannot constrain capability.\n\nCredit: anir0y (independent security research).\n\n## Affected packages\n\n- `pheditor/pheditor <= 2.0.6`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `pheditor/pheditor 2.0.7`","depth":"twilight","depthScore":48,"depthScoreParts":{"impact":48.4,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}