Skip to content

docs: state the WEBJS_NO_TRUST_PROXY condition once, at the instruction - #1275

Merged
vivek7405 merged 1 commit into
mainfrom
docs/no-trust-proxy-scoping
Aug 5, 2026
Merged

docs: state the WEBJS_NO_TRUST_PROXY condition once, at the instruction#1275
vivek7405 merged 1 commit into
mainfrom
docs/no-trust-proxy-scoping

Conversation

@vivek7405

@vivek7405 vivek7405 commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Closes #1266

Stacked on #1272. That PR rewrites a different sentence in the same paragraph (the client-IP carve-out), so this branch is cut from it to keep the two edits from colliding inside one <p>. Merge #1272 first and this rebases cleanly.

Summary

The deployment page stated the flag's precondition twice in one paragraph: once as "when the container is directly exposed" at the point of instruction, and again as "Set it only when nothing trusted sits in front of the container" three sentences later. This says it once, in the wording .agents/skills/webjs/references/runtime.md already uses, and lets the closing sentences carry only the consequences.

It also adds the sentence a reader behind a CDN was actually missing.

Why not the straight deletion the issue asked for

The issue's plan was to delete the opening clause outright, on the grounds that the narrow framing is wrong on the merits. Checking that against the two surfaces the issue names as the sources being aligned TO, it does not hold:

  • packages/server/src/forwarded.js says the flag "is the remedy for a directly-exposed container, and it also narrows the forwarded-host exposure above, so it is not only a bare-VM concern." That makes the clause INCOMPLETE, not wrong.
  • .agents/skills/webjs/references/runtime.md says "Setting it on a genuinely proxied deploy is a misconfiguration."

Both agree with the precondition. The "global" claim in runtime.md is about which headers the flag covers, not about which topologies should set it, so it never contradicted the opening clause in the first place.

A straight deletion would also have made the page worse in a specific way: it leaves Set WEBJS_NO_TRUST_PROXY=1 to stop trusting forwarded headers. unconditioned at the one place a reader acts on it, with the restriction deferred three sentences. That is the wrong direction for a flag that breaks the legacy CSRF fallback on a proxied deploy and, after #1272, collapses every visitor behind a proxy into one rate-limit bucket. It would not even have fixed the reported harm: the Cloudflare reader who concluded the flag was irrelevant to them still hits "only when nothing trusted sits in front of the container" and concludes the same.

So the precondition stays, moved to the instruction and worded to match runtime.md. directly exposed no longer appears anywhere under website/app/docs/, which is the issue's acceptance criterion, and the flag's scope now reads identically on both surfaces.

What the CDN reader was actually missing

Not that the flag applies to them. That it does NOT. Cloudflare and Railway forward a client-supplied X-Forwarded-Host rather than overwriting it, so a forged forwarded host is reachable in the ordinary proxy topology, but this flag is not the remedy there. The remedy is keying shared state by the request origin, which html-cache.js already does. That is now one sentence on the page, pointing at the rule rather than restating the threat model.

Test plan

  • website/test/ssr/docs-links.test.ts (7/7): boots the site through createRequestHandler({ dev: false }) and fetches every internal /docs link, so /docs/deployment is rendered and status-asserted. That is the real gate here, since the one failure a prose edit can cause is an invariant 9 backtick closing the html literal and 500ing the page. No backtick was added.
  • website full suite 84/84, webjs check clean.
  • grep -rn "directly exposed" website/app/docs/ returns nothing.
  • The whole paragraph re-read end to end after the edit, since three of its sentences now interlock differently.
  • Counterfactual: stated honestly rather than invented. Reverting this edit leaves every test green, because no test asserts docs prose, and adding one for a single clause would rot on the next rewording. The render assertion reds only on a syntax break.
  • Browser / e2e / Bun parity: N/A. Prose inside one SSR'd docs page, no runtime-sensitive source touched.

Doc surfaces

Updated: website/app/docs/deployment/page.ts, the only surface this changes.

Deliberately untouched: .agents/skills/webjs/references/runtime.md and packages/server/src/forwarded.js already carry the correct framing and are the source this page is aligned TO. website/app/docs/security/page.ts and website/app/docs/server-actions/page.ts also mention the flag, both only in the CSRF context and both accurate.

N/A: tests, scaffold templates, the MCP server, editor plugins, marketing copy, README, AGENTS.md, changelog (docs-only, no published-package surface changed).

@vivek7405 vivek7405 self-assigned this Aug 5, 2026
@vivek7405
vivek7405 force-pushed the docs/no-trust-proxy-scoping branch from a2faa58 to 67bdc02 Compare August 5, 2026 10:20
@vivek7405 vivek7405 changed the title docs: stop scoping WEBJS_NO_TRUST_PROXY to a directly-exposed container docs: state the WEBJS_NO_TRUST_PROXY condition once, at the instruction Aug 5, 2026

@vivek7405 vivek7405 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went back to the two files this page is supposed to agree with, and the premise I started from does not survive them. forwarded.js says the flag "is the remedy for a directly-exposed container, and it also narrows the forwarded-host exposure above", and runtime.md says setting it on a genuinely proxied deploy is a misconfiguration. So the opening clause was incomplete, not wrong, and both surfaces agree with the precondition it stated. The "global" wording in runtime.md is about which headers the flag covers, not which topologies should set it, so there was never the contradiction I thought I was fixing.

Deleting the clause outright would also have run the wrong way for this particular flag: it leaves the imperative unconditioned at the one place a reader acts on it, with the restriction three sentences downstream, for a switch that breaks the legacy CSRF fallback on a proxied deploy and now collapses every visitor behind a proxy into one rate-limit bucket. And it would not have fixed the reported harm anyway, since the Cloudflare reader still reads the closing sentence and draws the same conclusion.

So the precondition stays and moves up to the instruction, worded to match runtime.md, and the duplicate at the end goes. directly exposed is gone from the docs tree either way. The thing the CDN reader was actually missing is that this flag is NOT their remedy for a forged X-Forwarded-Host, so that is now one sentence pointing at origin-keying rather than a third copy of the threat model.

Comment thread website/app/docs/deployment/page.ts
Comment thread website/app/docs/deployment/page.ts
Comment thread website/app/docs/deployment/page.ts
@vivek7405
vivek7405 marked this pull request as ready for review August 5, 2026 10:29
Base automatically changed from fix/no-trust-proxy-overrides-ratelimit to main August 5, 2026 11:01
The deployment page stated the flag's precondition twice in one
paragraph, once as "when the container is directly exposed" at the point
of instruction and again as "only when nothing trusted sits in front of
the container" three sentences later. Say it once, in the wording
runtime.md already uses, and let the closing sentences carry only the
consequences.

The original writeup wanted the opening clause deleted outright on the
grounds that the narrow framing was wrong. It is not. forwarded.js says
the flag "is the remedy for a directly-exposed container, and it also
narrows the forwarded-host exposure above", and runtime.md says setting
it on a genuinely proxied deploy is a misconfiguration. So the clause was
incomplete rather than wrong, and deleting it would have left the
imperative unconditioned at the one place a reader acts on it, for a flag
that breaks the legacy CSRF fallback when set on a proxied deploy.

What a reader behind a CDN was actually missing is that this flag is not
their remedy for a forged X-Forwarded-Host. Cloudflare and Railway
forward that header rather than overwriting it, so the exposure is real
in their topology, and the fix is to key shared state by the request
origin, which is what the HTML response cache does. That sentence is now
on the page.
@vivek7405
vivek7405 force-pushed the docs/no-trust-proxy-scoping branch from 67bdc02 to 6a051e9 Compare August 5, 2026 11:02
@vivek7405
vivek7405 merged commit 363c155 into main Aug 5, 2026
10 checks passed
@vivek7405
vivek7405 deleted the docs/no-trust-proxy-scoping branch August 5, 2026 12:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs: stop scoping WEBJS_NO_TRUST_PROXY to a directly-exposed container

1 participant