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
- Product A (e.g.
"malicious.dot") is loaded in the host.
- Product A calls
host_account_get(["legitimate-product.dot", 0]) — using product B's domain.
- The host returns the user's derived public key for product B's domain without prompting the user.
- Product A now knows the user's public key in product B's context, enabling cross-product tracking/correlation.
- 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):
- 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.
- 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).
- 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
Summary
host_account_get,host_account_get_alias, andhost_account_create_proofaccept a caller-suppliedProductAccountId(a(DotNsIdentifier, DerivationIndex)tuple) but are not behind any JIT permission check. A malicious product can invoke these methods with another product'sDotNsIdentifierto 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
host_account_get(ProductAccountId)(DotNsIdentifier, DerivationIndex)Account { publicKey, name }host_account_get_alias(ProductAccountId)(DotNsIdentifier, DerivationIndex)ContextualAlias { context, alias }host_account_create_proof(ProductAccountId, RingLocation, message)(DotNsIdentifier, DerivationIndex)+ ring + messageRingVrfProofCurrent Implementation
In
host-container, all three are created as plainmakeNotImplementedSlotentries with no permission gating:Compare with
remote_statement_store_submitandremote_preimage_submit, which usemakePermissionGatedRequestSlotto enforceRemotePermissionchecks before the handler is called.Attack Scenario
"malicious.dot") is loaded in the host.host_account_get(["legitimate-product.dot", 0])— using product B's domain.host_account_get_aliasleaks the user's contextual alias, andhost_account_create_proofallows generating proofs under another product's identity.Suggested Mitigation
Options to consider (not mutually exclusive):
DotNsIdentifierin the request matches the calling product's registered identity. Requests for other domains should be rejected.PermissionDenied/Rejectedon denial).docs/design/host-api-protocol.md) should document the expected host behavior — whether the host MUST restrictProductAccountIdto the calling product's own domain or MUST prompt for cross-domain access.References
docs/design/host-api-protocol.md(Accounts section, line ~630)packages/host-container/src/createContainer.ts(lines 230-248, 471-485)packages/host-api/src/protocol/v1/accounts.ts