Skip to content

Make first-party integration URLs root-relative#819

Merged
aram356 merged 2 commits into
mainfrom
fix-integration-relative-urls
Jun 29, 2026
Merged

Make first-party integration URLs root-relative#819
aram356 merged 2 commits into
mainfrom
fix-integration-relative-urls

Conversation

@aram356

@aram356 aram356 commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

Closes #820

Problem

The GPT, DataDome, Permutive, Lockr, and Sourcepoint attribute rewriters rewrite a publisher's <script src> / <link href> to an absolute first-party URL built from request_host:

format!("{}://{}/integrations/gpt/script", ctx.request_scheme, ctx.request_host)

ctx.request_host is the host TS derived for the request (extract_request_hostHost/X-Forwarded-Host). When that isn't the page's own host, these URLs leak the wrong host into the HTML — e.g. the page renders https://ts.example.com/integrations/gpt/script while the address bar shows www.example.com. This shows up behind a host-rewriting dev proxy, and anywhere request_host resolves to the routing host rather than the production domain.

Fix

Emit these URLs root-relative (/integrations/...) so the browser resolves them against the page's own host:

"/integrations/gpt/script".to_string()

Correct both in production and behind a proxy, and it removes the dependency on request_host / X-Forwarded-Host derivation entirely. This matches what GTM, Didomi, Testlight, and these integrations' own inline-script rewriters already do.

Scope — full integration audit

Audited every integration's page-facing URL emission (attribute rewriters, head injectors, inline-script rewriters, config-rendered URLs):

Verdict Integrations
Fixed (were absolute from request_host) gpt, datadome, permutive, lockr, sourcepoint
Already root-relative google_tag_manager, didomi, testlight, datadome client_side_tag_url (default), sourcepoint trap prefix
Correctly absolute (real external/upstream origin) GPT/GTM/Permutive/Sourcepoint upstream fetch targets
Intentionally absolute — left unchanged NextJS RSC/flight payload host rewriting
Server-side only — not page-facing DataDome protection module's raw-Host read (validation API body)

These five were the only page-facing first-party URLs built from a host.

Tests

Unit tests asserting the old absolute form updated to the root-relative form (no weakening). cargo fmt, cargo clippy --workspace --all-targets --all-features -D warnings, and cargo test --workspace all pass.

The GPT, DataDome, Permutive, Lockr, and Sourcepoint attribute rewriters
rewrote a publisher's `<script src>` / `<link href>` to an absolute first-party
URL built from `request_host`, e.g. `https://{request_host}/integrations/gpt/script`.
When the host that reaches the program isn't the page's host — behind a
host-rewriting dev proxy, or any deployment where `request_host` resolves to the
routing host rather than the production domain — those URLs leak the wrong host
into the page (e.g. `https://ts.example.com/integrations/...` while the address
bar shows `www.example.com`).

Emit them root-relative (`/integrations/...`) instead, so the browser resolves
them against the page's own host. This is correct both in production and behind
a proxy, removes the dependency on `request_host`/`X-Forwarded-Host` derivation,
and matches what GTM, Didomi, Testlight, and these integrations' own inline-script
rewriters already do.

Audited every integration: these five were the only page-facing first-party URLs
built from a host. NextJS RSC/flight payload rewriting stays absolute (those URLs
are intentional). The DataDome protection module's raw-`Host` read is server-side
(validation API body), not page-facing, and is left as-is. Tests updated to
assert the root-relative form.

@ChristianPavilonis ChristianPavilonis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Automated review: I reviewed the root-relative integration URL changes for GPT, DataDome, Lockr, Permutive, and Sourcepoint. I did not find any blocking correctness, security, data-loss, authorization, or severe compatibility issues. CI is passing. I left one non-blocking compatibility comment about <base href> semantics because root-relative attribute URLs are still resolved against the document base URL, not always the address-bar origin.

Comment thread crates/trusted-server-core/src/integrations/gpt.rs

@ChristianPavilonis ChristianPavilonis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review Summary

Approved. I reviewed the root-relative first-party integration URL change and did not find any blocker/high/medium correctness, security, or compatibility issues beyond the already-noted <base href> edge case.

Findings

P3 / Low

  • crates/trusted-server-core/src/integrations/datadome.rs:55 — DataDome module docs still show the old absolute rewrite output (https://publisher.com/integrations/datadome/tags.js). Please update the example to the new root-relative form (/integrations/datadome/tags.js) when convenient.

@aram356

aram356 commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed review feedback in 38aee53:

  • P3 (datadome.rs:55) — updated the module doc example from the old absolute https://publisher.com/integrations/datadome/tags.js to the root-relative /integrations/datadome/tags.js.
  • <base href> compatibility note — documented the tradeoff at all five rewrite sites (gpt, datadome, lockr, permutive, sourcepoint), noting that a page-level <base href> participates in URL resolution. This is the intended, lighter option from the review and is consistent with GTM/Didomi/Testlight, which are already root-relative.

Comment/doc-only change; cargo fmt and cargo clippy pass.

@aram356 aram356 merged commit bc54caa into main Jun 29, 2026
14 checks passed
@aram356 aram356 deleted the fix-integration-relative-urls branch June 29, 2026 06:19
prk-Jr added a commit that referenced this pull request Jun 29, 2026
Resolve conflicts from main's PR16 axum adapter (#643) and first-party
consent fixes (#819, #822) by keeping this branch's PR18 legacy-admin-alias
credential-leak fix across all three adapters. Core changes from main merged
cleanly; lockfiles and manifests already consistent.
prk-Jr added a commit that referenced this pull request Jun 29, 2026
Keep the branch's evolved tree (fastly 0.12, worker 0.8, edgezero
ce6bcf74, Spin adapter), which already supersedes main's PR16/PR18
content carried via the stack's merge history.

Incorporate main's two new fixes that the branch lacked:
- #819 root-relative first-party integration URLs (datadome, gpt,
  lockr, permutive, sourcepoint)
- #822 Sourcepoint first-party consent iframe/same-origin guard

Auto-merge picked main's older fastly-0.11 TLS code for the fastly
adapter (main.rs, platform.rs, route_tests.rs); restore the branch
versions so the get_tls_protocol/cipher calls match the locked
fastly 0.12 API.

Verified: cargo check-{fastly,cloudflare,axum,spin} --locked all pass.
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.

First-party integration URLs leak the routing host instead of being root-relative

3 participants