Repository navigation
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tailscale Serve and T3 Connect add X-Forwarded-Proto: https. The hub builds its request origin from that header, so it no longer matched the Origin the proxy sets, and the Device panel screenshot failed with 403. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — This is a minimal, self-contained server bug fix that removes one conflicting proxy header while preserving routing, authentication, and request behavior. The affected screenshot flow is covered by a focused regression test, with no product-default or static-analysis changes. You can add or adjust custom eligibility rules. Learn more. |
Author
|
#19379 already solves this |
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.
Problem
When you open T3 through Tailscale Serve or T3 Connect, the Device panel's Android screenshot fails with "Screenshot capture failed (403). Try again." The same click works when the browser connects to the server directly.
The reverse proxy adds
X-Forwarded-Proto: https, andDeviceHubProxypasses it on to the device hub. The hub's Node adapter builds the request origin from that header, so it seeshttps://127.0.0.1:<port>. The proxy rewritesOrigintohttp://127.0.0.1:<port>. serve-emu compares the two before any mutation, finds a mismatch, and returns{"code":"forbidden","message":"Browser origin is not allowed to mutate serve-emu state"}.Change
DeviceHubProxyaddsx-forwarded-prototo the headers it drops. The header describes the browser's connection to T3, not T3's loopback connection to the hub. The hub reads no other forwarding header, so the fix drops only this one.Scope and approval
This is a small fix for an obvious bug, so it qualifies without a prior issue. It changes one entry in the proxy's dropped-header set. The fix covers every POST through the proxy (screenshot, stream mode, stream settings, fold). WebSocket upgrades do not forward request headers, and the agent's
device_screenshottool calls the hub directly, so neither path had the bug.Verification
vp test run apps/server/src/device/DeviceHubProxy.test.ts. The new test sends a screenshot POST withX-Forwarded-Proto: httpsand asserts that the hub gets the rewrittenOriginand nox-forwarded-proto. On the test commit alone it fails withexpected { origin: 'http://hub.test', …(4) } to not have property "x-forwarded-proto". With the fix, 16 of 16 proxy tests pass.DeviceHubProxy.layerwithFetchHttpClientagainst the running hub and sent the request that Tailscale Serve delivers. Onmainthe hub returned 403 with the error above. With the fix it returned 200image/png(767,845 bytes). I did not commit the harness.StatusCode error (403 POST http://127.0.0.1:43531/vendor/serve-emu/api/screenshot?device=emulator-5554).Model and harness: Claude Opus 5.5 (
claude-opus-5-5) in Claude Code, running inside T3 Code.🤖 Generated with Claude Code