Skip to content

v0.2.2 — Sitemap SSRF hardening, request backpressure, and a real PHPUnit suite for the plugin

Choose a tag to compare

@github-actions github-actions released this 04 Sep 14:48
· 63 commits to main since this release
14d0ad2

[0.2.2] - 2026-09-04

Security

  • Sitemap fetching now goes through the same SSRF protections already applied everywhere else in this service. It previously used a plain, unprotected fetch() - a compromised or misconfigured sitemap index could have pointed this service at an internal address or a cloud-metadata endpoint, and it would have fetched it directly. Every hop (the sitemap itself, every sub-sitemap, and any redirect along the way) is now blocked from reaching a private/reserved address, and sub-sitemap fetches are additionally restricted to the sitemap's own origin.
  • The WordPress receiver call now has a 10s timeout and a small bounded retry (network errors/5xx only, never a permanent 4xx rejection). This service processes work through a single queue worker, so a hung receiver call previously could have stalled every URL behind it indefinitely.
  • The in-memory generation queue is now bounded (500 entries by default, MAX_QUEUE_LENGTH env-overridable) - previously unbounded, so a leaked shared secret hammering /generate, or an unexpectedly huge sitemap, could grow memory use without limit. POST /generate now returns 503 (with Retry-After) instead of a misleading 202 when the queue is actually full, so callers know to retry instead of assuming their request was accepted.
  • The WordPress plugin's REST receiver now properly wp_unslash()s $_SERVER['REMOTE_ADDR'] before sanitizing it - a WordPress-coding-standards gap flagged by the official Plugin Check tool, not an exploitable issue on its own, but worth closing.

Fixed

  • A sitemap configured with a public IPv6 literal address was being incorrectly blocked as if it were private/reserved. A bracketed IPv6 literal (the form a URL's own hostname actually takes) was falling through to a DNS lookup that can't resolve a literal at all, and the failure was then treated as "couldn't verify it's safe, block it."

Added

  • The WordPress plugin now has an automated PHPUnit test suite, run against a real WordPress install on both its declared minimum PHP/WordPress versions and the current ones, plus WordPress Coding Standards (WPCS) and the official WordPress Plugin Check tool in CI. Previously the plugin side was only checked with php -l (syntax only) - none of its REST authentication, rate limiting, CSS sanitization, or storage logic was regression-tested.
  • The container image now also publishes to Docker Hub (solarssk/wp-critical-css) alongside GHCR, built once and pushed to both from the same image.

Deploy

  • Container image: ghcr.io/solarssk/wp-critical-css:0.2.2 (rolling :latest, :0.2), also published to docker.io/solarssk/wp-critical-css:0.2.2.
  • WordPress plugin: wp-critical-css-0.2.2.zip, attached to this release.
  • No migration steps - fully backward compatible with 0.2.1's stored data, configuration, and REST contract.

Full changelog