Verify #378: Frontend trust boundaries, build guards, and expert mode #906

Merged
PlasticDigits merged 2 commits from verify/issue-378-frontend-trust-boundaries into main 2026-06-14 02:54:45 +00:00
PlasticDigits commented 2026-06-13 14:02:47 +00:00 (Migrated from gitlab.com)

Summary

Implements the #378 remediation bundle for parent #376 (H-04, H-05, M-07, M-08, M-09, M-10, M-15): off-chain trust documentation, production build guards, narrowed CSP connect-src, protocol-page contract audit surface, token logo host allowlist, and expert-mode typed confirmation.

Acceptance checklist

Criterion Result How verified
Off-chain indexer trust documented; deploy checklist requires HTTPS indexer URL PASS docs/security-model.md § Off-chain trust; docs/frontend.md § Off-chain deploy checklist; docs/runbooks/launch-checklist.md Phase 4
vite build fails on dev mnemonic outside development; fails on missing WC project ID in production PASS VITE_DEV_MNEMONIC=test-seed npm run build -- --mode staging → error; npm run build without WC ID → error; src/viteConfig.build.test.ts
CSP tightened (no broad https: connect-src in production); documented dev exception PASS dist/index.html connect-src lists explicit hosts only; render.yaml updated; docs/frontend.md § CSP
Factory/router visible on protocol/audit page only; startup verification documented PASS ProtocolPage.tsx data-testid="protocol-core-contracts"; ProtocolPage.test.tsx; docs note optional LCD sanity
Logo host allowlist enforced; listing human-review documented PASS tokenLogoAllowlist.ts + TokenLogo.tsx; docs/CG_CMC_COMPLIANCE.md § Token metadata human review
Expert mode requires typed confirmation; 30%/50% thresholds unchanged PASS ExpertModeModal.tsx phrase enable expert mode; ExpertModeModal.test.tsx; swapRouteSlippage.ts still 30% block
All frontend unit tests pass PASS make test-frontend — 166 files, 994 tests
Production artifacts: no dev mnemonic, no default WC project ID PASS VITE_WC_PROJECT_ID=verify-test-wc-id npm run build; rg on dist/ — no 2ce7811b… or mnemonic strings
Attack: evil logo host → blockie PASS TokenLogo.test.tsx + tokenLogoAllowlist.test.ts
Attack: expert mode without phrase PASS ExpertModeModal.test.tsx — enable button disabled until phrase matches
Manual make dev browser walkthrough FAIL LocalTerra not provisioned (make has-localterra exit 2). UI flows covered by SwapPage.test.tsx (route summary, expert mode), ProtocolPage.test.tsx

Test plan

make test-frontend
make lint-frontend
cd frontend-dapp && npm run test -- --run src/viteConfig.build.test.ts src/components/swap/__tests__/ExpertModeModal.test.tsx src/components/ui/__tests__/TokenLogo.test.tsx
VITE_WC_PROJECT_ID=verify-test-wc-id npm run build  # frontend-dapp/
rg '2ce7811b869be33ffad28cff05c93c15' dist/ || echo OK

Follow-ups

  • Move index.html theme bootstrap inline scripts into bundled modules to allow removing script-src 'unsafe-inline' in production CSP.
  • Optional client-side factory LCD sanity check on startup (documented only today).
  • Re-run manual make dev browser QA after make setup-cloud-localterra on a VM with Chrome.

Note

Low Risk
Documentation and a frontend unit test only; no runtime logic changes in this diff.

Overview
Adds operator guidance for indexer logo_url metadata in docs/CG_CMC_COMPLIANCE.md: human review steps before production (address/symbol verification, allowlisted HTTPS hosts via tokenLogoAllowlist.ts, re-review on change), tied to #378 / M-09.

Adds ProtocolPage.test.tsx to assert the protocol page exposes the factory/router audit block (protocol-deploy-addresses, protocol-factory-address, protocol-router-address) with mocked indexer calls — regression coverage for #378 contract visibility.

Reviewed by Cursor Bugbot for commit 4e06ee3688. Bugbot is set up for automated code reviews on this repo. Configure here.

## Summary Implements the #378 remediation bundle for parent #376 (H-04, H-05, M-07, M-08, M-09, M-10, M-15): off-chain trust documentation, production build guards, narrowed CSP `connect-src`, protocol-page contract audit surface, token logo host allowlist, and expert-mode typed confirmation. ## Acceptance checklist | Criterion | Result | How verified | |-----------|--------|--------------| | Off-chain indexer trust documented; deploy checklist requires HTTPS indexer URL | **PASS** | `docs/security-model.md` § Off-chain trust; `docs/frontend.md` § Off-chain deploy checklist; `docs/runbooks/launch-checklist.md` Phase 4 | | `vite build` fails on dev mnemonic outside development; fails on missing WC project ID in production | **PASS** | `VITE_DEV_MNEMONIC=test-seed npm run build -- --mode staging` → error; `npm run build` without WC ID → error; `src/viteConfig.build.test.ts` | | CSP tightened (no broad `https:` connect-src in production); documented dev exception | **PASS** | `dist/index.html` connect-src lists explicit hosts only; `render.yaml` updated; `docs/frontend.md` § CSP | | Factory/router visible on protocol/audit page only; startup verification documented | **PASS** | `ProtocolPage.tsx` `data-testid="protocol-core-contracts"`; `ProtocolPage.test.tsx`; docs note optional LCD sanity | | Logo host allowlist enforced; listing human-review documented | **PASS** | `tokenLogoAllowlist.ts` + `TokenLogo.tsx`; `docs/CG_CMC_COMPLIANCE.md` § Token metadata human review | | Expert mode requires typed confirmation; 30%/50% thresholds unchanged | **PASS** | `ExpertModeModal.tsx` phrase `enable expert mode`; `ExpertModeModal.test.tsx`; `swapRouteSlippage.ts` still 30% block | | All frontend unit tests pass | **PASS** | `make test-frontend` — 166 files, 994 tests | | Production artifacts: no dev mnemonic, no default WC project ID | **PASS** | `VITE_WC_PROJECT_ID=verify-test-wc-id npm run build`; `rg` on `dist/` — no `2ce7811b…` or mnemonic strings | | Attack: evil logo host → blockie | **PASS** | `TokenLogo.test.tsx` + `tokenLogoAllowlist.test.ts` | | Attack: expert mode without phrase | **PASS** | `ExpertModeModal.test.tsx` — enable button disabled until phrase matches | | Manual `make dev` browser walkthrough | **FAIL** | LocalTerra not provisioned (`make has-localterra` exit 2). UI flows covered by `SwapPage.test.tsx` (route summary, expert mode), `ProtocolPage.test.tsx` | ## Test plan ```bash make test-frontend make lint-frontend cd frontend-dapp && npm run test -- --run src/viteConfig.build.test.ts src/components/swap/__tests__/ExpertModeModal.test.tsx src/components/ui/__tests__/TokenLogo.test.tsx VITE_WC_PROJECT_ID=verify-test-wc-id npm run build # frontend-dapp/ rg '2ce7811b869be33ffad28cff05c93c15' dist/ || echo OK ``` ## Follow-ups - Move `index.html` theme bootstrap inline scripts into bundled modules to allow removing `script-src 'unsafe-inline'` in production CSP. - Optional client-side factory LCD sanity check on startup (documented only today). - Re-run manual `make dev` browser QA after `make setup-cloud-localterra` on a VM with Chrome. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Documentation and a frontend unit test only; no runtime logic changes in this diff. > > **Overview** > Adds **operator guidance** for indexer `logo_url` metadata in `docs/CG_CMC_COMPLIANCE.md`: human review steps before production (address/symbol verification, allowlisted HTTPS hosts via `tokenLogoAllowlist.ts`, re-review on change), tied to **#378 / M-09**. > > Adds **`ProtocolPage.test.tsx`** to assert the protocol page exposes the factory/router audit block (`protocol-deploy-addresses`, `protocol-factory-address`, `protocol-router-address`) with mocked indexer calls — regression coverage for **#378** contract visibility. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 4e06ee36886598e8b9bfd74f498c1dd4c359272d. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->
PlasticDigits commented 2026-06-13 14:05:34 +00:00 (Migrated from gitlab.com)

Security review — MR !906

Commit reviewed: 525056e0ffb110a9f79bd799f8063007fbfb9c8e

Scope: Frontend trust-boundary hardening for #378 — production build guards (VITE_DEV_MNEMONIC, VITE_WC_PROJECT_ID), narrowed production CSP connect-src, token logo host allowlist, expert-mode typed confirmation, protocol-page contract audit surface, and related docs/runbook updates.

Method: Full MR diff review with attacker-input tracing on logo URLs (indexer logo_url → TokenLogo), build-time env injection paths, CSP enforcement (Vite transformIndexHtml + render.yaml), WalletConnect project ID resolution, and expert-mode enablement flow. Cross-checked prior MR discussion threads (none).

Outcome: FINDINGS: 0 medium+

No new medium, high, or critical vulnerabilities identified on this diff. Inline threads: none.

Areas reviewed (no exploitable path found)

Change Assessment
tokenLogoAllowlist.ts + TokenLogo.tsx Indexer-controlled logo_url is hostname-allowlisted (https: + exact host match); untrusted hosts fall back to blockies. No subdomain-suffix bypass (gitlab.com.evil.com rejected); www.gitlab.com blocked (registry uses bare gitlab.com). Residual logo-phishing on UGC hosts (e.g. public GitLab repos) is operator-trust / human-review scope documented in MR — narrower than pre-MR arbitrary https: logos.
vite.config.ts build guards VITE_DEV_MNEMONIC blocked for staging/production; escape hatch requires VITE_ALLOW_DEV_MNEMONIC=local-only + VITE_NETWORK=local + non-staging/non-production mode — deploy-time misconfig only, not remotely triggerable.
wallet.ts resolveWcProjectId() Shared default WC ID gated on import.meta.env.DEV; production builds without ID fail at build (vite.config) and runtime.
cspConnectSrc.ts / render.yaml Production connect-src narrowed from broad https:; env-derived LCD/RPC/indexer origins parsed via URL API. Dual CSP (meta + Render header) is restrictive intersection — operational indexer-host alignment, not attacker leverage.
ExpertModeModal.tsx Typed phrase is UX friction; localStorage toggle remains user-controlled (pre-existing). Not a new authz boundary.
ProtocolPage.tsx Build-time VITE_* addresses rendered via React text nodes / AddressRow — no HTML injection sink.

Label: block:security not applied (zero medium+ findings).

## Security review — MR !906 **Commit reviewed:** `525056e0ffb110a9f79bd799f8063007fbfb9c8e` **Scope:** Frontend trust-boundary hardening for #378 — production build guards (`VITE_DEV_MNEMONIC`, `VITE_WC_PROJECT_ID`), narrowed production CSP `connect-src`, token logo host allowlist, expert-mode typed confirmation, protocol-page contract audit surface, and related docs/runbook updates. **Method:** Full MR diff review with attacker-input tracing on logo URLs (indexer `logo_url` → `TokenLogo`), build-time env injection paths, CSP enforcement (Vite `transformIndexHtml` + `render.yaml`), WalletConnect project ID resolution, and expert-mode enablement flow. Cross-checked prior MR discussion threads (none). **Outcome:** `FINDINGS: 0` medium+ No new medium, high, or critical vulnerabilities identified on this diff. Inline threads: none. ### Areas reviewed (no exploitable path found) | Change | Assessment | |--------|------------| | `tokenLogoAllowlist.ts` + `TokenLogo.tsx` | Indexer-controlled `logo_url` is hostname-allowlisted (`https:` + exact host match); untrusted hosts fall back to blockies. No subdomain-suffix bypass (`gitlab.com.evil.com` rejected); `www.gitlab.com` blocked (registry uses bare `gitlab.com`). Residual logo-phishing on UGC hosts (e.g. public GitLab repos) is operator-trust / human-review scope documented in MR — narrower than pre-MR arbitrary `https:` logos. | | `vite.config.ts` build guards | `VITE_DEV_MNEMONIC` blocked for staging/production; escape hatch requires `VITE_ALLOW_DEV_MNEMONIC=local-only` + `VITE_NETWORK=local` + non-staging/non-production mode — deploy-time misconfig only, not remotely triggerable. | | `wallet.ts` `resolveWcProjectId()` | Shared default WC ID gated on `import.meta.env.DEV`; production builds without ID fail at build (`vite.config`) and runtime. | | `cspConnectSrc.ts` / `render.yaml` | Production `connect-src` narrowed from broad `https:`; env-derived LCD/RPC/indexer origins parsed via `URL` API. Dual CSP (meta + Render header) is restrictive intersection — operational indexer-host alignment, not attacker leverage. | | `ExpertModeModal.tsx` | Typed phrase is UX friction; `localStorage` toggle remains user-controlled (pre-existing). Not a new authz boundary. | | `ProtocolPage.tsx` | Build-time `VITE_*` addresses rendered via React text nodes / `AddressRow` — no HTML injection sink. | **Label:** `block:security` not applied (zero medium+ findings).
PlasticDigits commented 2026-06-13 14:17:21 +00:00 (Migrated from gitlab.com)

added 11 commits

  • 525056e0...9f1d4cb2 - 10 commits from branch main
  • 4e06ee36 - Merge main into verify/issue-378-frontend-trust-boundaries.

Compare with previous version

added 11 commits <ul><li>525056e0...9f1d4cb2 - 10 commits from branch <code>main</code></li><li>4e06ee36 - Merge main into verify/issue-378-frontend-trust-boundaries.</li></ul> [Compare with previous version](/PlasticDigits/cl8y-dex-terraclassic/-/merge_requests/188/diffs?diff_id=1850346604&start_sha=525056e0ffb110a9f79bd799f8063007fbfb9c8e)
PlasticDigits commented 2026-06-13 14:17:24 +00:00 (Migrated from gitlab.com)

Resolved merge conflicts with main (commit 4e06ee36).

Approach: Merged main into the source branch and aligned overlapping #378 code with main's canonical implementation (vite CSP/build guards, ENABLE EXPERT MODE phrase, token logo allowlist naming).

Kept from this MR: ProtocolPage.test.tsx (updated for protocol-deploy-addresses testids), CG/CMC token metadata human-review section, and verification test coverage.

Removed as superseded: cspConnectSrc.ts and duplicate __tests__/ files (main uses inline CSP in vite.config.ts).

Sanity: make test-frontend — 166 files, 999 tests passed.

Resolved merge conflicts with `main` (commit 4e06ee36). **Approach:** Merged `main` into the source branch and aligned overlapping #378 code with main's canonical implementation (vite CSP/build guards, `ENABLE EXPERT MODE` phrase, token logo allowlist naming). **Kept from this MR:** `ProtocolPage.test.tsx` (updated for `protocol-deploy-addresses` testids), CG/CMC token metadata human-review section, and verification test coverage. **Removed as superseded:** `cspConnectSrc.ts` and duplicate `__tests__/` files (main uses inline CSP in `vite.config.ts`). **Sanity:** `make test-frontend` — 166 files, 999 tests passed.
ghost1 commented 2026-06-13 14:17:27 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
ghost1 commented 2026-06-13 14:17:33 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
PlasticDigits commented 2026-06-13 14:18:48 +00:00 (Migrated from gitlab.com)

Security review — MR !906

Commit reviewed: 4e06ee36886598e8b9bfd74f498c1dd4c359272d

Scope: Post-merge-conflict diff vs main (base_sha 9f1d4cb2 → head_sha 4e06ee36): operator token-metadata human-review documentation (docs/CG_CMC_COMPLIANCE.md) and ProtocolPage.test.tsx regression coverage for factory/router audit test IDs. Runtime #378 hardening (build guards, CSP, logo allowlist, expert-mode phrase) is already on main and is out of this diff.

Method: Diff-only review with attacker-input tracing on changed files. Cross-checked prior security review on 525056e0 — that broader bundle assessment still holds on main; this pass re-validates only what this MR still adds.

Outcome: FINDINGS: 0 medium+

Security review: no medium+ findings on this diff. Inline threads: none.

Areas reviewed (no exploitable path in diff)

Change Assessment
docs/CG_CMC_COMPLIANCE.md § Token metadata human review Operator/process documentation only; no executable code, secrets, or client trust-boundary changes.
ProtocolPage.test.tsx Vitest harness with mocked indexer client; asserts DOM test IDs. No production sinks, no attacker-controlled input paths, no credential or env leakage.

Label: block:security not applied (zero medium+ findings).

## Security review — MR !906 **Commit reviewed:** `4e06ee36886598e8b9bfd74f498c1dd4c359272d` **Scope:** Post-merge-conflict diff vs `main` (`base_sha` `9f1d4cb2` → `head_sha` `4e06ee36`): operator token-metadata human-review documentation (`docs/CG_CMC_COMPLIANCE.md`) and `ProtocolPage.test.tsx` regression coverage for factory/router audit test IDs. Runtime #378 hardening (build guards, CSP, logo allowlist, expert-mode phrase) is already on `main` and is **out of this diff**. **Method:** Diff-only review with attacker-input tracing on changed files. Cross-checked prior security review on `525056e0` — that broader bundle assessment still holds on `main`; this pass re-validates only what this MR still adds. **Outcome:** `FINDINGS: 0` medium+ Security review: no medium+ findings on this diff. Inline threads: none. ### Areas reviewed (no exploitable path in diff) | Change | Assessment | |--------|------------| | `docs/CG_CMC_COMPLIANCE.md` § Token metadata human review | Operator/process documentation only; no executable code, secrets, or client trust-boundary changes. | | `ProtocolPage.test.tsx` | Vitest harness with mocked indexer client; asserts DOM test IDs. No production sinks, no attacker-controlled input paths, no credential or env leakage. | **Label:** `block:security` not applied (zero medium+ findings).
PlasticDigits commented 2026-06-14 02:54:46 +00:00 (Migrated from gitlab.com)

mentioned in commit 171aa60b58

mentioned in commit 171aa60b58f5f033b9f2f17a9d59689462686076
PlasticDigits (Migrated from gitlab.com) merged commit 171aa60b58 into main 2026-06-14 02:54:46 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic!906
No description provided.