Skip to content

Fix merge conflicts in https://github.com/plausible/wordpress/pull/300#307

Open
Dan0sz wants to merge 13 commits into
developfrom
a8cteam51-feature/harden-proxy-api
Open

Fix merge conflicts in https://github.com/plausible/wordpress/pull/300#307
Dan0sz wants to merge 13 commits into
developfrom
a8cteam51-feature/harden-proxy-api

Conversation

@Dan0sz

@Dan0sz Dan0sz commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

This PR fixes the merge conflicts in #300

Summary by CodeRabbit

  • Security
    • Stricter proxy endpoint request validation
    • Same-origin checks enforced when configured
    • Request size capped at 8 KB
    • JSON payload structure validated before processing
    • Proxy routes hidden from REST API discovery
    • Improved HTTP response handling and validation

crweiner and others added 8 commits April 9, 2026 12:08
… in Proxy.php and URL length check in MU plugin

Agent-Logs-Url: https://github.com/crweiner/plausible-wordpress-plugin/sessions/b35d7e5f-5764-4ad1-9b52-a62192c6ac6b

Co-authored-by: crweiner <23106097+crweiner@users.noreply.github.com>
…es return a 404 so you cant assume an endpoint exists based on response
Added hardening to the host matching and also to ensure that all rout…
- Guard n/d/u with isset + is_string before string ops to avoid
  TypeError on non-string payloads (which would surface as 500s
  and defeat the uniform-404 design).
- Use === '' instead of empty() for n and u so legitimate values
  like 0 aren't rejected.
- Strip scheme and www. from the home_url() fallback in
  get_expected_domain() so it returns a bare domain matching
  Helpers::get_domain(), preventing silent rejection of valid
  payloads on sites without a configured domain_name setting.
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@Dan0sz, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 25 minutes. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0fab0c3e-5608-434a-b776-5a714990930c

📥 Commits

Reviewing files that changed from the base of the PR and between a2077aa and d7753d8.

📒 Files selected for processing (2)
  • mu-plugin/plausible-proxy-speed-module.php
  • src/Proxy.php
📝 Walkthrough

Walkthrough

Adds cached proxy config and an early mu-plugin short-circuit that rejects non-conforming proxy paths; implements multi-stage validation (method, JSON type, provenance, size, payload, host/domain normalization) in both mu-plugin and REST Proxy, hides proxy routes from REST discovery, and centralizes uniform JSON no-route errors.

Changes

Proxy Request Hardening with Early Detection and Validation

Layer / File(s) Summary
Request Size Limit Constants
mu-plugin/plausible-proxy-speed-module.php, src/Proxy.php
Both files define MAX_REQUEST_BYTES = 8192 to enforce a hard cap on request body size during validation.
Mu-plugin: Cached Proxy Resources & Path Detection
mu-plugin/plausible-proxy-speed-module.php
Cache plausible_analytics_proxy_resources on init and detect proxy requests by checking request path prefix against the cached namespace via get_request_path().
Mu-plugin: Short-Circuit Validation Flow
mu-plugin/plausible-proxy-speed-module.php
Early short-circuit for proxy paths performing ordered checks (namespace index vs exact endpoint, method, JSON Content-Type, provenance, request size, payload) and responding with a uniform JSON no-route error.
Headers, Method, and Provenance Checks
mu-plugin/plausible-proxy-speed-module.php
Normalize request method, enforce application/json Content-Type prefix, and validate Origin/Referer host against home_url() when plausible_analytics_proxy_require_same_origin requires it.
Host and Domain Normalization
mu-plugin/plausible-proxy-speed-module.php
Provide host extraction and domain normalization utilities (strip scheme/www, lowercase, trim trailing dots) for consistent comparisons.
Request Body Size Enforcement and Cached Reader
mu-plugin/plausible-proxy-speed-module.php
Cap reads from php://input at MAX_REQUEST_BYTES + 1, cache the raw body, and expose a size-check helper.
JSON Payload Shape and Field Validation
mu-plugin/plausible-proxy-speed-module.php
Decode JSON to array, restrict allowed top-level keys, validate required string fields (n, d, u) with length bounds, optionally validate p type, and verify domain/URL host match rules.
Centralized JSON Error Response
mu-plugin/plausible-proxy-speed-module.php
Unify error replies with send_json_error(): set HTTP status, application/json with WP charset, structured {code,message,data:{status}} body, and exit.
REST Filters Registration and Route Wiring
src/Proxy.php
Register REST filters to block namespace index probing and hide proxy routes from discovery; change route permission_callback to validate_proxy_request.
REST Validation and Discovery Methods
src/Proxy.php
Add maybe_block_namespace_index(), hide_route_discovery(), and validate_proxy_request() enforcing body size, JSON content type, provenance, allowed keys, domain and URL host matching, and consistent rejection via REST helpers.
Response Code Extraction Hardening
src/Proxy.php
Guard response data structure and Plausible code presence before deriving and forcing an HTTP response code.

Possibly related PRs

  • plausible/wordpress#297: Tightens proxy request detection via is_proxy_request() and request URI matching; overlaps with detection and short-circuit logic.
  • plausible/wordpress#306: Modifies proxy request detection and eligibility logic in the mu-plugin, related to namespace-prefix matching and rewrite initialization.

Poem

A rabbit hops through proxy gates,
Counting bytes and checking traits,
Origins match, the JSON's clean,
Paths are tight, no ghosts between—
Short-circuits guard the analytics streams. 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title refers to fixing merge conflicts from PR #300, but the actual changes implement significant proxy API hardening with request validation, size limiting, and security improvements—not merge conflict resolution. Update the title to reflect the main change: 'Harden proxy API with request validation and size limiting' or similar, which accurately describes the substantial security improvements in the changeset.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch a8cteam51-feature/harden-proxy-api

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov

codecov Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 6.06061% with 93 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/Proxy.php 6.06% 93 Missing ⚠️

📢 Thoughts on this report? Let us know!

@Dan0sz

Dan0sz commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review this PR

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

@Dan0sz Sure, I'll review the PR right away!

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

@Dan0sz Sure, I'll review the PR right away!

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
mu-plugin/plausible-proxy-speed-module.php (1)

283-284: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Missing filter application for max body size creates inconsistency with REST layer.

The REST-side validation in src/Proxy.php uses apply_filters('plausible_analytics_proxy_max_body_bytes', self::MAX_REQUEST_BYTES) to allow configuration of the body size limit. This mu-plugin uses the hardcoded constant directly, so if someone uses the filter to adjust the limit, the two validation layers will enforce different thresholds.

🔧 Suggested fix
 	private function request_body_too_large() {
-		return strlen( $this->get_request_body() ) > self::MAX_REQUEST_BYTES;
+		$max_request_bytes = (int) apply_filters( 'plausible_analytics_proxy_max_body_bytes', self::MAX_REQUEST_BYTES );
+
+		return $max_request_bytes > 0 && strlen( $this->get_request_body() ) > $max_request_bytes;
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mu-plugin/plausible-proxy-speed-module.php` around lines 283 - 284, The
request_body_too_large() method uses the hardcoded self::MAX_REQUEST_BYTES,
causing mismatch with the REST layer; update request_body_too_large() to obtain
the limit via the same filter used in src/Proxy.php by calling
apply_filters('plausible_analytics_proxy_max_body_bytes',
self::MAX_REQUEST_BYTES) and compare strlen($this->get_request_body()) against
that filtered value so both layers enforce the same configurable max body size.
🧹 Nitpick comments (1)
mu-plugin/plausible-proxy-speed-module.php (1)

363-364: 💤 Low value

Consider using str_starts_with() for consistency.

The rest of the file uses str_starts_with() (e.g., lines 93, 215), but this line uses the older strpos(...) === 0 pattern.

♻️ Suggested refactor
-		if ( ! $host && strpos( $url, '/' ) === 0 ) {
+		if ( ! $host && str_starts_with( $url, '/' ) ) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@mu-plugin/plausible-proxy-speed-module.php` around lines 363 - 364, The
condition checking whether $url starts with '/' uses strpos(...) === 0
inconsistently; in the same file other checks use str_starts_with(). Update the
check inside the function in plausible-proxy-speed-module.php (the block that
currently reads if ( ! $host && strpos( $url, '/' ) === 0 ) ) to use
str_starts_with($url, '/') instead, keeping the existing !$host guard and return
true behavior so the logic remains identical while matching the file's style.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@mu-plugin/plausible-proxy-speed-module.php`:
- Around line 283-284: The request_body_too_large() method uses the hardcoded
self::MAX_REQUEST_BYTES, causing mismatch with the REST layer; update
request_body_too_large() to obtain the limit via the same filter used in
src/Proxy.php by calling
apply_filters('plausible_analytics_proxy_max_body_bytes',
self::MAX_REQUEST_BYTES) and compare strlen($this->get_request_body()) against
that filtered value so both layers enforce the same configurable max body size.

---

Nitpick comments:
In `@mu-plugin/plausible-proxy-speed-module.php`:
- Around line 363-364: The condition checking whether $url starts with '/' uses
strpos(...) === 0 inconsistently; in the same file other checks use
str_starts_with(). Update the check inside the function in
plausible-proxy-speed-module.php (the block that currently reads if ( ! $host &&
strpos( $url, '/' ) === 0 ) ) to use str_starts_with($url, '/') instead, keeping
the existing !$host guard and return true behavior so the logic remains
identical while matching the file's style.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 526cd647-a498-48b1-aaac-4d4c84e4db7b

📥 Commits

Reviewing files that changed from the base of the PR and between 404cf06 and a2077aa.

📒 Files selected for processing (1)
  • mu-plugin/plausible-proxy-speed-module.php

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.

4 participants