Skip to content

Security: ThrownLemon/conceal-bridge-ux

docs/security.md

Security Guide

This guide defines security requirements and safe implementation rules.

Core references in this repo:


1) Threat model (what we defend against)

The frontend must assume:

  • The browser is a hostile environment (extensions, injected scripts, malicious iframes).
  • Users can be tricked (phishing / spoofed UI / wrong network).
  • Remote dependencies can be unavailable or compromised (supply chain).
  • Backend data is not inherently trustworthy (it can be misconfigured or attacked). Treat it as untrusted input even if it’s “our” backend.

We mainly defend user funds and user privacy by:

  • validating inputs
  • minimizing signing surface
  • preventing unsafe retries / double actions
  • reducing injection/XSS risk via CSP and safe Angular patterns

2) Security principles for this codebase

  1. Never handle secrets

    • Never request, store, log, or transmit private keys / seed phrases.
    • The app only interacts with wallets through providers and viem clients (see EvmWalletService).
  2. Validate before you act

    • Validate addresses/amounts and config-derived addresses before sending txs or making irreversible backend calls (see validation patterns in SwapPage.startCcxToEvm()).
  3. Minimize signature/transaction requests

    • Only request exactly the permissions and RPC methods needed.
    • Do not add message signing or typed-data signing flows unless required and clearly documented.
  4. Prefer explicit user confirmation

    • Make the user aware of network, recipient, and amounts before triggering wallet actions.
  5. No dangerous DOM patterns

    • Do not introduce raw HTML rendering or bypass sanitization in templates. Keep Angular template binding and default escaping.

3) Input validation (addresses, amounts, config-derived values)

3.1 User-provided addresses

Current patterns:

Rules:

  • Always validate addresses at two layers:
    1. form validation (Angular validators) and
    2. runtime checks before use (see runtime checks in SwapPage.startCcxToEvm() and SwapPage.startEvmToCcx()).
  • Never “auto-correct” CCX addresses. If invalid, fail with a clear message and require user correction.
  • For EVM addresses, prefer strict viem validation via isAddress() prior to:
    • backend init calls
    • contract transfers
    • token watch/add operations

3.2 Amount validation (numeric parsing, bounds, decimals)

Current rules already implemented:

Rules:

  • Keep min/max enforcement aligned to BridgeChainConfig.common.
  • Do not accept NaN, infinity, negative, or zero.
  • When converting to on-chain units, always use config-derived decimals/units (example: parseUnits()).
  • Avoid floating-point arithmetic for on-chain values; only parse floats for UI input, then convert via parseUnits() or parseEther().

3.3 Config-derived values are untrusted input

The frontend receives chain config from the backend via BridgeApiService.getChainConfig(). This config includes:

Rules:

  • Before using config addresses in wallet operations, validate them with viem address checks:
  • If config is missing or invalid, treat it as a page-blocking issue and fail safe (see how config load errors set pageError).

4) Transaction signing & on-chain interactions (EVM)

4.1 Never sign arbitrary data by default

This app’s primary actions are:

Rules:

  • Do not introduce “sign message” authentication or typed-data signing unless explicitly required and reviewed.
  • If you must add signing, scope it tightly and document:
    • exact message format
    • replay protections (nonce, domain, expiry)
    • how the backend verifies it

4.2 Chain safety (network switching)

Before any transaction, ensure the wallet is on the correct chain:

Rules:

4.3 Confirmation and finality

The swap uses confirmation waiting:

Rules:


5) Secrets & storage rules

5.1 Private keys / seed phrases

Absolute rules:

  • Never ask for or accept seed phrases or private keys in UI or logs.
  • Never store secrets in:
    • local storage
    • session storage
    • query params
    • analytics/telemetry payloads

Wallet connection uses providers; any wallet secrets remain inside the wallet.

5.2 Local storage usage must remain non-sensitive

The app stores a single non-sensitive flag:

Rules:

  • Never store wallet addresses, tx hashes, payment IDs, emails, or amounts in storage unless there’s a strong product requirement and it’s reviewed.
  • Treat any persisted user data as potentially exfiltratable.

5.3 Don’t leak sensitive config in logs

Runtime config includes:

Rules:

  • Avoid logging config values in production builds.
  • Never log full error objects that might include request URLs with tokens (if added in the future).

6) Phishing prevention & safe UX

6.1 External links must not enable tab-nabbing

External links in the UI already follow good practice:

  • target="_blank" + rel="noopener" as used in HomePage

Rules:

6.2 Never ask users to “verify wallet” by sharing secrets

Rules:

  • Never show instructions that request:
    • seed phrase
    • private key
    • remote desktop access
  • Wallet support guidance should instead point users to:
    • verifying domain
    • checking wallet prompts
    • checking explorer links for tx hashes

6.3 Display critical transaction details for user verification

In swap flows, the user should always be able to verify:

  • recipient addresses (bridge deposit address, recipient)
  • payment ID
  • transaction hash

Current UI displays:

Rules:

  • Any new flow that triggers a wallet prompt must ensure the user can see what they are signing (network + destination + value).

7) Contract verification requirements (wCCX interactions)

The app interacts with:

Rules:


8) “Slippage protection” in this project (what it means here)

This bridge is not a DEX swap, so classic AMM slippage protection does not directly apply. The analogous protections are:

Rules:

  • Never silently adjust user-entered amounts.
  • Never proceed when liquidity checks indicate insufficient bridge funds.

9) Web security headers & CSP (deployment requirement)

This app is a static Angular SPA (bootstrapped via bootstrapApplication()) and must rely on hosting/CDN headers for baseline hardening.

Rules:

  • Keep CSP tight and iterate using report-only rollout
  • Minimize external asset hosts:

10) AI agent checklist before merging security-sensitive changes

Before finalizing any change that touches wallet, transactions, config, or external connectivity, verify:


Related docs/specs in this repo

There aren’t any published security advisories