makeDefaultExo builds its interface guard as M.interface(name, {}, { defaultGuards: 'passable' }) (packages/kernel-utils/src/exo.ts:13-14). That admits any method name with any passable arguments — the membrane enforces nothing unless the caller passes an explicit M.interface.
Current state: there are 62 makeDefaultExo( call sites across packages/*/src, and outside test fixtures only three pass an explicit interface guard (evm-wallet-experiment/src/vats/home-coordinator.ts:1163, lib/delegation-twin.ts:47 and :109).
Given that #959 and #960 deliberately made the exo membrane the sole capability argument enforcer, a default that enforces nothing is the wrong way round. Anything reachable across a vat or kernel boundary should be narrow by construction, not by remembering.
Proposed:
- Add
makeGuardedExo (or equivalent) that requires an explicit interface guard.
- Add a lint rule flagging
makeDefaultExo used without a guard, at least for exos that are exported across a boundary.
- Migrate existing call sites incrementally, prioritising anything reachable remotely.
- Document the guidance: prefer removing a parameter over validating it. An exo that closes over an identity and takes no argument for it cannot be asked about anything else, which is stronger than a guard that checks the argument.
Note S.interface in described.ts:281-283 also sets defaultGuards: 'passable', deliberately, to admit the injected __getDescription__ method — that case needs preserving.
makeDefaultExobuilds its interface guard asM.interface(name, {}, { defaultGuards: 'passable' })(packages/kernel-utils/src/exo.ts:13-14). That admits any method name with any passable arguments — the membrane enforces nothing unless the caller passes an explicitM.interface.Current state: there are 62
makeDefaultExo(call sites acrosspackages/*/src, and outside test fixtures only three pass an explicit interface guard (evm-wallet-experiment/src/vats/home-coordinator.ts:1163,lib/delegation-twin.ts:47and:109).Given that #959 and #960 deliberately made the exo membrane the sole capability argument enforcer, a default that enforces nothing is the wrong way round. Anything reachable across a vat or kernel boundary should be narrow by construction, not by remembering.
Proposed:
makeGuardedExo(or equivalent) that requires an explicit interface guard.makeDefaultExoused without a guard, at least for exos that are exported across a boundary.Note
S.interfaceindescribed.ts:281-283also setsdefaultGuards: 'passable', deliberately, to admit the injected__getDescription__method — that case needs preserving.