What happens if function transferFrom is called by owner of _tokenId but with different _from parameter than msg.sender? require() is not checking that msg.sender is equal to _from so I can pass any address to _from and mess up ownerZombieCount mapping and emit false Transfer event.

Am I failing to observe something?

pragma solidity >=0.5.0 <0.6.0;

import "./zombieattack.sol";
import "./erc721.sol";

contract ZombieOwnership is ZombieAttack, ERC721 {

  mapping (uint => address) zombieApprovals;

  function balanceOf(address _owner) external view returns (uint256) {
    return ownerZombieCount[_owner];

  function ownerOf(uint256 _tokenId) external view returns (address) {
    return zombieToOwner[_tokenId];

  function _transfer(address _from, address _to, uint256 _tokenId) private {
    zombieToOwner[_tokenId] = _to;
    emit Transfer(_from, _to, _tokenId);

  function transferFrom(address _from, address _to, uint256 _tokenId) external payable {
    require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender);
    _transfer(_from, _to, _tokenId);

  function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId) {
    zombieApprovals[_tokenId] = _approved;
    emit Approval(msg.sender, _approved, _tokenId);

Edit: I just checked ERC721.sol from


and there is require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner"); check so i guess Cryptozombies' implementation is only for educational purposes and is lacking security and is possible to compromise

1 Answer 1


Yes, this contract is only for educational purposes.

But you can do use require if msg.sender is a owners of tokenId

require(ownerOf(tokenId) == from, "Transfer from incorrect owner");

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.