Skip to content

fix: SSR Cache Poisoning via Unvalidated X-Forwarded-Host Header#21317

Open
rmch91 wants to merge 3 commits intodevelopfrom
CXSPA-12468
Open

fix: SSR Cache Poisoning via Unvalidated X-Forwarded-Host Header#21317
rmch91 wants to merge 3 commits intodevelopfrom
CXSPA-12468

Conversation

@rmch91
Copy link
Copy Markdown
Contributor

@rmch91 rmch91 commented Apr 1, 2026

Closes: https://jira.tools.sap/browse/CXSPA-12468

QA Steps

Prerequisites

# 1. Checkout the branch
git checkout CXSPA-12468

# 2.
npm install

# 3. Build the libs
npm run build:libs

# 4. Build the SSR app
npm run build:ssr

# 5. Start the SSR server with caching enabled and a longer timeout
NODE_TLS_REJECT_UNAUTHORIZED=0 SSR_CACHE=true npm run serve:ssr

The server starts at http://localhost:4000. Keep the server terminal visible to observe the logs.


Test 1: Verify default behavior (path-only cache key)

Goal: Confirm that X-Forwarded-Host does not affect the cache key.

Step 1 — Send a first request

curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost:4000/electronics-spa/en/USD/

Expected server log — one render starts and completes:

{"message":"Rendering started (/electronics-spa/en/USD/)", ...}
{"message":"Rendering completed (/electronics-spa/en/USD/)", ...}
{"message":"Request is resolved with the SSR rendering result (/electronics-spa/en/USD/)", ...}

Step 2 — Send the same request with a different X-Forwarded-Host:

curl -s -o /dev/null -w "HTTP %{http_code}\n" -H "X-Forwarded-Host: attacker.com" http://localhost:4000/electronics-spa/en/USD/

Expected server log — the request is served from cache, no new "Rendering started" message

Pass criteria: Both requests use the same cache key /electronics-spa/en/USD/. Only one render occurred.


Test 2: Verify cache poisoning is no longer possible (concurrent burst)

Goal: Confirm that 20 concurrent requests with different X-Forwarded-Host values do NOT create 20 separate cache entries or exhaust concurrency.

Step 1 — Restart the SSR server to clear the cache (Ctrl+C, then start again):

NODE_TLS_REJECT_UNAUTHORIZED=0 SSR_CACHE=true npm run serve:ssr

Step 2 — Send 20 concurrent requests with different X-Forwarded-Host headers:

for i in {1..20}; do
  curl -s -H "X-Forwarded-Host: attacker${i}.com" http://localhost:4000/electronics-spa/en/USD/ > /dev/null &
done
wait

Expected server logs — exactly one "Rendering started" and one "Rendering completed", with all 20 requests waiting on and resolved by that single render:

{"message":"Rendering started (/electronics-spa/en/USD/)", ...}
{"message":"Request is waiting for the SSR rendering to complete (/electronics-spa/en/USD/)", ...}
{"message":"Request is waiting for the SSR rendering to complete (/electronics-spa/en/USD/)", ...}
... (up to 19 "waiting" messages)
{"message":"Rendering completed (/electronics-spa/en/USD/)", ...}
{"message":"Request is resolved with the SSR rendering result (/electronics-spa/en/USD/)", ...}
{"message":"Request is resolved with the SSR rendering result (/electronics-spa/en/USD/)", ...}
... (20 "resolved" messages total)

Pass criteria:

  • Only 1 render, not 20
  • Only 1 concurrency slot used (no "Concurrency limit exceeded" messages)
  • All 20 requests resolved with SSR result
  • No "fallbacking to CSR" messages (with 30s timeout)

@rmch91 rmch91 requested a review from a team as a code owner April 1, 2026 10:03
@github-actions github-actions bot marked this pull request as draft April 1, 2026 10:03
@rmch91 rmch91 marked this pull request as ready for review April 1, 2026 11:32
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 1, 2026

Merge Checks Failed

Please push a commit to re-trigger the build.
To push an empty commit you can use `git commit --allow-empty -m "Trigger Build"`

@github-actions github-actions bot marked this pull request as draft April 1, 2026 11:32
@rmch91 rmch91 marked this pull request as ready for review April 1, 2026 12:37
@cypress
Copy link
Copy Markdown

cypress bot commented Apr 1, 2026

spartacus    Run #52556

Run Properties:  status check passed Passed #52556  •  git commit 0be6f70db1 ℹ️: Merge bbb8f367ddfcb58d0c97ba30605bfe3f60b08d68 into 7c67650e877bb05108fe605d80ca...
Project spartacus
Branch Review CXSPA-12468
Run status status check passed Passed #52556
Run duration 04m 07s
Commit git commit 0be6f70db1 ℹ️: Merge bbb8f367ddfcb58d0c97ba30605bfe3f60b08d68 into 7c67650e877bb05108fe605d80ca...
Committer Roman
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 3
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 101
View all changes introduced in this branch ↗︎

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.

1 participant