Skip to content

ERC1155 Unsafe BatchTransfer

id: LS35M
title: ERC1155 Unsafe BatchTransfer 
baseSeverity: M
category: token-transfer
language: solidity
blockchain: [ethereum]
impact: Loss of tokens, skipped hooks, or denial of service
status: draft
complexity: medium
attack_vector: external
mitigation_difficulty: medium
versions: [">=0.5.0", "<=0.8.25"]
cwe: CWE-703
swc: SWC-135

πŸ“ Description

  • ERC-1155 defines safeBatchTransferFrom() as the standardized method to transfer multiple token IDs and amounts atomically. When projects implement non-standard batch transfer functions, or skip the required onERC1155BatchReceived() hook, it creates serious risks:
  • Tokens are lost when transferred to contracts that expect proper hook invocation.
  • Receiver logic is skipped, breaking accounting or trustless asset reception.
  • Malicious contracts can front-run transfers or trap tokens by rejecting callbacks.
  • Most issues arise from:
  • Implementing a raw batchTransfer() function without safe mechanics
  • Using transferFrom() patterns from ERC20/ERC721 without 1155 compliance
  • Assuming msg.sender is always from, violating proxy or operator logic

🚨 Vulnerable Code

pragma solidity ^0.8.0;

contract UnsafeBatch1155 {
    mapping(address => mapping(uint256 => uint256)) public balances;

    function batchTransfer(address to, uint256[] calldata ids, uint256[] calldata amounts) external {
        require(ids.length == amounts.length, "Length mismatch");

        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids[i];
            uint256 amt = amounts[i];

            balances[msg.sender][id] -= amt;
            balances[to][id] += amt;
        }

        // ❌ Missing call to onERC1155BatchReceived
    }
}

πŸ§ͺ Exploit Scenario

  1. Alice calls batchTransfer() to send tokens to a contract that expects ERC1155 compliance.
  2. Because onERC1155BatchReceived() is never called, the receiving contract:
  3. Fails to register the tokens
  4. May revert when attempting to use them
  5. Alternatively, an attacker uses batchTransfer() to bypass a receiver’s accept logic, depositing tokens the receiver never intended to receive.

Assumptions:

  • Transfer is made to a contract address.
  • No hook is triggered, leading to broken logic or token loss.

βœ… Fixed Code

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";

contract SafeBatch1155 is ERC1155 {
    constructor() ERC1155("https://api.example.com/meta/{id}.json") {}

    function safeBatchTransfer(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) external {
        safeBatchTransferFrom(msg.sender, to, ids, amounts, data); // βœ… standard and safe
    }
}

🧭 Contextual Severity

- context: "Batch transfer to arbitrary user-provided addresses"
  severity: M
  reasoning: "Tokens may be silently lost if recipient is not compatible"
- context: "Batch transfer only to known EOAs or whitelisted system contracts"
  severity: L
  reasoning: "Controlled environment reduces risk of token lock-up"
- context: "Transfer handled via audited, standards-compliant `safeBatchTransferFrom`"
  severity: I
  reasoning: "Conforms to ERC1155 with enforced safety"

πŸ›‘οΈ Prevention

Primary Defenses

  • Never create custom batch transfer logic without calling onERC1155BatchReceived.
  • Use OpenZeppelin’s ERC1155 or a compliant audited base contract.

Additional Safeguards

  • Use Address.isContract(to) to guard transfers to contracts.
  • Always match ids.length == amounts.length and validate amount > 0.

Detection Methods

  • Review for non-standard batchTransfer() functions.
  • Check that onERC1155BatchReceived() is called on external to addresses.
  • Tools: Slither (erc1155-compliance), MythX, ConsenSys Diligence linter

πŸ•°οΈ Historical Exploits

  • Name: Revest Finance FNFT Reentrancy Exploit
  • Date: 2022-03-27
  • Loss: ~$2
  • Post-mortem: Link to post-mortem

πŸ“š Further Reading


βœ… Vulnerability Report

id: LS35M
title: ERC1155 Unsafe BatchTransfer 
severity: M
score:
impact: 4       
exploitability: 3 
reachability: 4   
complexity: 2  
detectability: 4  
finalScore: 3.55

πŸ“„ Justifications & Analysis

  • Impact: Tokens may be irretrievably lost or misused.
  • Exploitability: Any user can send tokens to break recipient logic.
  • Reachability: Frequent in custom NFT contracts or bridging code.
  • Complexity: Not difficult to understand, but easy to miss.
  • Detectability: Highly detectable via review or standard detectors.