57203 sc medium revised malicious accesstoken creator can steal gas via mintstaticprice or mintdynamicprice
Submitted on: Oct 24th 2025 at 11:12:18 UTC by @blackgrease for Audit Comp | Belong
Report ID: #57203
Report Type: Smart Contract
Report severity: Medium
Target: https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/tokens/AccessToken.sol
Impacts: Theft of gas; Griefing (no profit motive required)
Description
TO IMMUNEFI TRIAGERS
This section responds to a comment in report #57040 to clarify some points. The rest of the report remains unchanged.
1. Victim interaction and facilitator contract
The only contract the victim interacts with is the deployed AccessToken. The exploit leverages the AccessToken logic — the AccessToken contract is the facilitator of the attack. During normal execution the victim is not aware that an external call will be made to a malicious contract (external calls are made to the platform, referrer and creator).
2. Signed message does not include intended owner
To deploy an instance of AccessToken, the Signer address signs a message consisting of NFT name, symbol, contractURI, feeNumerator. This message does not include the intended owner/deployer of AccessToken. Upon deployment the deployer becomes the owner. Consequently:
A user can provide NFT data to be signed and then call deploy using a different address.
For comparison,
Factory::deployVestingWalletincludes the intended owner in the signed message (function deployVestingWallet(address _owner, VestingWalletInfo calldata vestingWalletInfo, bytes calldata signature)). That pattern prevents this class of problem for vesting wallets, but it is not applied toAccessToken.During
AccessToken::initializethe owner is set as_initializeOwner(_params.creator)which is not controlled by the user submitting the signed data.
For a visualization of the exploit flow, the reporter attached "AccessToken-TheftOfGasExploitFlow.png".
Therefore, because the user has no control over the interaction with the creator address and because the AccessToken purpose can be abused to harm users, the issue is considered valid.
Report: Description
The AccessToken allows users to pay for NFT mints using ETH through mintStaticPrice or mintDynamicPrice. When mints are made using ETH, these functions call an internal _pay function which sends payments to:
the platform,
the referrer, and
the creator
using the low-level SafeTransferLib::safeTransferETH. The low-level call forwards all available gas to recipients. A malicious creator (or a malicious referrer, if applicable) can use this to steal gas from users when they pay using ETH, by executing arbitrary code in their fallback/receive while receiving the payment. The caller pays for the extra gas.
Important things to note:
Factory::producedoes not verify the caller. Once the Signer provides a valid signature forNFT name, symbol, contractURI, feeNumerator,producecan be called by any address.SafeTransferLib.solcontains a more gas-restrictive functionforceSafeTransferETHwhich uses a gas stipend, but it was not used.If the referrer is not protocol-controlled, the same attack can extend to payments made to the referrer address if the AccessToken was created using a referral code.
The associated Code for _pay called by mintStaticPrice() and mintDynamicPrice()
_pay called by mintStaticPrice() and mintDynamicPrice()The SafeTransferLib::safeTransferETH logic
SafeTransferLib::safeTransferETH logicImpact
A malicious creator (or referrer) can abuse the payment logic to steal gas by executing additional arbitrary logic in their fallback/receive when receiving ETH. The unsuspecting buyer pays for the extra gas, leading to:
Theft of gas (attacker causes buyer to spend more gas than necessary).
Griefing (attacker causes damage without direct monetary profit).
Mitigation
Replace safeTransferETH calls with the more restrictive forceSafeTransferETH from the same SafeTransferLib.sol, which uses a gas stipend to limit forwarded gas and mitigate this class of gas-stealing attacks.
No additional functionality or protocol-level assumptions are suggested beyond using a gas-stipend-limited transfer to protocol-controlled addresses (and ensuring referral/creator addresses are validated or protocol-controlled where appropriate).
Proof of Concept
A runnable Foundry PoC and a stack trace are available in the private gist:
https://gist.github.com/blackgrease/840497c0aa53d6a459e03c5708b1108e
The gist contains:
a runnable Foundry PoC
PoC-StackTrace_TheftOfGasFromMaliciousCreator.txt
PoC Steps — Setup and exploit flow
Deploy an
AccessTokenviaFactory::producefrom a contract that implements a maliciousreceive.A buyer pays the required price and mints the NFT.
When the payment is made to the creator, the malicious
receiveis triggered and executes arbitrary logic, stealing gas.Console logs show starting and remaining gas and the amount of gas consumed via the malicious interaction.
(Note: referral-based attack is described in the report and can be applied analogously to any non-protocol-controlled referrer.)
If you need the PoC reproduced inline or want extracted test cases / specific locations in the repository mapped to suggested fixes, I can prepare a patch-style suggestion applying forceSafeTransferETH where appropriate and highlighting where referral/creator addresses should be protocol-controlled or validated.
Was this helpful?