fix(policy): don't expose signer or key material through enforced handles#75
Open
AlonzoRicardo wants to merge 1 commit into
Open
fix(policy): don't expose signer or key material through enforced handles#75AlonzoRicardo wants to merge 1 commit into
AlonzoRicardo wants to merge 1 commit into
Conversation
…dles The policy-enforced account and protocol proxies substituted only the named write methods; every other property access fell through to the raw account. That left `keyPair` (the private key), `_signer`, `_provider`, and a protocol's `_account` back-reference reachable through the guarded handle, so a caller holding an enforced account could sign outside policy evaluation (e.g. `account.keyPair.privateKey`, `account._signer.signTransaction(...)`, `account.getSwapProtocol(x)._account.sendTransaction(...)`). Both get-traps now hide key material (`keyPair`) and internal references (underscore-prefixed by WDK convention) via a shared `isProtectedMember` check. Enforced methods, protocol getters, `simulate`, `registerProtocol`, reads, and identity accessors (`path`/`index`) are unchanged; the prototype-climb variant is neutralized because every signing path funnels through the now-hidden `_signer`. Adds regression coverage for the account and protocol proxies.
AlonzoRicardo
force-pushed
the
fix/policy-proxy-internal-reference-exposure
branch
from
July 8, 2026 15:47
e11471a to
0329f6e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The policy engine's enforced account (
wdk.getAccount()) and its protocol proxies only substituted the named members (theOPERATIONSwrite methods, protocol verbs,simulate,registerProtocol). Every other property read fell through to the raw account viaReflect.get, so the guarded handle still surfaced:keyPair→ the private key_signer→ the raw signer (account._signer.signTransaction(...))_provider/_config_accountback-reference (account.getSwapProtocol(x)._account.sendTransaction(...))Any of these lets a caller holding an "enforced" account sign or move funds without policy evaluation, defeating the guardrail the proxy exists to provide.
Fix
Both
gettraps now hide key material and internal references through one shared rule:keyPairis blocked by name — it's the one public getter that returns key material._signer,_provider,_config, the ERC-4337_ownerAccount, and a protocol's_accountacross every chain, rather than a per-name denylist that would miss chain-specific fields.Object.getPrototypeOf(account).sendTransaction.call(account, …)) is neutralized by the same rule: every signing path funnels throughthis._signer, nowundefined.Unchanged: enforced write methods, protocol getters,
simulate,registerProtocol, all reads (getBalance, quotes,verify, …), and identity accessors (path,index).instanceofstill holds (nogetPrototypeOftrap). Ungoverned accounts (no policy registered) are untouched.The wallet classes' public API is deliberately not changed — the boundary is enforced only at the proxy, so direct (non-governed) users keep
keyPair/_signer(no#private fields introduced).Scope / trust boundary
This contains a caller holding an enforced account. It is not a defense against code that also holds the
WalletManager/WDKinstance or constructs an account directly — that remains the existing, documented trust boundary.Tests
New
internal-reference containmentblock covering:keyPairhidden,_signer/_provider/_confighidden, reads + enforced ops still work, and the protocol_accountreach-through blocked while protocol enforcement still holds. Full suite 135 passing,standardclean.