Skip to content

Epic — Establish a lifecycle-safe, origin-bound signing review protocol #124

Description

@knytcomics-ui

Outcome

Replace the best-effort page-message/runtime-callback flow with a one-shot protocol binding every decision to the exact transaction, tab, frame, document, wallet adapter, and review window. Requests must survive MV3 worker suspension, reject replay or cross-window decisions, and settle within a defined deadline.

Audit evidence and problem

  • src/intercept/mainWorldEntry.ts generates a page-visible ID, posts XDR through window.postMessage(..., '*'), and has no page-side timeout.
  • src/intercept/bridgeEntry.ts trusts and forwards that page-provided ID; it does not generate the authoritative ID claimed by README.
  • src/background/background.ts keeps resolver functions only in an in-memory Map; DEFAULT_TIMEOUT_MS is unused.
  • Popup creation results are not retained. There is no chrome.windows.onRemoved handler, so closing a popup can hang the dApp request.
  • DECISION_MADE resolves solely by request ID and ignores sender tab/frame/window. Duplicate IDs overwrite map entries.
  • Transaction data and decision identity are placed in popup query parameters and treated as authoritative by src/popup/App.tsx.
  • docs/threat-model.md records forgery, MV3 state loss, stale popup, request flooding, and missing sender binding as open threats.

Non-negotiable invariants

  • A decision is bound to one transaction digest, tab, frame, document, adapter, and review window.
  • Page-controlled identifiers are never authoritative capabilities.
  • The first valid terminal transition wins; replay is a no-op.
  • Unrelated or stale senders cannot resolve a request.
  • Worker restart cannot release a cancelled request or lose a completed decision.
  • Popup close, creation failure, bridge loss, and timeout settle deterministically.
  • The released XDR is byte-for-byte identical to the reviewed XDR.
  • Pending state, windows, timers, and tombstones are bounded and pruned.

Required scope

A. Versioned protocol

Define runtime-validated, versioned messages. Separate page correlation IDs from extension-generated request IDs and bind immutable transaction digests, network, adapter, tab/frame/document identity, timestamps, and state.

B. Durable state machine

Implement received → validating → assessing → awaiting_review → proceed | cancel | expired | failed. Persist recoverable metadata before opening UI and add a bridge resume/status handshake because callback functions cannot survive suspension.

C. Trusted review capability

Pass only an opaque capability in the review URL. Load display state from the worker, retain windowId, validate sender context, and reject copied, expired, mismatched, or consumed capabilities.

D. Failure and concurrency semantics

Install deadlines at page, bridge, assessment, and review layers. Handle popup/tab closure, navigation, worker restart, extension update, storage failure, duplicate messages, and popup creation failure. Add per-frame and global admission limits.

E. Compatibility

Define safe behavior for stale content scripts after extension updates and browsers lacking documentId. Compatibility fallbacks must be explicit and testable.

Deliverables

  • Protocol/state-machine ADR and threat-model update.
  • Runtime message schemas and transaction digest binding.
  • Durable pending repository, replay tombstones, and resume handshake.
  • Sender/window-bound popup state API.
  • Timeout, close, restart, update, and admission-control handlers.
  • Developer inspection/cleanup tooling and adversarial browser tests.

Acceptance criteria

  • A page observing all window messages cannot forge a proceed decision.
  • Decisions from the dApp tab, options page, unrelated tab, or wrong popup are rejected.
  • Copying a review URL reveals no transaction and grants no authority.
  • Fifty concurrent requests using one page ID cause no overwritten state.
  • Replaying a valid proceed 100 times releases the wallet request once.
  • Closing the popup settles as cancellation within two seconds.
  • Popup creation failure settles and clears all state.
  • Worker termination during review preserves context and permits one terminal decision.
  • Worker termination after proceed cannot cause a second release.
  • Originating-tab navigation or closure invalidates the request.
  • A missing bridge/background cannot hang beyond the absolute deadline.
  • Changing one XDR byte after review causes digest rejection.
  • Incompatible old content scripts receive a typed failure, not silent bypass.
  • Flooding 1,000 requests respects per-frame/global bounds and does not open 1,000 windows.

Required verification

Unit and property-based state-machine tests; actual Chrome sender integration tests; multi-tab/frame Playwright tests; forced worker termination; popup/navigation/update failure injection; adversarial same-page messaging; load tests; security review. A mocked happy-path resolver test is insufficient.

Out of scope

Oracle accuracy, expanded Stellar semantics, new wallets, and protection against a compromised browser/wallet.

Dependencies and sequencing

Foundational; land before the oracle, semantic review, protection-status, and retained-record contracts stabilize.

Complexity

Extreme

Impact

Critical — forged, lost, mismatched, or hanging decisions compromise a financial signing workflow.

Suggested labels

epic architecture security reliability browser-extension state-machine production

Activity

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

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third Campaignarchitecturebrowser-extensionBrowser extension runtime and platform behaviorepicLarge architecture-level engineering outcomeproductionProduction readiness and operational controlsreliabilityAvailability, recovery, and failure semanticssecuritystate-machineExplicit lifecycle and state transition design

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions