performwp / performwp/perform

Make the settings AJAX endpoint a strict schema boundary

Open
#202 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area: settings bug owner:codex priority: medium risk: backward-compatibility status: ready
Dominant language
PHP
Stars
5
Forks
2
PR merge metrics
No merged PRs in 30d

Description

Problem

The authenticated settings AJAX endpoint validates known fields, but preserves unknown request keys in the canonical perform_settings option. Arrays for unknown keys are recursively accepted without a schema or size bound. This is not an unauthenticated privilege-escalation path because the endpoint correctly requires manage_options and a nonce, but it weakens the settings contract, permits option bloat, and makes accidental or extension-supplied state persist indefinitely.

Evidence

  • src/Admin/Settings/Menu.php:76-96 correctly enforces manage_options and the perform_save_settings nonce.
  • src/Admin/Settings/Menu.php:122-178 looks up field definitions but falls back to preserving undefined scalar and array keys.
  • src/Admin/Settings/Menu.php:181-192 merges those values into the canonical option and persists them.
  • src/Includes/Helpers.php:145-151 recursively cleans arrays but does not impose shape, key, depth, or item-count bounds.
  • Current settings tests cover list normalization but not rejection of unknown keys or malformed payloads.

Scope

Make the React settings endpoint a strict, documented schema boundary without changing released option keys or legitimate extension hooks.

Implementation plan

  1. Build an allowlist from the declared settings field IDs plus the small set of documented control fields.
  2. Reject or ignore unknown keys before merging; return a clear JSON error only for malformed first-party payloads, without echoing submitted secrets.
  3. Define per-field normalization for scalar, list, textarea, URL, toggle, number, and select values, including reasonable list-size and string-length bounds.
  4. Preserve masked-secret behavior and existing multiline/cache-bypass normalization.
  5. Provide an explicit, documented extension filter only if current integrations require custom settings persistence; it must be opt-in and validate its own keys.
  6. Add PHPUnit coverage for unknown scalars/arrays, invalid select values, malformed JSON, oversized lists, masked secrets, and a valid settings save.

Acceptance criteria

  • Only registered settings keys are written to perform_settings by this endpoint.
  • Unknown scalar and nested-array input cannot grow or alter the stored option.
  • Legitimate settings, masked Cloudflare secrets, multiline resource hints, and cache bypass lists retain their existing storage contract.
  • Errors are capability-safe and do not expose submitted secrets or option contents.

Validation

  • composer test
  • composer phpstan
  • PHPCS on changed PHP files
  • Isolated administrator save proof with a valid payload and rejected unknown-key payload.

Non-goals and risk

  • Do not alter roles/capabilities, nonce lifetime, secret transport, or public option names.
  • Any decision to support third-party custom settings keys is an owner-gated backward-compatibility decision.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with src/Admin/Settings/Menu.php:122-192 and src/Includes/Helpers.php:145-151, then locate the existing settings tests covering list normalization. Run the focused PHPUnit tests before broad validation with composer test, composer phpstan, and PHPCS. Done means unknown and malformed inputs are rejected or ignored, valid settings and masked secrets retain their storage contract, and the requested coverage passes without exposing secrets.

Written by the indexing model from the issue text.

Assessment

Tech stack
php
Domain
api, backend, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.