Skip to content

Add WordPress adversarial Playground adapter#2028

Merged
chubes4 merged 1 commit into
mainfrom
feat-2017-wordpress-adversarial-adapter
Jul 24, 2026
Merged

Add WordPress adversarial Playground adapter#2028
chubes4 merged 1 commit into
mainfrom
feat-2017-wordpress-adversarial-adapter

Conversation

@chubes4

@chubes4 chubes4 commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add a WordPress-owned adversarial adapter to runtime-playground without changing runtime-core
  • translate supported REST, block, shortcode, serialized value, option/meta, file, cron, CLI, role/capability, and multisite membership mutations onto existing WordPress and runtime primitives
  • add WordPress oracle mappings, bounded hashed novelty signals, explicit clock and transport fidelity matrices, and persistent WordPress HTTP API fault interception
  • add disposable intentionally vulnerable plugin/theme fixtures and executable authorization/state-corruption campaigns

Refs #2017
Issue: #2017

Architecture and layering

  • WordPress policy and names live entirely in packages/runtime-playground/src/wordpress-adversarial-adapter.ts.
  • packages/runtime-core has no diff. The adapter consumes the merged generic campaign, oracle, transport-fault, clock, episode, artifact, and recipe contracts.
  • Existing Core/WordPress primitives are used directly: WP_REST_Request/rest_do_request(), block APIs, do_shortcode(), serialization helpers, options/meta APIs, cron APIs, role/user APIs, multisite membership APIs, pre_http_request, existing WP-CLI execution, checkpoints, and existing artifact sealing/redaction.
  • Network remains denied by the runtime default; the HTTP fault adapter writes a disposable MU plugin and fault model only inside the contained runtime.

Fidelity matrix

Surface Fidelity Notes
REST, blocks, shortcodes, serialized values, options/meta, files, cron actions, CLI, roles/capabilities exact Uses native WordPress/runtime APIs
Multisite membership exact when multisite Explicitly unsupported in a single-site runtime
AJAX, XML-RPC unsupported In-process execution cannot preserve their terminating HTTP boundaries honestly
HTTP response substitution exact pre_http_request substitution
HTTP malformed/truncated response, delay, timeout, refusal/reset emulated WordPress HTTP API boundary, not socket behavior
Chunking, bandwidth, jitter, half-close, disconnect-after-bytes, remap, wire corruption unsupported Left to #2018
Browser clock exact Existing Playwright controller
Cron scheduler clock emulated Selects and invokes due events at an explicit timestamp; does not alter background spawn time
PHP/WordPress global and database clocks unsupported No supported global clock injection primitive exists in this Playground runtime

Fixtures and findings

  • Fixture defects included: authorization/nonce bypass, code injection, partial state commit, non-atomic race, external-service fail-open, AJAX nonce bypass, shortcode/theme reflected output, duplicated UI effect, and stuck loading state.
  • Live campaigns currently demonstrate authorization bypass and partial state commit.
  • The live Playground run produced two sealed findings with fingerprint 3730994076f0fd524accf26ca34dd479e0d2ff1d439449fd4dc3cce8156f3462 in separate campaign bundles.
  • Authorization evidence digest: 720badbd511eb07733153384f2b101ffe45549b88aa1c04586587c2a026531b0; 9 redactions were applied.
  • State evidence digest: 918ef9ac05b2a607b22c7664d4185153b5cd390dabde9797d55935305234aece.
  • Runtime runtime-mrzekjrm-fc0i5o ended destroyed; replay runtime runtime-mrzep43q-sc8t34 also ended destroyed.
  • Absolute-path replay completed with status: findings and adversarial-replay-completed, reproducing the minimized authorization case in a fresh runtime.

Verification

  • npm run build passed.
  • npm run test:release-package-coverage passed.
  • npm run test:adversarial-runtime passed: 14/14.
  • npm run test:fuzz-run-recipe passed.
  • npm run test:nested-fuzz-suite-recipe-command passed.
  • npm run test:production-boundary-enforcement passed.
  • npm run test:runtime-contract-package-exports passed.
  • npm run test:public-api-contract passed.
  • npm run wp-codebox:source -- recipe validate --recipe examples/recipes/wordpress-adversarial-vulnerable.json --json passed.
  • PHP syntax checks passed for the plugin and theme fixtures.
  • Live command: npm run wp-codebox:source -- adversarial run --recipe examples/recipes/wordpress-adversarial-vulnerable.json --timeout 10m --json.
  • Replay command: npm run wp-codebox:source -- adversarial replay --recipe examples/recipes/wordpress-adversarial-vulnerable.json --replay <absolute-sealed-replay-path> --timeout 10m --json.
  • npm run check reaches the unchanged known command-registry-smoke fails on main: wordpress.collect-workload-result outputShape missing outputSchema id mention #1745 failure: wordpress.collect-workload-result outputShape should mention outputSchema id. scripts/command-registry-smoke.ts has identical SHA-256 on this branch and origin/main: 7ecfe041efbcadaa05040959860696639c7208b3cfc1c68c35780703f37d6b59.

Compatibility

  • Existing recipe validation, nested static fuzz recipes, production boundaries, package exports, and public API contracts remain intact.
  • No recipe schema or runtime-core changes were needed.
  • Existing static fuzzRun behavior is unchanged.

Residual scope

  • Recipe orchestration does not currently advertise isolated-workers, so deterministic same-state concurrent campaign replay cannot be declared without failing validation. The fixture includes a true widened race, but this PR does not claim it is automatically discovered/replayed.
  • Injection, race, external-service recovery, and minimized browser/UI journeys are represented by fixtures but do not yet have live automated campaigns in this PR.
  • AJAX and XML-RPC need faithful server request adapters rather than unsafe in-process callback invocation.
  • PHP/WordPress global clock and database clock control remain unsupported; scheduler control is explicitly emulated.
  • Expected finding steps currently cause the overall recipe command to exit nonzero even though sealed findings are produced and replay completes.
  • Relative replay paths resolve from the recipe directory; the verified replay used an absolute sealed path.
  • Exact socket-level faults remain Add an exact transport fault proxy provider #2018.

Because these acceptance criteria remain open, this PR intentionally uses Refs #2017 rather than closing the issue.

AI assistance

  • AI assistance: Yes
  • Tool: OpenCode
  • Used for: implementation, fixture/campaign construction, verification, live Playground execution, and PR drafting

@chubes4
chubes4 merged commit 2dfb11a into main Jul 24, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant