Summary
createNoopSpawnHandler() unconditionally replaces PHP process spawning with a handler that immediately exits with code 1. This silently breaks proc_open, exec, shell_exec, popen, and system — with no error message or user feedback.
Built JS location: Resources/cli/index-BfPBbX5j.js line 1802
Applied at: lines 1827 and 1868 (site-specific and global WP-CLI execution)
function createNoopSpawnHandler() {
return createSpawnHandler(async (args, processApi) => {
await new Promise((resolve) => setTimeout(resolve, 1));
processApi.exit(1); // Always fails. No error message.
});
}
Impact
- WP-CLI internals:
wp --info, wp db export, MySQL binary detection, and any command using WP_CLI\Process fail silently (see STU-1275, which reported the symptom but was closed without fixing the root cause)
- Automattic's own php-mcp-client: Uses
proc_open to spawn MCP servers — completely broken in Studio
- Plugin/theme code: Any WordPress code calling
exec(), proc_open(), etc. silently gets nothing back
- No feedback: The no-op exits with code 1 but produces no warning, log entry, or error message — developers have no way to know why their code isn't working
php-wasm supports this
The Playground php-wasm runtime explicitly provides php.setSpawnHandler() as a supported API. The php-wasm documentation shows php.setSpawnHandler(require('child_process').spawn) as a usage pattern. The infrastructure for real process spawning is already there — Studio just opts out of it.
Security consideration
I understand the instinct to sandbox process execution. But the current approach is the worst of both worlds: it provides no security feedback (silent failure) while breaking legitimate functionality. Consider:
- Studio already grants PHP full filesystem access to the site folder via
createNodeFsMountHandler mounts
- Every other local WordPress dev tool (Local, MAMP, Docker, wp-env) allows process spawning
- Studio is a local development tool, not a production hosting environment
- The user explicitly chose to install and run their code
A scoped approach would be better than a blanket no-op — for example, a spawn handler with logging/warnings, or an opt-in setting. But the silent no-op should be replaced.
Suggested fix
At minimum, replace the no-op with a handler that bridges to Node.js child_process.spawn:
function createNoopSpawnHandler() {
const { spawn } = require("child_process");
return spawn;
}
php-wasm's internal handler already supports receiving a child_process.spawn-compatible function directly.
If full bridging is considered too permissive, consider:
- A spawn handler with logging (so failures aren't silent)
- An allowlist of safe executables
- A user-facing setting to enable process spawning
Related
- STU-1275 — reported
proc_open failure symptom in wp --info, closed without addressing root cause
Summary
createNoopSpawnHandler()unconditionally replaces PHP process spawning with a handler that immediately exits with code 1. This silently breaksproc_open,exec,shell_exec,popen, andsystem— with no error message or user feedback.Built JS location:
Resources/cli/index-BfPBbX5j.jsline 1802Applied at: lines 1827 and 1868 (site-specific and global WP-CLI execution)
Impact
wp --info,wp db export, MySQL binary detection, and any command usingWP_CLI\Processfail silently (see STU-1275, which reported the symptom but was closed without fixing the root cause)proc_opento spawn MCP servers — completely broken in Studioexec(),proc_open(), etc. silently gets nothing backphp-wasm supports this
The Playground php-wasm runtime explicitly provides
php.setSpawnHandler()as a supported API. The php-wasm documentation showsphp.setSpawnHandler(require('child_process').spawn)as a usage pattern. The infrastructure for real process spawning is already there — Studio just opts out of it.Security consideration
I understand the instinct to sandbox process execution. But the current approach is the worst of both worlds: it provides no security feedback (silent failure) while breaking legitimate functionality. Consider:
createNodeFsMountHandlermountsA scoped approach would be better than a blanket no-op — for example, a spawn handler with logging/warnings, or an opt-in setting. But the silent no-op should be replaced.
Suggested fix
At minimum, replace the no-op with a handler that bridges to Node.js
child_process.spawn:php-wasm's internal handler already supports receiving a
child_process.spawn-compatible function directly.If full bridging is considered too permissive, consider:
Related
proc_openfailure symptom inwp --info, closed without addressing root cause