Skip to content

Account methods expose cross-product data without JIT permission gating #134

Description

@filvecchiato

Summary

host_account_get, host_account_get_alias, and host_account_create_proof accept a caller-supplied ProductAccountId (a (DotNsIdentifier, DerivationIndex) tuple) but are not behind any JIT permission check. A malicious product can invoke these methods with another product's DotNsIdentifier to obtain account public keys, contextual aliases, and ring VRF proofs that belong to a different product's domain — without user awareness or consent.

Affected Methods

Method Input Returns Risk
host_account_get(ProductAccountId) (DotNsIdentifier, DerivationIndex) Account { publicKey, name } Leaks the user's derived public key for an arbitrary product domain
host_account_get_alias(ProductAccountId) (DotNsIdentifier, DerivationIndex) ContextualAlias { context, alias } Leaks the user's ring VRF alias scoped to an arbitrary product domain
host_account_create_proof(ProductAccountId, RingLocation, message) (DotNsIdentifier, DerivationIndex) + ring + message RingVrfProof Generates a valid proof on behalf of the user under an arbitrary product domain

Current Implementation

In host-container, all three are created as plain makeNotImplementedSlot entries with no permission gating:

// packages/host-container/src/createContainer.ts:230-248
const handleAccountGetSlot = makeNotImplementedSlot(
  'host_account_get',
  () => new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED }),
);

const handleAccountGetAliasSlot = makeNotImplementedSlot(
  'host_account_get_alias',
  () => new RequestCredentialsErr.Unknown({ reason: NOT_IMPLEMENTED }),
);

const handleAccountCreateProofSlot = makeNotImplementedSlot(
  'host_account_create_proof',
  () => new CreateProofErr.Unknown({ reason: NOT_IMPLEMENTED }),
);

Compare with remote_statement_store_submit and remote_preimage_submit, which use makePermissionGatedRequestSlot to enforce RemotePermission checks before the handler is called.

Attack Scenario

  1. Product A (e.g. "malicious.dot") is loaded in the host.
  2. Product A calls host_account_get(["legitimate-product.dot", 0]) — using product B's domain.
  3. The host returns the user's derived public key for product B's domain without prompting the user.
  4. Product A now knows the user's public key in product B's context, enabling cross-product tracking/correlation.
  5. Similarly, host_account_get_alias leaks the user's contextual alias, and host_account_create_proof allows generating proofs under another product's identity.

Suggested Mitigation

Options to consider (not mutually exclusive):

  1. Domain scoping at the container level: The host container should enforce that DotNsIdentifier in the request matches the calling product's registered identity. Requests for other domains should be rejected.
  2. JIT permission prompt: If cross-domain access is a legitimate use case, gate these methods behind a JIT user approval prompt (similar to signing methods returning PermissionDenied/Rejected on denial).
  3. Spec update: The protocol spec (docs/design/host-api-protocol.md) should document the expected host behavior — whether the host MUST restrict ProductAccountId to the calling product's own domain or MUST prompt for cross-domain access.

References

  • Protocol spec: docs/design/host-api-protocol.md (Accounts section, line ~630)
  • Container implementation: packages/host-container/src/createContainer.ts (lines 230-248, 471-485)
  • Codec definitions: packages/host-api/src/protocol/v1/accounts.ts

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingteam: sdkOrigin: SDK

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions