Conversation
Use structured serialization to prevent request fields from shifting TransferCache key boundaries.
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.
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
HttpTransferCachecurrently creates its cache key by concatenating several variable-length request fields using a NUL (\0) delimiter:This assumes that the delimiter cannot occur inside any of the serialized fields.
However, a literal U+0000 can occur in the raw
HttpRequest.urlstring as well as in a string request body. This makes it possible for the delimiter to be shifted across a field boundary.For example, these two distinct POST requests:
and:
produce the same NUL-delimited pre-hash representation.
As a result, two semantically different requests can generate the same TransferCache key and the second request can incorrectly reuse the response cached for the first request instead of reaching the backend.
More details and reproduction information are available in the related Google security report:
https://issuetracker.google.com/u/1/issues/561141793
What is the new behavior?
The cache-key fields are serialized as a structured JSON array before hashing:
This makes the representation unambiguous because each field remains structurally separated regardless of the characters contained in the field itself.
The two requests above therefore generate different key material and are treated as separate requests.
The PR also adds a regression test covering the NUL-shifted URL/body boundary.
Security impact
The previous delimiter-based representation could cause two different cacheable POST requests to share the same
HttpTransferCacheentry.When this happens, a later request can receive a response belonging to an earlier request while its backend request is skipped.
The regression test verifies that requests whose URL/body boundary differs only by placement of a literal NUL are assigned separate TransferCache identities.
This change addresses the underlying framing problem rather than replacing NUL with another sentinel character.
Why structured serialization?
A delimiter-based encoding is only unambiguous if the delimiter is guaranteed to be impossible in every serialized field.
Using a different delimiter would retain the same class of problem if that value can appear in field content.
Structured serialization provides explicit field boundaries and avoids depending on a sentinel-value assumption.
For example:
is structurally different from:
even though the equivalent delimiter-joined representations collide.
Tests
A regression test was added to:
covering:
The affected HTTP test target passes on the rebased branch:
The expected TransferState hashes in the existing test were also updated because changing the pre-hash representation intentionally changes generated cache keys.
Does this PR introduce a breaking change?
The TransferCache key representation is an internal implementation detail. Existing entries are generated as part of the server-rendering / hydration lifecycle rather than being a public persisted cache-key format.
Other information
The change is intentionally limited to the TransferCache key representation and its regression coverage.
More information about the security issue, reproduction, and affected behavior can be found here:
https://issuetracker.google.com/u/1/issues/561141793