Harden ad-spoof pod accounting (cap + unknown-length gating) + GQL body-read timeout - #240
Open
ryanbr wants to merge 1 commit into
Open
Harden ad-spoof pod accounting (cap + unknown-length gating) + GQL body-read timeout#240ryanbr wants to merge 1 commit into
ryanbr wants to merge 1 commit into
Conversation
ryanbr
added a commit
that referenced
this pull request
Jun 10, 2026
Mirror of PR #240 (release pair) into the testing pair: - Per-iteration break caps spoofing at the declared pod length (mirrors TTV-AB v9.4.1) — prevents beacons for more ads than the pod claims and impossible "5/2 pod" logs when one poll surfaces more DATERANGEs than X-TV-TWITCH-AD-POD-LENGTH declares. - GQL relay abort timer now clears after the response body read (mirrors TTV-AB v9.6.1) so a mid-body hang rejects instead of leaking. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Spoofing-code hardening mirroring upstream TTV-AB (shared-lineage code):
1. Pod accounting (TTV-AB v9.4.1 + v9.6.4 + v9.7.3):
- Cap: a per-iteration break stops spoofing at the declared pod length
when Twitch over-surfaces DATERANGEs in one poll (no beacons past the
pod, no "5/2 pod" logs).
- hasExplicitPodLength gate: when Twitch OMITS X-TV-TWITCH-AD-POD-LENGTH,
podLength is just the current poll's match count, so every
size-vs-podLength check was meaningless — the early-out bailed after
the first ad (later ads unspoofed) and pod_complete could fire on
multiple polls. All three checks (pre-loop early-out, in-loop cap,
pod_complete) now gate on hasExplicitPodLength: unknown length → never
early-out, never fabricate pod_complete.
2. GQL relay timeout through body read (TTV-AB v9.6.1): the main-thread
fetch relay cleared its 5s abort timer at headers, leaving
response.text() unbounded on a mid-body hang. Timer now clears after
the body read; abort mid-body rejects through the existing catch.
All in opt-in spoof-on territory (spoofing default-off) except the relay
timeout. Worker-blob safe; main-thread for the relay.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ryanbr
force-pushed
the
fix/spoof-pod-cap
branch
from
June 11, 2026 10:31
665369e to
af3cd80
Compare
ryanbr
added a commit
that referenced
this pull request
Jun 11, 2026
Mirror of PR #240 (release pair) into the testing pair. Adds hasExplicitPodLength gating on top of v655's pod cap: when Twitch omits X-TV-TWITCH-AD-POD-LENGTH, podLength is just the current poll's match count, so the size-vs-podLength checks were meaningless — the early-out bailed after the first ad (later ads unspoofed) and pod_complete could fire on multiple polls. All three checks (pre-loop early-out, in-loop cap, pod_complete) now gate on hasExplicitPodLength. Mirrors TTV-AB v9.6.4 + v9.7.3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jul 24, 2026
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.
Spoofing-code hardening mirroring upstream GosuDRM/TTV-AB — all in the shared
notifyAdCompletelineage, where TTV-AB hit these in the field.1. Pod accounting (TTV-AB v9.4.1 + v9.6.4 + v9.7.3)
Two related edge cases around
X-TV-TWITCH-AD-POD-LENGTH, both producing internally-inconsistent ad-completion beacons (the cross-validation flag the payload is designed to avoid):(a) Over-surface — cap. Twitch occasionally exposes more unique stitched-ad DATERANGEs in one poll than the pod declares. The pre-loop early-out only caught that across polls, so within one poll vaft kept spoofing past the pod (
5/2 podlogs, beacons for more ads than the pod claims). A per-iterationbreaknow stops at the declared length. (v9.4.1)(b) Unknown length — gate. When Twitch omits the pod-length attribute,
podLengthfalls back to the current poll's match count, making everysize-vs-podLengthcomparison meaningless:pod_completecould fire on multiple polls.All three checks (pre-loop early-out, in-loop cap,
pod_complete) are now gated onhasExplicitPodLength = !!podLenMatch. Unknown length → never early-out (spoof every surfaced ad), never fabricatepod_complete. (v9.6.4 + v9.7.3)2. GQL relay abort timeout through body read (TTV-AB v9.6.1)
The main-thread fetch relay (worker's access tokens + spoof beacons) cleared its 5s AbortController timer at headers, leaving
await response.text()unbounded on a mid-body hang. Worker-side relay timeout already bounded the impact (no stall — leaked promise), but the timer now clears after the body read so a mid-body abort rejects through the existing catch.Scope / validation
hasExplicitPodLength); relay change is main-thread.npx acorn --ecma2022clean on both; added lines byte-identical across the pair.## Unreleased).🤖 Generated with Claude Code