ESI: make the private control on nonce blocks login-aware to stop empty nonces on public pages#1010
Open
robertstaddon wants to merge 1 commit into
Open
Conversation
…gin-aware A nonce registered with the `private` control is made private for every visitor: it is emitted with cache-control='private' on the ESI include, and at resolve load_esi_block() re-applies set_private() from the _control URL param with no login check. load_nonce_block() only needs privacy for logged-in users (it calls set_private() only when Router::is_logged_in()), and a logged-out nonce is uid 0 / shared, so it never needed to be private. On a publicly cached page a private fragment has no private vary scope for an anonymous request, so it empties on the server's Private Cache TTL cycle until the next purge. Strip `private` from the nonce control for non-logged-in requests in the wp_create_nonce() override, using the same Router::is_logged_in() check load_nonce_block() uses. Logged-in behavior is unchanged, guest nonces are safely shared via the public ESI path, and _hash validation is unaffected because _control is signed and validated symmetrically. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1009
Summary
When a nonce is registered with the
privatecontrol (e.g.my_nonce_action private), thewp_create_nonce()override emits a private ESI include for every visitor. On a publicly cached page, that routes guest fragments into a private cache scope that does not exist for anonymous requests; they go empty on the Private Cache TTL cycle (~1800s by default).Strip
privatefrom the nonce control at emission when! Router::is_logged_in(), using the same predicateload_nonce_block()already uses to decide privacy is only needed for logged-in users. Full root-cause analysis, impact, and rejected alternatives are in the linked issue.Changes
litespeed-cache.php— in thewp_create_nonce()override, dropprivatefrom the control before callingsub_esi_block()for non-logged-in requests.Why emission (not resolve)
See the issue for the full walkthrough. In short:
load_nonce_block()already skipsset_private()for guests; guest privacy is set earlier via the include'scache-control='private'attribute and_control=privatein the signed URL — both fixed only at emission. A resolve-side change would require altering genericload_esi_block()and still could not rewrite the attribute baked into cached page HTML.Safety /
_hashprivateon the include;load_nonce_block()still privatizes at resolve).0and shared across anonymous visitors — public ESI is correct._controlis signed and validated symmetrically: guests omit it; logged-in users keep_control=private.Test plan
private-registered nonce, logged out: include has nocache-control='private'; nonce stays populated past Private Cache TTL (> 1 hour)._hashvalidates for both guest and logged-in includes after the control change.