■ Description

Some tokens do not return a bool (e.g. USDTBNBOMG) on ERC20 methods. see here  for a comprehensive (if somewhat outdated) list.

Some tokens (e.g. BNB) may return a bool for some methods, but fail to do so for others. This resulted in stuck BNB tokens in Uniswap v1 (details).

Some particulary pathological tokens (e.g. Tether Gold) declare a bool return, but then return false even when the transfer was successful (code).

■ Example

function transfer(address dst, uint wad) external returns (bool) {
    return transferFrom(msg.sender, dst, wad);
}
// bad_1
function transferFrom(address src, address dst, uint wad) public {
    require(balanceOf[src] >= wad, "insufficient-balance");
    if (src != msg.sender && allowance[src][msg.sender] != type(uint).max) {
        require(allowance[src][msg.sender] >= wad, "insufficient-allowance");
        allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
    }
    balanceOf[src] = sub(balanceOf[src], wad);
    balanceOf[dst] = add(balanceOf[dst], wad);
    emit Transfer(src, dst, wad); 
		// missing return value
}

// bad_2
function transferFrom(address src, address dst, uint wad) public returns (bool) {
  require(balanceOf[src] >= wad, "insufficient-balance");
  if (src != msg.sender && allowance[src][msg.sender] != type(uint).max) {
      require(allowance[src][msg.sender] >= wad, "insufficient-allowance");
      allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
  }
  balanceOf[src] = sub(balanceOf[src], wad);
  balanceOf[dst] = add(balanceOf[dst], wad);
  emit Transfer(src, dst, wad);
  return false; // return false
}

// good
function _safeTransfer(address token, address to, uint value) private {
    (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
    require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
}

■ How to protect against this attack?

Check the return value

require( token.transfer(),"");

■ Resources

https://github.com/d-xo/weird-erc20#missing-return-values

https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-erc20-interface