fix: validateDelegation should allow redelegation signing (non-root authority)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 413
- Forks
- 308
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 253
Description
## Description
The `validateDelegation` function in `packages/signature-controller/src/utils/validation.ts` currently blocks **all** delegation signing requests from external origins when the delegator is an internal account. This is overly restrictive — it should only block signing when the delegation's `authority` field equals the `ROOT_AUTHORITY`, meaning the EOA is the root delegator.
## Current Behavior
When an external dapp requests a delegation signature where the `delegator` is an internal account, `validateDelegation` unconditionally throws:
```
External signature requests cannot sign delegations for internal accounts.
```
This happens regardless of the `authority` field value in the delegation message.
**Relevant code** (`validation.ts`, lines ~230-255):
```typescript
function validateDelegation({ data, internalAccounts, origin, decodedPermission }) {
if (!isDelegationRequest(data)) return;
const hasDecodedPermission = decodedPermission !== undefined;
if (!hasDecodedPermission) {
const isOriginExternal = origin && origin !== ORIGIN_METAMASK;
const delegatorAddressLowercase = (data.message?.delegator)?.toLowerCase();
const isSignerInternal = internalAccounts.some(
(internalAccount) => internalAccount.toLowerCase() === delegatorAddressLowercase,
);
if (isOriginExternal && isSignerInternal) {
throw new Error(
`External signature requests cannot sign delegations for internal accounts.`,
);
}
}
}
```
## Why This Is Wrong
In the [ERC-7710 delegation framework](https://docs.delegations.org/), there are two types of delegation signing:
1. **Root delegation** — The EOA creates a new delegation where it is the root delegator. The `authority` field is set to `ROOT_AUTHORITY` (`0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`). This grants access to the EOA's own funds and should indeed be restricted.
2. **Redelegation** — The EOA has been *granted* a delegation and wants to redelegate some or all of those permissions to another party. The `authority` field is set to the hash of the parent delegation (not `ROOT_AUTHORITY`). This is safe because:
- The signer is not risking their own funds
- They can only redelegate permissions that were already granted to them
- The root delegator's funds are already at risk via the original delegation
- The redelegation is bounded by the caveats of the parent delegation
Currently, MetaMask blocks both cases, preventing users from redelegating delegations that were granted to them by external dapps.
## Proposed Fix
Add a check for the `authority` field in the delegation message. Only block the signing request when `authority === ROOT_AUTHORITY`:
```typescript
const ROOT_AUTHORITY = '0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff';
const AUTHORITY_FIELD = 'authority';
function validateDelegation({ data, internalAccounts, origin, decodedPermission }) {
if (!isDelegationRequest(data)) return;
const hasDecodedPermission = decodedPermission !== undefined;
if (!hasDecodedPermission) {
const isOriginExternal = origin && origin !== ORIGIN_METAMASK;
const delegatorAddressLowercase = (data.message?.delegator)?.toLowerCase();
const isSignerInternal = internalAccounts.some(
(internalAccount) => internalAccount.toLowerCase() === delegatorAddressLowercase,
);
const authority = (data.message?.authority)?.toLowerCase();
const isRootAuthority = authority === ROOT_AUTHORITY;
if (isOriginExternal && isSignerInternal && isRootAuthority) {
throw new Error(
`External signature requests cannot sign root delegations for internal accounts.`,
);
}
}
}
```
## Security Analysis
| Scenario | Authority | Blocked? | Rationale |
|----------|-----------|----------|-----------|
| Root delegation (EOA creates new delegation) | `0xfff...fff` | ✅ Yes | EOA is granting access to its own funds |
| Redelegation (EOA passes on granted delegation) | `` | ❌ No | EOA is only passing on already-granted permissions; no additional risk to signer's own funds |
Allowing redelegation signing is safe because the redelegation can never exceed the permissions of the parent delegation. The root delegator already accepted the risk when creating the original delegation.
## References
- [ERC-7710 Delegation Framework](https://docs.delegations.org/)
- [MetaMask Delegation Framework](https://github.com/MetaMask/delegation-framework)
- `packages/signature-controller/src/utils/validation.ts`
- `packages/signature-controller/src/utils/delegations.ts`
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in packages/signature-controller/src/utils/validation.ts at validateDelegation and inspect how the delegation message's authority is handled. Verify that external requests for internal accounts remain blocked for ROOT_AUTHORITY while redelegation requests are allowed, then run the relevant signature-controller validation tests if available.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- authorization, security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 56/100