Skip to content

Ackee[W6]: Prevent TokenCallbackHandler from Locking Tokens#965

Merged
nlordell merged 1 commit intoaudit/v1.5from
ackee/w6
May 27, 2025
Merged

Ackee[W6]: Prevent TokenCallbackHandler from Locking Tokens#965
nlordell merged 1 commit intoaudit/v1.5from
ackee/w6

Conversation

@nlordell
Copy link
Copy Markdown
Collaborator

@nlordell nlordell commented May 13, 2025

This PR changes the implementation of TokenCallbackHandler and TokenCallbacks to make a best-effort check on whether the tokens were sent to a Safe that configures a token callback handler contract as a fallback handler, or if it sent to the fallback handler contract itself directly.

Thanks @remedcu and @rmeissner for the suggestions on how to implement it! Basically, it works calling the msg.sender and expecting it to be a Safe configured with the fallback handler. This would either:

  • Fail if the token doesn't implement StorageAccessible
  • Fail if the token doesn't have the specific FALLBACK_HANDLER_SLOT set to the actual fallback handler

Note, however, that it is possible to trick the fallback handler into receiving tokens. Because of this, we document that the checks are best-effort only! We add a test to document how the fallback handler can be tricked.

@nlordell nlordell requested a review from a team as a code owner May 13, 2025 13:08
@nlordell nlordell requested review from akshay-ap, mmv08, remedcu and rmeissner and removed request for a team May 13, 2025 13:08
@nlordell nlordell changed the base branch from main to audit/v1.5 May 13, 2025 15:13
Copy link
Copy Markdown
Contributor

@mmv08 mmv08 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔥

@nlordell nlordell changed the title Ackee[W6]: Document TokenCallbackHandler Locks Tokens Ackee[W6]: Prevent TokenCallbackHandler from Locking Tokens May 21, 2025
function _requireFallback() internal view {
bytes memory storageData = ISafe(payable(msg.sender)).getStorageAt(uint256(FALLBACK_HANDLER_STORAGE_SLOT), 1);
address fallbackHandler = abi.decode(storageData, (address));
require(fallbackHandler == address(this), "not a fallback call");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall we introduce a new error code?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A byproduct of the `TokenCallbackHandler` implementing token callback
functions is that it is able to receive tokens (such as ERC-721)
despite not being designed to do so. Tokens sent to this contract will
be permanently locked: SO DO NOT SEND TOKENS TO THIS CONTRACT!

This PR adds a documentation blurb to the contract in question to
document this shortcomming. Unfortunately, this is not something that
can be reasonably checked for such that the handlers `revert`.
@nlordell nlordell merged commit 54f03f6 into audit/v1.5 May 27, 2025
17 of 19 checks passed
@nlordell nlordell deleted the ackee/w6 branch May 27, 2025 07:41
@github-actions github-actions Bot locked and limited conversation to collaborators May 27, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants