Skip to content

fix: fail closed for RWA and widget token restrictions#7621

Draft
fairlighteth wants to merge 8 commits into
developfrom
deepsec/medium-05-rwa-geoblock-hardening
Draft

fix: fail closed for RWA and widget token restrictions#7621
fairlighteth wants to merge 8 commits into
developfrom
deepsec/medium-05-rwa-geoblock-hardening

Conversation

@fairlighteth

@fairlighteth fairlighteth commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Addresses the MEDIUM RWA/geoblock and widget token-scope findings in cowswap-frontend.

This PR makes the restriction model fail closed when prerequisites are missing or still loading:

  • Keeps RWA gating blocked while feature flags, geolocation, or restricted-token metadata are unresolved.
  • Applies RWA checks to both sides of the trade before clearing the gate.
  • Keeps EthFlow continuation behind the same consent boundary.
  • Enforces widget token-list scopes consistently for favorites, bridge search, and token import paths.
  • Refetches full default token lists when curated-only mode relaxes after geo checks, so non-US users do not stay stuck on the curated subset.
  • Adds focused coverage for token-selection, trade-form validation, and curated-mode invalidation behavior.

To Test

  1. Run targeted frontend checks
  • pnpm exec jest --config apps/cowswap-frontend/jest.config.mjs --runInBand --runTestsByPath apps/cowswap-frontend/src/modules/tokensList/state/tokensToSelectAtom.test.ts apps/cowswap-frontend/src/modules/tokensList/hooks/useTokensToSelect.test.ts apps/cowswap-frontend/src/modules/tradeFormValidation/services/validateTradeForm.test.ts passes.
  • pnpm exec jest --config libs/tokens/jest.config.ts --runInBand --runTestsByPath libs/tokens/src/updaters/TokensListsUpdater/curatedMode.test.ts passes.
  • pnpm exec tsc --noEmit -p apps/cowswap-frontend/tsconfig.app.json passes.
  1. Verify RWA fail-closed behavior
  • Simulate restricted-token metadata still loading or unavailable and confirm the trade path stays blocked instead of allowing through.
  • Simulate missing geo/flag prerequisites and confirm consent-gated lists and trades fail closed.
  • Confirm the UI does not clear the RWA gate after checking only one side of a two-token trade.
  1. Verify EthFlow consent behavior
  • Start an EthFlow path involving a consent-restricted token.
  • Confirm the continuation path still requires the same RWA consent and cannot bypass it.
  1. Verify widget token-scope enforcement
  • In widget mode with a restricted token list, confirm bridge search only shows allowed tokens.
  • Confirm favorite-token fallbacks do not reintroduce tokens outside the widget-selected scope.
  • Confirm restricted token imports stay blocked until the required consent state is available.
  1. Verify curated-list recovery after geo checks
  • Start from the curated-only path while geo checks are still unresolved.
  • Confirm a later non-US geo result restores the full default token-list set without waiting for the 6h refresh interval.

Background

These findings were mostly fail-open cases.

The goal here is not to broaden restrictions, but to make sure missing geo data, partially loaded token metadata, or widget-mode fallbacks do not silently turn a blocked state into an allowed one.

@vercel

vercel Bot commented Jun 6, 2026

Copy link
Copy Markdown

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

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

Request Review

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 48fad9d3-8517-4fdd-a4d4-e7dd4933eb55

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deepsec/medium-05-rwa-geoblock-hardening

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

cloudflare-workers-and-pages Bot commented Jun 6, 2026

Copy link
Copy Markdown

Deploying explorer-dev with  Cloudflare Pages  Cloudflare Pages

Latest commit: 894f645
Status: ✅  Deploy successful!
Preview URL: https://22fd3e65.explorer-dev-dxz.pages.dev
Branch Preview URL: https://deepsec-medium-05-rwa-geoblo.explorer-dev-dxz.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 6, 2026

Copy link
Copy Markdown

Deploying swap-dev with  Cloudflare Pages  Cloudflare Pages

Latest commit: 894f645
Status: ✅  Deploy successful!
Preview URL: https://a894e07f.swap-dev-5u6.pages.dev
Branch Preview URL: https://deepsec-medium-05-rwa-geoblo.swap-dev-5u6.pages.dev

View logs

- block trade and import flows until RWA checks are ready
- hide restricted token lists until geo or consent checks pass
- enforce widget-selected token scopes for favorites and bridge search
- reset the token list cache when geo checks switch from
  curated-only mode back to the full source set
- cover the invalidation rule with a focused unit test
@fairlighteth

Copy link
Copy Markdown
Contributor Author
AI Review (Codex GPT-5, worked 2m): no new non-duplicate findings

Review completed. I found no new non-duplicate comments worth posting.

Review scope and related context

Related context checked:

  • libs/tokens/src/updaters/TokensListsUpdater/index.tsx: current code resets the token-list cache when curated-only mode relaxes, so the full default list set can refetch immediately.
  • apps/cowswap-frontend/src/modules/rwa/hooks/useRwaTokenStatus.ts: current code consistently keeps the RWA gate fail-closed while feature flags, geo, or restricted-token metadata are unresolved.
  • apps/cowswap-frontend/src/modules/trade/hooks/useConfirmTradeWithRwaCheck.ts and apps/cowswap-frontend/src/modules/ethFlow/containers/EthFlow/hooks/useEthFlowActions.ts: the current diff applies the same pending/restricted/consent handling to both standard trade confirmation and EthFlow continuation.
  • There are still no human review threads on this PR; only deploy/status comments are present, so there were no active threads to de-duplicate against.

- filter favorite chips against the current selectable token set
- cover widget-scoped favorite leakage in selector hook tests
- preserve virtual widget lists while curated-only mode is active
- cover the curated widget token path with a regression test
@fairlighteth

Copy link
Copy Markdown
Contributor Author
⚠️ AI Review (Codex GPT-5, worked 4m): geo-check race can re-enable curated mode after the flag turns off

Finding: stale api.country.is responses can override a later isGeoBlockEnabled=false result

  • Location: libs/tokens/src/updaters/TokensListsUpdater/index.tsx:119
  • The effect now starts the geo fetch before the geoblock flag has necessarily resolved. If that request is still in flight when LaunchDarkly later resolves isGeoBlockEnabled to false, the next effect run correctly calls setCuratedListOnly(false) and returns, but the older promise still resolves and calls setCuratedListOnly(isUsUser) (or true in catch).
  • That leaves the app back in curated-only mode even though geoblocking is disabled, which contradicts the PR’s fail-closed contract and can silently narrow the default token-list set again.

Suggested fix

  • Guard the async callbacks with an effect-local cancellation/staleness flag so only the latest [chainId, isGeoBlockEnabled] run can update curated mode.
  • Add a targeted updater test that simulates undefined/true -> false while the geo request is pending and asserts the stale response cannot switch curated mode back on.
Review scope and related context

This is separate from the existing comments on the PR, which are currently only deploy/status comments plus an earlier AI no-findings summary. There are still no human review threads covering this race.

🤖 Prompt for AI agents
Verify this finding against current code. Fix only if still valid, keep the change minimal, and validate with targeted tests.

Context:
- libs/tokens/src/updaters/TokensListsUpdater/index.tsx
- The geo fetch starts before isGeoBlockEnabled is guaranteed to be resolved.
- A later effect run can set curated mode to false when the flag resolves false, but the older fetch callbacks still call setCuratedListOnly(...) afterward.
- Expected fix: ignore stale async results from earlier effect runs, and add a regression test for the pending-fetch -> flag-false transition.

- keep later geoblock flag changes authoritative over old requests
- cover the pending geo request race with a regression test
@fairlighteth

Copy link
Copy Markdown
Contributor Author
AI Review (Codex GPT-5, worked 1m): no new non-duplicate findings

Review completed. I found no new non-duplicate comments worth posting.

Review scope and related context

Related context checked:

  • libs/tokens/src/updaters/TokensListsUpdater/index.tsx: the stale geo-response race is now guarded with effect cleanup/abort logic, so older api.country.is requests no longer override a later isGeoBlockEnabled=false state.
  • libs/tokens/src/updaters/TokensListsUpdater/index.test.tsx: current head adds a focused updater regression test for that pending-request transition.
  • libs/tokens/src/state/tokenLists/tokenListsStateAtom.ts: curated-only mode now retains virtual widget lists, so customTokens are no longer filtered out in widget mode.
  • apps/cowswap-frontend/src/modules/tokensList/hooks/useTokensToSelect.ts: favorite tokens are still filtered against the current selectable token set, so the earlier widget-scope leakage is not reproducible in current code.
  • There are still no human review threads on this PR; the current comments are deploy/status comments plus earlier AI review notes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant