{"id":"GHSA-g3hq-hphg-8fhh","aliases":[],"url":"https://o3.security/vulnerability/GHSA-g3hq-hphg-8fhh","summary":"Pheditor: Terminal command-allowlist bypass via argument injection leads to RCE — surviving vector after the metacharacter-sanitization fixes","details":"### 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).","published":"2026-07-24T21:45:40Z","modified":"2026-07-24T22:00:28.100901242Z","cvss":{"score":8.8,"severity":"HIGH","vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"},"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"Packagist","name":"pheditor/pheditor","fixedVersion":"2.0.7"}],"fix":{"url":"https://github.com/pheditor/pheditor/commit/f40f5070d5a171b65359bc87568734d31de498e1","label":"pheditor/pheditor@f40f507"},"references":[{"type":"WEB","url":"https://github.com/pheditor/pheditor/security/advisories/GHSA-g3hq-hphg-8fhh"},{"type":"WEB","url":"https://github.com/pheditor/pheditor/commit/f40f5070d5a171b65359bc87568734d31de498e1"},{"type":"PACKAGE","url":"https://github.com/pheditor/pheditor"},{"type":"WEB","url":"https://github.com/pheditor/pheditor/releases/tag/2.0.7"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-07-24T22:00:28.100901242Z"}}