Project

One World
NFTDeFi
15,000 USDC
View results
Submission Details
Severity: medium
Invalid

Meta-Transaction Context Loss in _msgSender() Allows Privilege Escalation and Unauthorized Minting

Summary

There is loss of meta-transaction context in the _msgSender() implementation creating a security vulnerability that compromises the contract's ability to properly authenticate users executing transactions through meta-transactions. When transactions are executed via executeMetaTransaction(), the contract fails to correctly identify the original signer, instead defaulting to the direct msg.sender. This breaks the core functionality of gasless transactions and could lead to privilege escalation where unauthorized addresses gain access to restricted functions. In the context of this OWP Identity contract, this means functions protected by MINTER_ROLE could be accessed by addresses that don't actually possess the role, potentially allowing unauthorized minting or burning of tokens.

The issue stems from an incomplete implementation of the meta-transaction context recovery in the _msgSender() function. The current implementation only performs a basic check for whether the caller is the contract itself (msg.sender == address(this)) but fails to properly integrate with the meta-transaction execution flow. When executeMetaTransaction() is called, it appends the original signer's address to the calldata, but the current _msgSender() implementation's assembly code block doesn't correctly extract this appended address. This creates a disconnect between the meta-transaction execution layer and the sender verification layer, effectively breaking the security model of the gasless transaction system.

The meta-transaction context loss in _msgSender() represents a critical vulnerability that could lead to privilege escalation and unauthorized access to privileged functions. In a practical scenario, this vulnerability could be exploited as follows:

An attacker could:

  1. Create a meta-transaction to call the mint() function

  2. Sign this transaction with any address

  3. Execute it through executeMetaTransaction()

  4. Due to the faulty _msgSender() implementation, the contract would incorrectly validate the MINTER_ROLE

  5. Successfully mint tokens without actually having the MINTER_ROLE permission

Consider this attack scenario:

// Attacker prepares meta-transaction
bytes memory mintData = abi.encodeWithSignature(
"mint(address,uint256,uint256,bytes)",
attackerAddress,
tokenId,
amount,
"0x"
);
// Attacker signs the meta-transaction with any address
(bytes32 sigR, bytes32 sigS, uint8 sigV) = signMetaTransaction(mintData);
// Attacker executes the meta-transaction
contract.executeMetaTransaction(
attackerAddress,
mintData,
sigR,
sigS,
sigV
);
// The _msgSender() fails to properly validate the actual signer
// Transaction succeeds despite attacker not having MINTER_ROLE

The broken _msgSender() implementation means that when checking onlyRole(MINTER_ROLE), the Access Control system receives an incorrect sender address, effectively bypassing the role check completely. This allows unauthorized minting of tokens, which could have severe economic implications for the protocol.

Vulnerable code

https://github.com/Cyfrin/2024-11-one-world/blob/main/contracts/OWPIdentity.sol#L82

function _msgSender()
internal
view
override
returns (address sender)
{
if (msg.sender == address(this)) {
bytes memory array = msg.data;
uint256 index = msg.data.length;
assembly {
sender := and(
mload(add(array, index)),
0xffffffffffffffffffffffffffffffffffffffff
)
}
} else {
sender = msg.sender; // <- Critical: Returns raw msg.sender instead of meta-tx signer
}
return sender;
}

Recommended Fix

function _msgSender()
internal
view
virtual
override(ERC1155, NativeMetaTransaction)
returns (address sender)
{
if (msg.sender == address(this)) {
bytes memory array = msg.data;
uint256 index = msg.data.length;
assembly {
sender := and(
mload(add(array, index)),
0xffffffffffffffffffffffffffffffffffffffff
)
}
return sender;
}
return super._msgSender(); // Properly maintain the inheritance chain
}

The fix explicitly overrides both parent contracts (ERC1155 and NativeMetaTransaction) and ensures proper handling of the meta-transaction context. The key changes include:

  1. Adding the 'virtual' keyword to allow further overrides if needed

  2. Explicitly specifying the override for both parent contracts

  3. Using super._msgSender() instead of msg.sender in the else clause to maintain the proper inheritance chain

  4. Returning the sender immediately after the assembly block to prevent any potential manipulation

The fix ensures proper meta-transaction context preservation and role validation. After implementing the fix, the previous attack scenario would fail as the contract would correctly identify the transaction signer and validate their MINTER_ROLE status.

Updates

Lead Judging Commences

0xbrivan2 Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.