Verify #378: frontend trust boundaries, build guards, expert mode #909
No reviewers
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:implement
agent:implement
agent:open_issues
agent:ready
agent:research
agent:security_audit
agent:verify
architecture
backend
blocker:hybrid
blocker:launch
blocker:limit-orders
blocker:v2
block:log_only
block:security
bug
ci
contracts
correctness
deploy
dev
devops
docs
documentation
duplicate
e2e
enhancement
epic
feature
frontend
functional-completion
gas
good first issue
governance
help wanted
high-risk
hooks
hybrid
indexer
infra
infrastructure
integrators
invalid
launch-blocker
limit-orders
localnet
localterra
low priority
missing-implementation
needs-design
ops
performance
priority
high
priority
medium
product
qa
QA
question
ready
ready
research
scripts
security
security-hardening
smartcontracts
tech-debt
testing
ux
UX
v2
verification
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
code/cl8y-dex-terraclassic!909
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "verify/issue-378-frontend-trust-boundaries"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Implements the #376 remediation bundle tracked by #378:
docs/security-model.md; HTTPSVITE_INDEXER_URLin launch checklist.vite buildrejectsVITE_DEV_MNEMONICoutsidedevelopmentunlessVITE_ALLOW_DEV_MNEMONIC=local-only.connect-srcto env LCD/RPC/indexer + WalletConnect relay (viteCsp.ts); devindex.htmlkeeps broad policy./protocolonly (protocol-contract-addresses).CG_CMC_COMPLIANCE.md.VITE_WC_PROJECT_ID; removed shared WC default fromwallet.ts.ENABLE EXPERT MODE); 30%/50% thresholds unchanged.Acceptance checklist
docs/security-model.md§ Off-chain trust;docs/runbooks/launch-checklist.mdPhase 4VITE_DEV_MNEMONIC=test npx vite build --mode staging→ exit 1npx vite build --mode production(no WC) → exit 1VITE_WC_PROJECT_ID=… npx vite build --mode production→dist/index.htmlconnect-src has no barehttps:npx vitest run src/pages/ProtocolPage.test.tsxPASSnpx vitest run src/utils/__tests__/tokenLogoAllowlist.test.ts src/components/ui/__tests__/TokenLogo.test.tsxPASSnpx vitest run src/components/swap/__tests__/ExpertModeModal.test.tsxPASS;SwapPage.test.tsxupdatedmake test-frontend→ 996 passedmake lint-frontend→ 0 errorsrgdist for default WC ID / test mnemonic → not foundmake devroute/protocol/expertmake has-localterraexit 2)Test plan
Follow-ups
render.yamlCSP headers at deploy time (static header cannot read Vite env).changed the description
changed the description
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit
eaecea2462. Configure here.CSP omits runtime LCD fallbacks
Medium Severity
Production
connect-srcis built only fromVITE_TERRA_LCD_URL,VITE_TERRA_RPC_URL, andVITE_INDEXER_URL. The app still falls back to default public LCD/RPC URLs inconstants.tswhen those vars are unset, so a production bundle can call hosts that CSP never whitelists and the browser blocks them.Reviewed by Cursor Bugbot for commit
eaecea2462. Configure here.Render CSP blocks API calls
High Severity
The static
Content-Security-Policyheader’sconnect-srclists only'self'and WalletConnect hosts, not the Terra LCD, RPC, or indexer origins the dApp fetches at runtime. Browsers enforce every CSP policy together, so this header intersects with the production meta policy and blocks those requests on Render.Reviewed by Cursor Bugbot for commit
eaecea2462. Configure here.Security review — MR !909
Commit reviewed:
eaecea24627cac200be7dd72ae8197b760d38e04Scope: #378 frontend trust-boundary bundle — build env guards (
VITE_DEV_MNEMONIC,VITE_WC_PROJECT_ID), production CSP (viteCsp.ts,render.yaml), token logo host allowlist (TokenLogo/tokenLogoAllowlist.ts), protocol-page contract audit surface, expert-mode typed confirmation, and related docs/tests.Outcome:
FINDINGS: 0medium+Summary
This MR is a net hardening pass. Traced attacker-controlled inputs (indexer
logo_url, build-timeVITE_*, expert-mode UI, CSP env URLs) to their sinks:developmentbuilds reject inlinedVITE_DEV_MNEMONICunlessVITE_ALLOW_DEV_MNEMONIC=local-only; production requiresVITE_WC_PROJECT_ID. Removes shared WC default from the bundle. No bypass for external attackers — only CI/operator env.resolveAllowedTokenLogoUrienforceshttps:+ hostname allowlist before<img src>; disallowed URIs fall back to blockies. Narrows prior blankethttps:img-src. Residual phishing via indexer-curated URLs on allowlisted CDNs (e.g.gitlab.comraw) is documented off-chain trust, not a new client-side sink.buildProductionCspMetaContentderivesconnect-src/img-srcfrom env origins + fixed WC hosts;originFromEnvUrlnormalizes viaURL()(no HTML/CSP attribute breakout).unsafe-inlinescript/style pre-exists.SwapPageviareadExpertMode(). localStorage tampering is same-origin self-risk only./protocolaudit surface; on-chain execution still uses env-inlined addresses (pre-existing deploy trust).Prior threads re-checked
Re-evaluated Bugbot inline notes on
render.yamlandviteCsp.ts:constants.tsLCD fallbacks — UnsetVITE_TERRA_*yields runtimepublicnode.comcalls that production CSP would block; again misconfiguration/DoS, not a plausible fund-theft or injection path.Neither rises to medium+ security under an exploitability standard.
Inline finding threads: none (no medium+ issues on this diff).
changed this line in version 2 of the diff
added 1 commit
06d36616- Fix production CSP fallback hosts and Render header intersection.Compare with previous version
resolved all threads
Bugfix follow-up (
06d36616)buildProductionConnectSrcnow includesPRODUCTION_TERRA_LCD_FALLBACK/PRODUCTION_TERRA_RPC_FALLBACK(same hosts asconstants.ts) whenVITE_TERRA_*env URLs are unset. Regression:viteCsp.test.tsempty-env case.Content-Security-Policyheader fromrender.yaml. Browsers intersect header + meta policies; the static header could not mirror operatorVITE_*origins (LCD/RPC/indexer) and blocked fetches on Render. Production CSP remains env-aware viavite build→dist/index.htmlmeta (viteCsp.ts). Other security headers (X-Content-Type-Options,X-Frame-Options,Referrer-Policy) unchanged.Tests:
npx vitest run src/utils/__tests__/viteCsp.test.ts src/viteConfig.build.test.ts— 9 passed.changed the description
Security review — MR !909
Commit reviewed:
06d36616d1e1fb03327da9d9d6a063e07b707c40Scope: #378 frontend trust-boundary bundle —
vite.config.tsbuild guards (VITE_DEV_MNEMONIC,VITE_WC_PROJECT_ID), production CSP (viteCsp.ts,render.yaml), token logo host allowlist (tokenLogoAllowlist.ts/TokenLogo),/protocolcontract audit surface, expert-mode typed confirmation, and related docs/tests.Outcome:
FINDINGS: 0medium+Summary
Re-reviewed after bugfix commit
06d36616(LCD/RPC CSP fallbacks + removal of static RenderContent-Security-Policyheader). Traced attacker-controlled inputs to sinks:developmentbuilds reject inlinedVITE_DEV_MNEMONICunlessVITE_ALLOW_DEV_MNEMONIC=local-only; production requiresVITE_WC_PROJECT_ID. Shared WC default removed fromwallet.ts. Controls are build/CI-operator scoped — no external bypass.buildProductionCspMetaContentderives origins viaURL()(originFromEnvUrl); includesconstants.tsLCD/RPC fallbacks when env unset. Static Render CSP header removed so header ∩ meta no longer blocks legitimate fetches.unsafe-inlinescript/style is pre-existing.logo_url→resolveAllowedTokenLogoUrienforceshttps:+ hostname allowlist before<img src>; disallowed URIs fall back to blockies. Productionimg-srcmirrors allowlist (narrower than prior blankethttps:). Residual phishing via operator-curated allowlisted hosts is documented off-chain trust, not a new client sink.SwapPageviareadExpertMode()/SWAP_EXPERT_MODE_SLIPPAGE_BLOCK_PCT. localStorage tampering is same-origin self-risk only./protocolfor audit; on-chain execution still uses env-inlined addresses (deploy trust, unchanged).Prior threads re-checked
06d36616by removing static CSP header; intersecting policies was availability/config, not attacker-widened fetch surface.buildProductionConnectSrcnow includesPRODUCTION_TERRA_LCD_FALLBACK/PRODUCTION_TERRA_RPC_FALLBACK.docs/security-model.md; out of scope for client-only hardening in this diff.Inline finding threads: none (no medium+ issues on this diff).
Security review: no medium+ findings on this diff.
added 33 commits
main01b1b664- Merge branch 'main' into verify/issue-378-frontend-trust-boundariesCompare with previous version
Resolved merge conflicts with
main(commit01b1b664).Kept from MR branch:
viteCsp.tsproduction CSP module, unifiedassertBuildEnvGuards, no shared WalletConnect default inwallet.ts,protocol-contract-addressesaudit section withAddressRow.Integrated from main: LCD/RPC rows on
/protocol,VITE_VERIFY_DEPLOY_ADDRESSESin.env.example, merged token-logo host allowlist (CoinGecko/CMC + IPFS gateways) with backward-compat aliases, and combined launch-checklist / compliance doc wording.Targeted vitest:
viteConfig.build.test.ts,viteCsp.test.ts,tokenLogoAllowlist,ExpertModeModal,ProtocolPage— all pass.Security review — MR !909
Commit reviewed:
01b1b664e241ea36be95f003a5f08ddb90db69e7Scope: #378 frontend trust-boundary bundle after merge with
main—vite.config.tsbuild guards (VITE_DEV_MNEMONIC,VITE_WC_PROJECT_ID), production CSP (viteCsp.ts,render.yaml), token logo host allowlist (tokenLogoAllowlist.ts/TokenLogo),/protocolcontract audit surface +deployAddressVerification.ts, expert-mode typed confirmation (EXPERT_MODE_ACK_VERSION2), bootstrap script extraction (public/bootstrap/*), and related docs/tests.Outcome:
FINDINGS: 0medium+Summary
Re-reviewed current MR head (includes merge
01b1b664resolvingmainlanding conflicts). Traced attacker-controlled inputs to sinks:developmentbuilds rejectVITE_DEV_MNEMONICunlessVITE_ALLOW_DEV_MNEMONIC=local-only; production requiresVITE_WC_PROJECT_ID.wallet.tsdrops shared WC default.viteConfig.build.test.tsasserts production mnemonic rejection. Controls are build/CI-operator scoped — no unauthenticated bypass.buildProductionCspMetaContentderives origins viaURL(); includesconstants.tsLCD/RPC fallbacks when env unset. Static Render CSP header removed (fixes header ∩ meta blocking).unsafe-inlinescript/style matches pre-merge production template needs after bootstrap externalization.logo_url→resolveAllowedTokenLogoUrienforceshttps:+ hostname allowlist before<img src>; disallowed URIs fall back to blockies. Productionimg-srcmirrors allowlist. Residual phishing via operator-curated allowlisted hosts is documented off-chain trust, not a new client sink.SwapPageviareadExpertMode()/SWAP_EXPERT_MODE_SLIPPAGE_BLOCK_PCT.localStoragetampering is same-origin self-risk only./protocolfor audit; optionalverifyDeployAddressesOnLcdlogs warnings only (no authz change). On-chain execution still uses env-inlined addresses (deploy trust, unchanged).theme.js/trade-shell.jsuse static DOM writes;trade-shell.jsinnerHTMLis constant markup (no user/input interpolation).Prior threads re-checked
06d36616(PRODUCTION_TERRA_LCD_FALLBACK/PRODUCTION_TERRA_RPC_FALLBACK).06d36616(staticContent-Security-Policyheader removed fromrender.yaml).Security review: no medium+ findings on this diff.
mentioned in commit
d7aa33e895