Attack Vector
The validateDelegation() guard in MetaMask DelegationManager uses a decodedPermission parameter to check caveat compliance. An attacker can supply a crafted decodedPermission that passes structural validation but encodes permissions beyond the delegation's actual caveat set — bypassing the guard entirely.
Kill Chain
1Attacker holds delegation D with restricted caveats
2Constructs decodedPermission with extra perms not in D
3validateDelegation checks structure, not semantic coverage
4Guard passes — attacker executes with elevated permissions
Root Cause · S_delegation (bypass variant)
Guard validation is structural (checks format) but not semantic (checks that claimed permissions ⊆ granted caveats). The decoder/encoder mismatch creates an escape hatch from the permission boundary.
Relation to MM-005
MM-005 = non-inheritance at delegation creation. MM-006 = bypass at delegation validation. Same root cause (S_delegation), different exploit point. File as paired reports with shared root cause.
Shape · S_delegation (bypass variant)
Guard predicate:
validateDelegation(d, decodedPerm) = structValid(decodedPerm)
Should be:
validateDelegation(d, decodedPerm) = structValid(decodedPerm) ∧ semanticSubset(decodedPerm, d.caveats)
The missing semanticSubset check is the vulnerability. Any structurally valid permission passes the guard regardless of actual caveat scope.
γ₁ Stratum · T1 (1s)
T1 — UI consent / session gate. Exploit occurs at execution time when the malicious decodedPermission is submitted. Single-round attack.
Theorem · GuardBypassViaDecodedPermission
-- A guard is sound if it validates semantics, not just structure
def soundGuard (validate : Delegation → Permission → Bool)
(caveatOf : Delegation → Finset Perm) : Prop :=
∀ (d : Delegation) (p : Permission),
validate d p = true →
p.perms ⊆ caveatOf d
-- MetaMask validateDelegation is NOT a sound guard:
theorem mm_validate_delegation_unsound
(vd : Delegation → Permission → Bool)
(h_struct_only : ∀ p, structValid p → vd d p = true)
(h_no_semantic : ∃ p, structValid p ∧ ¬(p.perms ⊆ caveatOf d)) :
¬ soundGuard vd caveatOf := by
intro h_sound
obtain ⟨p, hstruct, hsuper⟩ := h_no_semantic
have := h_sound d p (h_struct_only p hstruct)
exact hsuper this
PoC (code analysis)
1Locate validateDelegation() in DelegationManager.sol
2Trace decodedPermission parameter validation path
3Construct permission with extra perms beyond delegation caveats
4Confirm guard passes despite semantic overflow
Filing Status
READY — FILE WITH MM-005
Programme: MetaMask (hackerone.com/metamask)
CLO signed ✅ · Priority P2
Shared root cause note: S_delegation family
Expected: $5K–$50K (combined with MM-005)