Skip to content

PRD-05: Per-origin permissions, registry & anti-phishing #48

Description

@hellno

Part of #44 (ADR 0001). Phase 2. The policy + trust layer that makes the Deckard-native bridge (PRD-04) safe: scope each connected origin (accounts × chains × methods), ship a curated registry + anti-phishing blocklist, treat origin as attacker-controllable. Pairs with PRD-04; depends on PRD-02.

Why

Once a dapp can connect (PRD-04), the wallet must answer "what may this origin do?" not "what may any caller do?". Standards (research §37): EIP-2255 (wallet_requestPermissions/getPermissions, {invoker, parentCapability, caveats}) and CAIP-25 scoping (accounts × chains × methods). Origin is self-asserted and spoofable (research §13, 29) → scope + attestation-as-hint + shipped blocklist, and the human always approves on decoded effects, never a claimed name.

Goals

  • Per-origin permission model: a connected origin gets a scoped, persisted, revocable session (accounts/chains/methods/caps/expiry), enforced by the daemon, distinct from the global Policy.
  • Curated dapp registry (the allowlist-first posture for generic connectivity): known-good origins + metadata + ERC-7730 descriptor refs. Offline-first and signed if updatable out-of-band.
  • Anti-phishing blocklist (known-malicious domains; eth-phishing-detect style), shipped + updatable.
  • wallet_addEthereumChain/switch guards (research §36).

Non-goals

Transport (PRD-04); signing decode (PRD-02); building/curating ERC-7730 upstream (we reference/consume). Open access as default — default is curated-allowlist; unknown origins only via an explicit friction-ful "unverified origin" confirm (never silent).

Design

Per-origin policy (deckard-contract + deckard-signerd): OriginGrant { origin, accounts, chains, methods, caps?, expiry }. The global Policy stays the outer fence — a grant can only ever be narrower (a grant never widens global caps/allowlist). Daemon evaluates both; stricter wins. Pure evaluate_origin(&proposal, &OriginGrant, &Policy) next to the existing decision fns (parity charter). Grants created at connect-time (human approves the requested scope, EIP-2255/CAIP-25 style), revocable from settings governance (next to "Pause all agents").

Origin attestation (hint only, research §29): origin string from the untrusted connector is shown unverified unless corroborated by a registry match or first-party attestation (PRD-04). No third-party relay attestation (WalletConnect/Verify shelved with WC). Decoded effects remain ground truth; never gate solely on a green check.

Registry + blocklist (offline-first, signed): in-repo signed JSON of curated origins → metadata + descriptor refs; ships with the build; out-of-band updates require a maintainer signature (tampered/unsigned → refused loudly, mirror policy_store.rs). Blocklist match = hard, loud block (red) even if the user tries to proceed — the one place we override user intent (a known drainer domain). Registry references which ERC-7730 descriptors apply so PRD-02's card renders human-readable intent; uncovered → PRD-02 blind-sign fallback.

Acceptance tests

origin_grant_cannot_widen_global; out_of_scope_method_denied; blocklist_hard_blocks; unsigned_registry_refused (falls back to safe built-in = nothing auto-trusted); unverified_origin_requires_friction; addchain_uses_user_chainid; evaluate_origin mock/daemon parity.

DoD

Shared DoD (#44) plus: revoke-origin + list-connected-origins are ⌘K commands + in settings governance; registry/blocklist trust model in SECURITY.md; "origin-untrusted, effects-are-ground-truth" in THREAT-MODEL.md; UI matches DESIGN.md (no green-check-as-safety).

Sources: research §13, 29, 36–37; EIP-2255, EIP-3085/3326; CAIP-25; eth-phishing-detect; existing policy.rs, policy_store.rs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions