Skip to content

proc_open/exec/popen silently fail — createNoopSpawnHandler replaces real process spawning #3044

@chubes4

Description

@chubes4

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

  1. 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)
  2. Automattic's own php-mcp-client: Uses proc_open to spawn MCP servers — completely broken in Studio
  3. Plugin/theme code: Any WordPress code calling exec(), proc_open(), etc. silently gets nothing back
  4. 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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions