Skip to content

fix: vercel -> cfpages changes#7401

Open
alfetopito wants to merge 6 commits into
developfrom
fix/vercel-cfpages
Open

fix: vercel -> cfpages changes#7401
alfetopito wants to merge 6 commits into
developfrom
fix/vercel-cfpages

Conversation

@alfetopito
Copy link
Copy Markdown
Collaborator

@alfetopito alfetopito commented Apr 24, 2026

Summary

Adapt app/cf pages setup to vercel specific changes

  1. Map headers
  2. Setup sentry source map uploading
  3. Pin nvmrc version to version number instead of name as CF pages can't handle that
  4. Bump node limit to 8gb as the default 4gb was not enough on CF pages

To Test

  1. Check cf build fix: vercel -> cfpages changes #7401 (comment)
  • Should succeed
  1. Open the cf link
  • Should point to the PR env/barn backend
  1. Check the headers curl -I https://fix-vercel-cfpages.swap-dev-5u6.pages.dev/
  • Should have in the response:
  - content-security-policy
  - cross-origin-opener-policy: same-origin-allow-popups
  - cross-origin-resource-policy: cross-origin
  - x-content-type-options: nosniff
  - referrer-policy: strict-origin-when-cross-origin

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 24, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cowfi Ready Ready Preview May 14, 2026 8:50am
explorer-dev Ready Ready Preview May 14, 2026 8:50am
storybook Ready Ready Preview May 14, 2026 8:50am
swap-dev Ready Ready Preview May 14, 2026 8:50am
widget-configurator Ready Ready Preview May 14, 2026 8:50am
2 Skipped Deployments
Project Deployment Actions Updated (UTC)
cosmos Ignored Ignored May 14, 2026 8:50am
sdk-tools Ignored Ignored Preview May 14, 2026 8:50am

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 24, 2026

Warning

Rate limit exceeded

@alfetopito has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 38 minutes and 46 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3da86df2-1638-41f3-8ed8-be655cfcf64c

📥 Commits

Reviewing files that changed from the base of the PR and between 5efbb17 and e6e8a2d.

📒 Files selected for processing (7)
  • .nvmrc
  • README.md
  • apps/cowswap-frontend/.env
  • apps/cowswap-frontend/public/_headers
  • apps/cowswap-frontend/vite.config.mts
  • docs/CLOUDFLARE_PAGES_MIGRATION.md
  • package.json

Walkthrough

This PR establishes Sentry production sourcemap uploads in the Vite build pipeline, adds HTTP security headers for Cloudflare Pages deployment, documents the complete Cloudflare Pages migration, and updates build infrastructure dependencies and configuration.

Changes

Deployment Infrastructure & Sentry Integration

Layer / File(s) Summary
Sentry sourcemap upload in build pipeline
apps/cowswap-frontend/vite.config.mts, apps/cowswap-frontend/.env
Vite build conditionally runs sentryVitePlugin in production when SENTRY_AUTH_TOKEN is set, deriving release name from package version and org/project from environment or defaults. Environment file documents required REACT_APP_SENTRY_DSN and SENTRY_AUTH_TOKEN, plus optional SENTRY_ORG and SENTRY_PROJECT overrides.
HTTP security headers for Cloudflare Pages
apps/cowswap-frontend/public/_headers
Introduces _headers configuration with Content-Security-Policy (broad connect-src, permissive style/font, explicit object-src restriction) and additional cross-origin, MIME-type, and referrer policies.
Cloudflare Pages migration documentation
docs/CLOUDFLARE_PAGES_MIGRATION.md, README.md
Comprehensive migration guide documents Pages configuration for cowswap-frontend and explorer, maps Vercel rewrite behavior to Pages SPA fallback, lists required project settings, provides per-app build variables, and includes validation checklist. README adds Sentry sourcemap and configuration documentation sections.
Build infrastructure and environment maintenance
.nvmrc, package.json, README.md
Node.js version bumped to 22.15.1, production build heap memory increased to 8192 MB via NODE_OPTIONS, and markdown table formatting refined.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A sourcemap's tale in clouds we send,
Sentry guards where errors end,
Cloudflare's pages spread their wings,
Security headers seal all things!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title directly relates to the core objective of migrating from Vercel to Cloudflare Pages, accurately capturing the main change across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description includes all major required sections: Summary with numbered objectives, To Test with verification steps including expected headers, and adequate detail about the changes being made.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/vercel-cfpages

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 24, 2026

Deploying swap-dev with  Cloudflare Pages  Cloudflare Pages

Latest commit: e6e8a2d
Status: ✅  Deploy successful!
Preview URL: https://c8459c19.swap-dev-5u6.pages.dev
Branch Preview URL: https://fix-vercel-cfpages.swap-dev-5u6.pages.dev

View logs

@alfetopito alfetopito force-pushed the fix/build-envs branch 2 times, most recently from ceac06b to 86967f0 Compare May 12, 2026 14:58
Base automatically changed from fix/build-envs to develop May 12, 2026 16:14
@alfetopito alfetopito force-pushed the fix/vercel-cfpages branch from 0c24c61 to 71c5466 Compare May 12, 2026 16:23
@alfetopito alfetopito marked this pull request as ready for review May 12, 2026 17:15
@alfetopito alfetopito marked this pull request as draft May 12, 2026 17:15
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
package.json (1)

26-26: 💤 Low value

Significant memory increase for production builds.

The Node.js memory limit has been doubled from ~4GB (default) to 8GB. While this addresses Cloudflare Pages build failures (as noted in the commit messages), consider monitoring actual memory usage to determine if the full 8GB is necessary long-term, or if a smaller increase would suffice.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 26, The npm script "build:cowswap" hardcodes
NODE_OPTIONS=--max-old-space-size=8192 which doubles Node's memory cap; change
this to a configurable or smaller value and add monitoring: replace the
hardcoded 8192 with an env-driven value (e.g., use an env var like
MAX_OLD_SPACE_SIZE or a script that falls back to a sensible default such as
4096), update the "build:cowswap" script to reference that env var, and add a
short note in the repo README or CI docs instructing how to override and to
collect build memory metrics to determine the minimal needed size.
apps/cowswap-frontend/public/_headers (2)

2-2: 🏗️ Heavy lift

Consider tightening overly permissive CSP directives.

Several CSP directives use wildcards that significantly reduce the security benefits of CSP:

  • connect-src * - allows connections to any origin
  • style-src * - allows styles from any source
  • font-src * - allows fonts from any source
  • frame-src * - allows framing any external content

While these may be necessary for DeFi integrations (wallet connectors, blockchain RPCs, third-party widgets), consider explicitly listing known domains to reduce the attack surface. At minimum, document why each wildcard is required.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/cowswap-frontend/public/_headers` at line 2, The CSP in public/_headers
is overly permissive because several directives use wildcards (notably
connect-src, style-src, font-src, frame-src); replace these wildcards with
explicit, minimal whitelists of required origins (e.g., known RPCs, analytics,
widget domains and CDN hosts) and remove any unnecessary '*' entries, or if
wildcard is absolutely required add an inline comment documenting why; update
the directives named connect-src, style-src, font-src, and frame-src in the
Content-Security-Policy header to list only the trusted domains and test the app
to ensure wallet connectors, RPC calls and third-party widgets still function.

2-2: ⚖️ Poor tradeoff

'unsafe-eval' and 'unsafe-inline' weaken script CSP protection.

The script-src directive includes both 'unsafe-eval' and 'unsafe-inline', which significantly reduce the effectiveness of CSP against XSS attacks. These are often required for certain frameworks and third-party scripts, but verify they are truly necessary.

If these are required for specific libraries (e.g., analytics, ads), consider using CSP nonces or hashes for inline scripts instead of the blanket 'unsafe-inline' permission.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/cowswap-frontend/public/_headers` at line 2, The Content-Security-Policy
header's script-src currently includes 'unsafe-eval' and 'unsafe-inline' which
weakens CSP; audit the third-party hosts listed in the script-src directive and
remove 'unsafe-eval' and 'unsafe-inline' where possible, then replace blanket
inline permissions by adopting CSP nonces or script hashes: update the
Content-Security-Policy header string (the line beginning with
Content-Security-Policy and the script-src token) to remove those unsafe tokens
and instead add either 'nonce-<value>' (and implement server-side injection of
that nonce into inline <script> tags) or add sha256/... hashes for any required
inline scripts, and narrow allowed origins in script-src/connect-src to only the
third-party domains actually needed.
docs/CLOUDFLARE_PAGES_MIGRATION.md (1)

86-91: ⚡ Quick win

Enhance validation checklist with security and behavior testing.

The current checklist verifies that headers are present but doesn't validate their correctness or security implications. Consider adding:

  • Verify frame-ancestors CSP directive aligns with security requirements (test iframe embedding)
  • Test deep-link routing behavior matches Vercel (compare specific routes between Vercel and CF Pages)
  • Validate that CSP headers don't block legitimate app functionality (wallet connections, external resources)
  • Confirm CORS and COOP/CORP headers work correctly with wallet integrations
📋 Proposed enhancement to validation checklist
 ## Validation checklist
 
 - `apps/cowswap-frontend/public/_headers` is copied into `build/cowswap/_headers`.
 - `build/cowswap` and `build/explorer` do not contain a top-level `404.html`.
 - Deep links for both apps resolve correctly on Pages preview deployments.
 - `cowswap` document responses include the migrated security headers.
+- Security headers function as intended:
+  - Test iframe embedding behavior matches requirements.
+  - Verify CSP doesn't block wallet connections or legitimate external resources.
+  - Confirm COOP/CORP headers work with wallet integrations.
+- SPA routing behavior matches Vercel production (test multiple route paths).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/CLOUDFLARE_PAGES_MIGRATION.md` around lines 86 - 91, Extend the
Validation checklist to include security and behavioral tests: add items to
verify the `frame-ancestors` CSP directive (attempt iframe embedding of
`cowswap` to ensure it matches security requirements), add explicit deep-link
routing comparisons between Vercel and Cloudflare Pages for representative
routes (e.g., root, /swap, /pool, and a known deep-link), add tests that
exercise wallet connections and external resource loads to confirm CSP headers
in `build/cowswap` don’t block legitimate app functionality, and add checks that
CORS and COOP/CORP headers on `cowswap` document responses work correctly with
wallet integrations (e.g., cross-origin requests and credentialed fetches).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/cowswap-frontend/public/_headers`:
- Line 2: The Content-Security-Policy header currently sets "frame-ancestors *",
which permits clickjacking; update the CSP line in public/_headers to replace
frame-ancestors * with a restrictive value (e.g., frame-ancestors 'self' or
frame-ancestors 'none', or an explicit allowlist like frame-ancestors 'self'
https://trusted-partner.com) and ensure the rest of the policy string remains
unchanged; locate the CSP header string (the long line beginning with
"Content-Security-Policy:") and edit only the frame-ancestors token to the
chosen restrictive option.

---

Nitpick comments:
In `@apps/cowswap-frontend/public/_headers`:
- Line 2: The CSP in public/_headers is overly permissive because several
directives use wildcards (notably connect-src, style-src, font-src, frame-src);
replace these wildcards with explicit, minimal whitelists of required origins
(e.g., known RPCs, analytics, widget domains and CDN hosts) and remove any
unnecessary '*' entries, or if wildcard is absolutely required add an inline
comment documenting why; update the directives named connect-src, style-src,
font-src, and frame-src in the Content-Security-Policy header to list only the
trusted domains and test the app to ensure wallet connectors, RPC calls and
third-party widgets still function.
- Line 2: The Content-Security-Policy header's script-src currently includes
'unsafe-eval' and 'unsafe-inline' which weakens CSP; audit the third-party hosts
listed in the script-src directive and remove 'unsafe-eval' and 'unsafe-inline'
where possible, then replace blanket inline permissions by adopting CSP nonces
or script hashes: update the Content-Security-Policy header string (the line
beginning with Content-Security-Policy and the script-src token) to remove those
unsafe tokens and instead add either 'nonce-<value>' (and implement server-side
injection of that nonce into inline <script> tags) or add sha256/... hashes for
any required inline scripts, and narrow allowed origins in
script-src/connect-src to only the third-party domains actually needed.

In `@docs/CLOUDFLARE_PAGES_MIGRATION.md`:
- Around line 86-91: Extend the Validation checklist to include security and
behavioral tests: add items to verify the `frame-ancestors` CSP directive
(attempt iframe embedding of `cowswap` to ensure it matches security
requirements), add explicit deep-link routing comparisons between Vercel and
Cloudflare Pages for representative routes (e.g., root, /swap, /pool, and a
known deep-link), add tests that exercise wallet connections and external
resource loads to confirm CSP headers in `build/cowswap` don’t block legitimate
app functionality, and add checks that CORS and COOP/CORP headers on `cowswap`
document responses work correctly with wallet integrations (e.g., cross-origin
requests and credentialed fetches).

In `@package.json`:
- Line 26: The npm script "build:cowswap" hardcodes
NODE_OPTIONS=--max-old-space-size=8192 which doubles Node's memory cap; change
this to a configurable or smaller value and add monitoring: replace the
hardcoded 8192 with an env-driven value (e.g., use an env var like
MAX_OLD_SPACE_SIZE or a script that falls back to a sensible default such as
4096), update the "build:cowswap" script to reference that env var, and add a
short note in the repo README or CI docs instructing how to override and to
collect build memory metrics to determine the minimal needed size.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a9bccaaf-5f66-40b0-bfb0-3c92c4d62424

📥 Commits

Reviewing files that changed from the base of the PR and between ee0ba3a and 5efbb17.

📒 Files selected for processing (7)
  • .nvmrc
  • README.md
  • apps/cowswap-frontend/.env
  • apps/cowswap-frontend/public/_headers
  • apps/cowswap-frontend/vite.config.mts
  • docs/CLOUDFLARE_PAGES_MIGRATION.md
  • package.json

@@ -0,0 +1,6 @@
/*
Content-Security-Policy: default-src 'self'; script-src 'self' https://*.cow.fi https://telegram.org https://*.appzi.io https://www.googletagmanager.com https://s3.amazonaws.com https://www.redditstatic.com https://www.google-analytics.com https://www.clarity.ms https://tag.safary.club https://static.ads-twitter.com https://scripts.clarity.ms https://api.hypelab.com https://googleads.g.doubleclick.net https://tag.adrsbl.io https://cdn.spindl.xyz https://r2.ixncdn.com https://cdn.id5-sync.com 'unsafe-eval' 'unsafe-inline'; style-src * 'unsafe-inline'; img-src 'self' data: blob: https:; font-src * data:; connect-src *; media-src * data: blob:; frame-src *; frame-ancestors *; worker-src 'self'; manifest-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; upgrade-insecure-requests;
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot May 12, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🌐 Web query:

What are the security risks of frame-ancestors wildcard in Content Security Policy for DeFi applications?

💡 Result:

Using CSP frame-ancestors with a wildcard like '*' is generally high risk for DeFi apps because it allows any website to embed your UI, enabling clickjacking (UI redressing) and other framing-based user deception. 1) Direct clickjacking / UI redressing risk - The frame-ancestors directive controls which parent origins may embed your page in an iframe (and related embedding elements) [1]. If you effectively allow all origins (e.g., via a wildcard), attackers can frame your DeFi app inside their own site and trick users into clicking UI they believe they control. - This “unauthorized framing” is described as enabling clickjacking attacks in CSP wildcard findings [2]. 2) Bypass of the security boundary you intended for “sensitive” screens - DeFi frontends are particularly sensitive because UI actions often lead to signing or confirming transfers/approvals. Guidance on clickjacking defenses emphasizes that protections must be applied to every page with interactive elements (not just a login page), since attackers target the highest-value actions like transfer confirmations and other authenticated operations [3]. A wildcard frame-ancestors undermines that boundary by letting any origin embed those sensitive pages. 3) Increased blast radius for frontend compromise scenarios - In DeFi, trust failure in the frontend delivery path can translate into harmful user interactions (e.g., deceptive transaction prompts, routing/approval abuse) [4][5]. While frame-ancestors wildcard is not the same as script-src being overly permissive, letting any origin embed your app expands the opportunities for attackers to present deceptive UI flows around those compromised or manipulated states. 4) Policy “failure mode” is easy to misunderstand - If you accidentally deploy a too-permissive frame-ancestors source expression, it effectively changes who can embed your site; frame-ancestors does not fall back from default-src [1]. So relying on other CSP directives or default-src for safety while using an over-broad frame-ancestors expression can leave your app embeddable by unintended parties. Practical DeFi guidance (safer patterns) - Prefer denying all embedding unless you have a business need: frame-ancestors 'none' [1]. - If you must allow embedding, use an explicit allowlist of exact trusted origins (and their required subdomains) rather than broad wildcards; the directive supports allowing specific sources, and the allowed set determines embedding authorization [1]. In short: frame-ancestors wildcard (allowing arbitrary origins) removes the main technical protection against hostile framing and increases clickjacking risk for DeFi user interactions, making it a bad fit for hardened DeFi security posture.

Citations:


🏁 Script executed:

cat -n apps/cowswap-frontend/public/_headers | head -20

Repository: cowprotocol/cowswap

Length of output: 1100


Critical: frame-ancestors * allows clickjacking attacks.

The CSP directive frame-ancestors * permits this application to be embedded in iframes on any untrusted website. For a DeFi application handling financial transactions, this creates a serious clickjacking risk where attackers can overlay transparent iframes to trick users into authorizing unintended transactions.

Restrict to trusted domains or block iframe embedding entirely:

  • frame-ancestors 'self' (only allow same-origin embedding)
  • frame-ancestors 'none' (block all iframe embedding)
  • Or explicitly list trusted domains: frame-ancestors 'self' https://trusted-partner.com
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/cowswap-frontend/public/_headers` at line 2, The Content-Security-Policy
header currently sets "frame-ancestors *", which permits clickjacking; update
the CSP line in public/_headers to replace frame-ancestors * with a restrictive
value (e.g., frame-ancestors 'self' or frame-ancestors 'none', or an explicit
allowlist like frame-ancestors 'self' https://trusted-partner.com) and ensure
the rest of the policy string remains unchanged; locate the CSP header string
(the long line beginning with "Content-Security-Policy:") and edit only the
frame-ancestors token to the chosen restrictive option.

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.

We do embed the page in an iframe when running the widget (see widget.cow.fi for an example).
Wouldn't changing this break the widget behaviour?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

Good point — let me check the widget architecture to better understand the embedding pattern.


🏁 Script executed:

#!/bin/bash
# Check if there's a widget app or widget-specific routes/config
fd -t f -e html -e ts -e tsx -e json --full-path | xargs grep -l "widget" 2>/dev/null | grep -i widget | head -20

# Check if there are any existing frame-ancestors or X-Frame-Options settings
rg -rn "frame-ancestors|X-Frame-Options" --type-add 'config:*.{json,yaml,yml,toml,conf,ini,headers,txt}' --type config -g '!node_modules' 2>/dev/null | head -20

# Check for any widget app
fd -t d "widget" --max-depth 3 | head -10

# List apps directory to understand widget vs cowswap-frontend
ls apps/ 2>/dev/null

Length of output: 909


Let me also check how the widget constructs iframe URLs to understand the embedding pattern better.


🏁 Script executed:

#!/bin/bash
cat libs/widget-lib/src/cowSwapWidget.ts
echo "---"
cat libs/widget-lib/src/urlUtils.ts

Length of output: 18895


@alfetopito, you're absolutely right — changing frame-ancestors globally to 'none' or 'self' would break the widget, since libs/widget-lib is designed to embed cowswap-frontend (e.g. swap.cow.fi) as an iframe on any arbitrary third-party website. That's the core product design.

However, there is a meaningful middle ground. Looking at libs/widget-lib/src/urlUtils.ts, widget routes follow the path pattern /:chainId/widget/:tradeType/:sell/:buy. Cloudflare Pages _headers supports path-scoped rules, so you could scope frame-ancestors * only to widget routes and restrict all other routes:

# Non-widget routes - no iframe embedding needed
/*
  Content-Security-Policy: default-src 'self'; ... frame-ancestors 'self'; ...

# Widget routes - must be embeddable anywhere
/:chainId/widget/*
  Content-Security-Policy: default-src 'self'; ... frame-ancestors *; ...

This way:

  • The main app at /swap, /limit, /about, etc. is protected against clickjacking.
  • Widget routes remain embeddable by any third-party host, preserving the widget use case.

It doesn't eliminate the risk entirely (attackers could still frame a widget URL), but it meaningfully reduces the attack surface by limiting the embeddable surface to only the routes that actually need it.

Would you like me to draft the updated _headers file with this split?


✏️ Learnings added
Learnt from: alfetopito
Repo: cowprotocol/cowswap PR: 7401
File: apps/cowswap-frontend/public/_headers:2-2
Timestamp: 2026-05-12T17:23:47.226Z
Learning: In the cowprotocol/cowswap repository, `cowswap-frontend` is intentionally embedded as an iframe on arbitrary third-party websites via the CowSwap widget (libs/widget-lib). Widget routes follow the URL pattern `/:chainId/widget/:tradeType/:sell/:buy`. The default widget host is `https://swap.cow.fi`. `frame-ancestors *` in the CSP is required for the widget use case; however, it can be scoped to widget routes only using Cloudflare Pages path-based `_headers` rules.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

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.

If the access is limited to app paths, what would happen to static files? Do we need to manually whitelist any path that's supposed to be served by the app?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@alfetopito, great question — there are actually two good news here:

1. Static files don't need manual whitelisting for frame-ancestors

frame-ancestors controls which documents are allowed to embed this document in a nested browsing context like an <iframe>. Browsers only enforce frame-ancestors when rendering a response as a document inside a frame. Static assets like JS bundles, CSS, images, and fonts are fetched as subresources — they're never framed directly — so frame-ancestors on their response headers has no meaningful security effect. You don't need to list /assets/*, /static/*, etc. separately.

2. However, the path-scoping approach I suggested has a catch with Cloudflare Pages

An incoming request which matches multiple rules' URL patterns will inherit all rules' headers, and if a header is applied twice, the values are joined with a comma separator.

This means if you had:

/*
  Content-Security-Policy: ... frame-ancestors 'self'; ...

/:chainId/widget/*
  Content-Security-Policy: ... frame-ancestors *; ...

Widget routes would match both rules, and the browser would receive two Content-Security-Policy headers joined with a comma. Per the CSP spec, when multiple CSP headers are present, the browser enforces all of them simultaneously (intersection), so frame-ancestors 'self' + frame-ancestors * would effectively leave only 'self' — the permissive widget rule would be silently negated.

To work around this on Cloudflare Pages, you'd need to:

  • Use !Content-Security-Policy in the widget rule to remove the base rule, then re-add the full widget-specific CSP. But this means maintaining the full CSP string in two places.
  • Or use a Cloudflare Worker to set headers conditionally based on path (more robust but more complex).

Given that complexity, the pragmatic trade-off is to leave frame-ancestors * globally as-is (current state), since:

  • Widget embedding requires it
  • frame-ancestors on static assets is a no-op for browsers
  • The main framing risk is on interactive HTML pages, which realistically need the same policy as widget routes for this app anyway

Would you like me to explore the Worker-based approach, or are you comfortable keeping the current global frame-ancestors *?

@alfetopito alfetopito marked this pull request as ready for review May 12, 2026 17:25
@alfetopito alfetopito requested review from a team May 13, 2026 13:28
@alfetopito alfetopito self-assigned this May 13, 2026
Copy link
Copy Markdown
Contributor

@elena-zh elena-zh left a comment

Choose a reason for hiding this comment

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

works as described, thank you

@socket-security
Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedhusky@​9.1.71001006280100
Addedjson-schema@​0.4.01001006880100
Addedsafe-stable-stringify@​2.5.010010010080100
Addedtiny-invariant@​1.3.310010010080100
Addedfast-safe-stringify@​2.1.110010010083100
Addedtslib@​2.8.110010010085100
Addedms@​2.1.31001008689100
Addedtypescript@​5.9.3100100909890

View full report

@socket-security
Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: npm entities is 91.0% likely obfuscated

Confidence: 0.91

Location: Package overview

From: pnpm-lock.yamlnpm/entities@4.5.0

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore npm/entities@4.5.0. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

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.

2 participants