Skip to content

Stop forwarding Authorization header to third-party integration APIs#833

Open
aram356 wants to merge 2 commits into
mainfrom
test-lockr-proxy-forwards-post-body
Open

Stop forwarding Authorization header to third-party integration APIs#833
aram356 wants to merge 2 commits into
mainfrom
test-lockr-proxy-forwards-post-body

Conversation

@aram356

@aram356 aram356 commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Root cause (verified with a local fastly compute serve reproduction)

The integration API proxies forward the publisher site's Authorization header (e.g. a staging basic-auth credential) to the third-party upstream. The Lockr API rejects any request carrying an unexpected Authorization:

{"success":false,"error":{"code":400,"message":"Invalid request"}}

This short-circuits the SDK's getAIMSettings() init (which gates on success && data) — no settings data, no pvStatus, no page-view, no identity tokens — on any deployment served behind site auth. It also leaks the publisher credential to the third party.

How it was confirmed

  • Direct upstream replay: a fully-correct request (Origin + content-type + body) returns success; adding only an Authorization header flips it to the exact 400 Invalid request. Missing Origin returns 500, missing body/content-type returns 400 from a different cause — both ruled out.
  • Local fastly compute serve (legacy path, lockr enabled) reproduced the 400; debug logging showed the proxy putting authorization on the outbound wire. Removing it → upstream no longer returns the 400.

This corrects two earlier misdiagnoses (Origin — PR #831, closed; POST body — the original framing of this PR). The body and content-type were always forwarded correctly.

Fix

Stop forwarding Authorization in lockr, permutive, and didomi.

Audit of all integration proxies:

Integration Forwarded Authorization? Action
lockr yes stopped
permutive yes stopped
didomi yes stopped
sourcepoint no (already omitted, with comment)
datadome, prebid, gpt no

Tests

  • New lockr_proxy_forwards_body_and_strips_authorization: asserts the proxy forwards the POST body + content-type but strips Authorization. Extends the stub HTTP client to record outgoing request bodies.
  • cargo test -p trusted-server-core — 1455 passed; fmt + clippy clean.

Fixes #832

The integration API proxies forwarded the publisher site's `Authorization`
header (e.g. a staging basic-auth credential) to the third-party upstream.
The Lockr API rejects any request carrying an unexpected `Authorization`
with `{"success":false,"error":{"code":400,"message":"Invalid request"}}`,
which short-circuits the SDK's `getAIMSettings()` init — no settings data,
no page-view, no identity tokens — on any deployment behind site auth.
Forwarding it also leaks the publisher credential to the third party.

Auditing the other integrations found the same copy-paste in permutive and
didomi; sourcepoint already omits it intentionally; datadome, prebid, and
gpt never forwarded it. Stop forwarding `Authorization` in lockr, permutive,
and didomi to match sourcepoint.

Add a regression test asserting the Lockr proxy forwards the POST body and
content-type but strips `Authorization`, and record outgoing request bodies
in the stub HTTP client so the test can assert on them.
@aram356 aram356 force-pushed the test-lockr-proxy-forwards-post-body branch from 7866e22 to 663caf2 Compare June 30, 2026 22:35
@aram356 aram356 changed the title Add regression test that Lockr API proxy forwards the POST body Stop forwarding Authorization header to third-party integration APIs Jun 30, 2026
@aram356 aram356 marked this pull request as draft June 30, 2026 22:47
@aram356 aram356 self-assigned this Jun 30, 2026
@aram356 aram356 marked this pull request as ready for review June 30, 2026 23:17

@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.

Summary

Reviewed the Trusted Server PR that strips Authorization from Lockr, Permutive, and Didomi integration proxies. The direction looks correct and CI is green. I am approving as requested, with inline notes for a remaining Lockr cookie-forwarding credential-leak risk and follow-up test coverage/test-infrastructure hardening.

from: &HeaderMap<HeaderValue>,
to: &mut HeaderMap<HeaderValue>,
) -> Result<(), Report<TrustedServerError>> {
// NOTE: `Authorization` is intentionally NOT forwarded. It carries the

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.

Lockr still forwards publisher cookies upstream

This header allowlist now correctly avoids forwarding Authorization, but the same proxy path still calls copy_cookie_header() below, which forwards the inbound publisher Cookie header after removing only consent cookie names. Because /integrations/lockr/api/... is first-party, browsers attach publisher cookies automatically; session/auth/staging cookies can still be sent to Lockr, which is the same credential-leak class this PR is addressing.

Suggestion: Omit Cookie entirely for Lockr if Lockr does not require it, or replace copy_cookie_header() with an explicit Lockr cookie allowlist. Do not forward unparseable cookie headers unchanged, and add a regression test with Cookie: session_id=secret; euconsent-v2=tcf asserting unrelated publisher cookies do not reach the upstream.

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.

Fixed. Lockr now forwards no Cookie header at all — copy_cookie_header() is removed (it also forwarded unparseable cookie headers verbatim). Verified the upstream does not need it: the successful direct request carried no Cookie, the SDK passes its first-party cookie data in the request body (firstPartyCookies), and Permutive/Didomi already forward no cookies. Regression test lockr_proxy_forwards_body_and_strips_publisher_credentials sends Cookie: session_id=secret; euconsent-v2=tcf and asserts no Cookie reaches the upstream.


/// Copy relevant request headers for proxying.
fn copy_request_headers(&self, from: &HeaderMap<HeaderValue>, to: &mut HeaderMap<HeaderValue>) {
// `Authorization` is intentionally NOT forwarded: it carries the

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.

Add regression coverage for Permutive authorization stripping

This security-sensitive behavior changed for Permutive too, but the new regression coverage only exercises Lockr. A future allowlist edit could reintroduce the Authorization credential leak here without failing tests.

Suggestion: Add a focused Permutive proxy test that sends Authorization to the first-party route and asserts the recorded upstream request omits it while preserving required headers/body.

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.

Added permutive_proxy_strips_authorization: sends Authorization through the first-party route and asserts the recorded upstream request omits it while still forwarding user-agent.

);
}

// `Authorization` is intentionally NOT forwarded: it carries the

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.

Add regression coverage for Didomi authorization stripping

This security-sensitive behavior changed for Didomi too, but the new regression coverage only exercises Lockr. A future allowlist edit could reintroduce the Authorization credential leak here without failing tests.

Suggestion: Add a focused Didomi proxy test that sends Authorization to the first-party route and asserts the recorded upstream request omits it while preserving required headers/body.

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.

Added copy_headers_strips_authorization: passes Authorization into copy_headers and asserts it is not present on the proxy request while user-agent is preserved.


// Capture the outgoing request body so tests can assert it is forwarded.
let (_, body) = request.request.into_parts();
let body_bytes = body

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.

Do not hide request-body capture failures in StubHttpClient

into_bytes_bounded(...).await.map(...).unwrap_or_default() records an empty body if collection fails or exceeds the limit, then still returns the queued response. Tests using recorded_request_bodies() cannot distinguish an intentionally empty body from a capture failure.

Suggestion: Propagate the collection error as PlatformError::HttpClient with context, e.g. change_context(PlatformError::HttpClient).attach("failed to capture StubHttpClient request body")?, instead of defaulting to Vec::new().

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.

Fixed. Replaced unwrap_or_default() with change_context(PlatformError::HttpClient).attach("failed to capture StubHttpClient request body")?, so a capture failure now surfaces as a send error instead of being recorded as an empty body.

…, surface stub body-capture errors

- Lockr: stop forwarding the publisher `Cookie` header to the upstream. Under
  the first-party proxy the browser attaches publisher session/auth cookies to
  `/integrations/lockr/api/...`; forwarding them (minus only consent names) is
  the same credential-leak class as `Authorization`. The SDK already sends the
  identity cookie data it needs in the request body, so no `Cookie` is required.
  Removes the now-unused `copy_cookie_header` (which also forwarded unparseable
  cookie headers verbatim).
- Add Permutive and Didomi regression tests asserting `Authorization` is not
  forwarded upstream, so a future allowlist edit can't silently reintroduce the
  leak.
- Extend the Lockr test to assert the `Cookie` header is stripped too.
- StubHttpClient: propagate request-body capture failures instead of recording
  an empty body, so tests can't mistake a capture failure for an empty body.
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.

Integration proxies forward publisher Authorization header to third-party APIs (breaks Lockr)

3 participants