Skip to content

Send no-cache headers on the record preview response#187

Merged
pfefferle merged 1 commit into
trunkfrom
add/preview-nocache-headers
Jul 8, 2026
Merged

Send no-cache headers on the record preview response#187
pfefferle merged 1 commit into
trunkfrom
add/preview-nocache-headers

Conversation

@pfefferle

Copy link
Copy Markdown
Member

Proposed changes:

The ?atproto record preview is served on a public front-end URL but carries per-object, edit_post-gated data — a post's saved custom Bluesky text and any third-party preview-transformer output. Preview::send() sent no cache-control headers, so a URL-keyed edge/page cache that stores a logged-in response could replay an authorized projection to a later unauthorized visitor.

This calls \nocache_headers() on every branch that emits a preview response — the 200 record payload, the 400 error, and the unsupported-post-type 404 — mirroring the well-known handlers (serve_wellknown_atproto_did / serve_wellknown_publication), which already no-cache every branch. It does not hoist the call to the top of render(), because render()'s many fall-through return branches must leave the normal (cacheable) page render untouched.

Context: surfaced by a full-codebase security audit as the one open item; classified as defense-in-depth hardening (not an exploitable vulnerability) — the leak only bites under a misconfigured cache that stores logged-in responses and keys purely on URL, a config under which far more sensitive authenticated content would already leak site-wide. Fixing it brings the preview in line with the plugin's two other public GET surfaces.

Other information:

  • Have you written new tests for your changes, if applicable? — No: header emission on this exit-ing path can't be exercised under PHPUnit (the CLI harness has already sent headers), the same reason the sibling well-known handlers carry no header assertions. Verified instead against a live wp-env response (see below).

Testing instructions:

  • composer lint and npm run env-test pass (854 tests).
  • Connect a test account (or set atmosphere_identity), then as a logged-in editor request a post preview and inspect headers:
    curl -sI -b <editor-cookie-jar> 'http://localhost:8884/<post>/?atproto=app.bsky.feed.post' | grep -i cache-control
    # -> Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private
    
  • Confirm a logged-out request to the same URL still falls through to the normal HTML page (no JSON, no plugin cache header).
  • Confirm an unsupported post type (e.g. a page) returns 404 with the same Cache-Control header.

Changelog entry

A patch/fixed entry is included at .github/changelog/fix-preview-cache-headers.

The ?atproto preview is served on a public front-end URL but carries
per-object, edit_post-gated data (a post's custom Bluesky text and any
third-party preview-transformer output). Preview::send() sent no
cache-control headers, so a URL-keyed edge/page cache that stores a
logged-in response could replay an authorized projection to a later
unauthorized visitor. Call nocache_headers() on every branch, mirroring
the well-known handlers.
Copilot AI review requested due to automatic review settings July 8, 2026 07:02
@pfefferle pfefferle self-assigned this Jul 8, 2026
@pfefferle
pfefferle requested a review from a team July 8, 2026 07:02
@github-actions github-actions Bot added the [Feature] Transformer AT Protocol record transformers label Jul 8, 2026

Copilot AI 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.

Pull request overview

This PR hardens the public ?atproto record preview endpoint against misconfigured URL-keyed caches by ensuring preview responses are always emitted with no-cache headers, aligning it with the plugin’s existing well-known handlers.

Changes:

  • Add \nocache_headers() to the unsupported post type 404 exit path in Preview::render().
  • Add \nocache_headers() at the start of Preview::send() so both 200 payloads and 400 error payloads are consistently non-cacheable.
  • Add a patch-level changelog entry documenting the behavior change.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
includes/transformer/class-preview.php Sends no-cache headers for all preview response branches (200/400 and unsupported-type 404).
.github/changelog/fix-preview-cache-headers Documents the preview no-cache header change as a patch fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@pfefferle
pfefferle merged commit a9a7954 into trunk Jul 8, 2026
9 checks passed
@pfefferle
pfefferle deleted the add/preview-nocache-headers branch July 8, 2026 08:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Transformer AT Protocol record transformers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants