MetaMask / MetaMask/core

fix: validateDelegation should allow redelegation signing (non-root authority)

Open
#7,917 0 comments 0 reactions 0 assignees View on GitHub

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

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.