Skip to content

Please note, this content is no longer actively maintained.

The content of the SWC registry has not been thoroughly updated since 2020. It is known to be incomplete and may contain errors as well as crucial omissions.

For currently maintained guidance on known Smart Contract vulnerabilities written primarily as guidance for security reviewers, please see the EEA EthTrust Security Levels specification. As well as the latest release version, an Editor's draft is available, that represents the latest work of the group developing the specification.

General guidance for developers on what to consider to ensure security, that is currently maintained, is also available through the Smart Contract Security Verification Standard (SCSVS).

Title

Assert Violation

Relationships

CWE-670: Always-Incorrect Control Flow Implementation

Description

The Solidity assert() function is meant to assert invariants. Properly functioning code should never reach a failing assert statement. A reachable assertion can mean one of two things:

  1. A bug exists in the contract that allows it to enter an invalid state;
  2. The assert statement is used incorrectly, e.g. to validate inputs.

Remediation

Consider whether the condition checked in the assert() is actually an invariant. If not, replace the assert() statement with a require() statement.

If the exception is indeed caused by unexpected behaviour of the code, fix the underlying bug(s) that allow the assertion to be violated.

References

Samples

assert_constructor.sol

/*
 * @source: https://github.com/ConsenSys/evm-analyzer-benchmark-suite
 * @author: Suhabe Bugrara
 */

pragma solidity ^0.4.19;

contract AssertConstructor {
    function AssertConstructor() public {
        assert(false);
    }
}

assert_minimal.sol

/*
 * @source: https://github.com/ConsenSys/evm-analyzer-benchmark-suite
 * @author: Suhabe Bugrara
 */

pragma solidity ^0.4.19;

contract AssertMinimal {
    function run() public {
        assert(false);
    }
}

assert_multitx_1.sol

/*
 * @source: https://github.com/ConsenSys/evm-analyzer-benchmark-suite
 * @author: Suhabe Bugrara
 */

pragma solidity ^0.4.19;

contract AssertMultiTx1 {
    uint256 private param;

    function AssertMultiTx1(uint256 _param) public {
        require(_param > 0);
        param = _param;
    }

    function run() {
        assert(param > 0);
    }

}

assert_multitx_2.sol

/*
 * @source: https://github.com/ConsenSys/evm-analyzer-benchmark-suite
 * @author: Suhabe Bugrara
 */

pragma solidity ^0.4.19;

contract AssertMultiTx2 {
    uint256 private param;

    function AssertMultiTx2(uint256 _param) public {
        param = 0;
    }

    function run() {
        assert(param > 0);
    }

    function set(uint256 _param) {
        param = _param;
    }


}

constructor_create.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 */

pragma solidity ^0.4.25;

contract ConstructorCreate{
    B b = new B();

    function check(){
        assert(b.foo() == 10);
    }

}

contract B{

    function foo() returns(uint){
        return 11;
    }
}

constructor_create_argument.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 */
pragma solidity ^0.4.22;

contract ConstructorCreateArgument{
    B b = new B(11);

    function check(){
        assert(b.foo() == 10);
    }

}

contract B{

    uint x_;
    constructor(uint x){
        x_ = x;
    }

    function foo() returns(uint){
        return x_;
    }
}

constructor_create_modifiable.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 * Assert violation with 2 message calls:
 * - B.set_x(X): X != 10
 * - ContructorCreateModifiable.check()
 */

pragma solidity ^0.4.22;

contract ContructorCreateModifiable{
    B b = new B(10);

    function check(){
        assert(b.foo() == 10);
    }

}

contract B{

    uint x_;
    constructor(uint x){
        x_ = x;
    }

    function foo() returns(uint){
        return x_;
    }

    function set_x(uint x){
        x_ = x;
    }
}

gas_model.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 */
pragma solidity ^0.4.21;

contract GasModel{
    uint x = 100;
    function check(){
        uint a = gasleft();
        x = x + 1;
        uint b = gasleft();
        assert(b > a);
    }
}

gas_model_fixed.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 */
pragma solidity ^0.4.21;

contract GasModelFixed{
    uint x = 100;
    function check(){
        uint a = gasleft();
        x = x + 1;
        uint b = gasleft();
        assert(b < a);
    }
}

mapping_perfomance_2.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 */
pragma solidity ^0.4.22;

contract MappingPerformance2sets{

    mapping(bytes32=>uint) m0;
    mapping(bytes32=>uint) m1;
    mapping(bytes32=>uint) m2;
    mapping(bytes32=>uint) m3;
    mapping(bytes32=>uint) m4;
    mapping(bytes32=>uint) m5;
    uint b;

    constructor(){
        b = 10;
    }

    function set(bytes32 a, uint cond){
        if(cond == 0){
            m0[a] = 5;
        }else if(cond == 1){
            m1[a] = 5;
        }else if(cond == 2){
            m2[a] = 5;
        }else if(cond == 3){
            m3[a] = 5;
        }else if(cond == 4){
            m4[a] = 5;
        }
    }
    function check(bytes32 a0, uint cond0,
                  bytes32 a1, uint cond1, bytes32 a){
                      set(a0, cond0);
                      set(a1, cond1);
                      assert(m5[a] == 0);
    }
}

mapping_performance_1.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 */
pragma solidity ^0.4.22;

contract MappingPerformance1set{

    mapping(bytes32=>uint) m0;
    mapping(bytes32=>uint) m1;
    mapping(bytes32=>uint) m2;
    mapping(bytes32=>uint) m3;
    mapping(bytes32=>uint) m4;
    mapping(bytes32=>uint) m5;
    uint b;

    constructor(){
        b = 10;
    }

    function set(bytes32 a, uint cond){
        if(cond == 0){
            m0[a] = 5;
        }else if(cond == 1){
            m1[a] = 5;
        }else if(cond == 2){
            m2[a] = 5;
        }else if(cond == 3){
            m3[a] = 5;
        }else if(cond == 4){
            m4[a] = 5;
        }
    }
    function check(bytes32 a0, uint cond0, bytes32 a){
                      set(a0, cond0);
                      assert(m5[a] == 0);
    }
}

out-of-bounds-exception.sol

pragma solidity ^0.5.0;

contract OutOfBoundsException {

    uint256[] private array;

    function getArrayElement(uint256 idx) public returns (uint256) {
        return array[idx];
    }

}

return_memory.sol

/*
 * @source: https://forum.zeppelin.solutions/t/using-automatic-analysis-tools-with-makerdao-contracts/1021/3
 * Author: Dan Guido / Trail of Bits
 * Slightly modified by Bernhard Mueller

* An assertion violation is possible in 3 transactions:
*
* etch(addr)
* lookup(slate, addr)
* checkAnInvariant()

* Whereby slate == Keccak(addr)
*
* Ideally tools should output the correct transaction trace.
*/

pragma solidity ^0.5.0;

contract ReturnMemory {
    mapping(bytes32=>address) public slates;
    bool everMatched = false;

    function etch(address yay) public returns (bytes32 slate) {
        bytes32 hash = keccak256(abi.encodePacked(yay));
        slates[hash] = yay;
        return hash;
    }

    function lookup(bytes32 slate, address nay) public {
       if (nay != address(0x0)) {
         everMatched = slates[slate] == nay;
       }
    }

    function checkAnInvariant() public returns (bool) {
        assert(!everMatched);
    }
}

runtime_create_user_input.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 */
pragma solidity ^0.4.22;

contract RuntimeCreateUserInput{

    function check(uint x){
        B b = new B(x);
        assert(b.foo() == 10);
    }

}

contract B{

    uint x_;
    constructor(uint x){
        x_ = x;
    }

    function foo() returns(uint){
        return x_;
    }

}

runtime_user_input_call.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 */
pragma solidity ^0.4.19;

contract RuntimeUserInputCall{

    function check(address b){
        assert(B(b).foo() == 10);
    }

}

contract B{
    function foo() returns(uint);
}

sha_of_sha_2_mappings.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 */
pragma solidity ^0.4.22;

contract ShaOfSha2Mappings{

    mapping(bytes32=>uint) m;
    mapping(bytes32=>uint) n;

    constructor(){
        m[keccak256(abi.encode("AAA", msg.sender))] = 100;
    }

    function check(address a){
        assert(n[keccak256(abi.encode("BBB", a))] == 0);
    }

}

sha_of_sha_collision.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 * Assert violation with 2 message calls:
 * - set(66)
 * - check(0x4100000000000000000000000000000000000000000000000000000000000000)
 */
pragma solidity ^0.4.22;

contract ShaOfShaCollission{

    mapping(bytes32=>uint) m;

    function set(uint x){
        m[keccak256(abi.encodePacked("A", x))] = 1;
    }
    function check(uint x){
        assert(m[keccak256(abi.encodePacked(x, "B"))] == 0);
    }

}

sha_of_sha_concrete.sol

/*
 * @source: ChainSecurity
 * @author: Anton Permenev
 */
pragma solidity ^0.4.22;

contract ShaOfShaConcrete{

    mapping(bytes32=>uint) m;
    uint b;

    constructor(){
        b = 1;
    }

    function check(uint x){
        assert(m[keccak256(abi.encodePacked(x, "B"))] == 0);
    }

}

token-with-backdoor.sol

/*
 * @source: TrailofBits workshop at TruffleCon 2018
 * @author: Josselin Feist (adapted for SWC by Bernhard Mueller)
 * Assert violation with 3 message calls:
 * - airdrop()
 * - backdoor()
 * - test_invariants()
 */
pragma solidity ^0.4.22;

contract Token{

    mapping(address => uint) public balances;
    function airdrop() public{
        balances[msg.sender] = 1000;
    }

    function consume() public{
        require(balances[msg.sender]>0);
        balances[msg.sender] -= 1;
    }

    function backdoor() public{
        balances[msg.sender] += 1;
    }

   function test_invariants() {
      assert(balances[msg.sender] <= 1000);
  }
}

two_mapppings.sol

pragma solidity ^0.4.22;

contract TwoMappings{

    mapping(uint=>uint) m;
    mapping(uint=>uint) n;

    constructor(){
        m[10] = 100;
    }

    function check(uint a){
        assert(n[a] == 0);
    }

}

simpledschief.sol

/*
 * @source: https://forum.zeppelin.solutions/t/using-automatic-analysis-tools-with-makerdao-contracts/1021/3
 * Author: Vera Bogdanich Espina / Zeppelin Solutions
 *
 * A simplified version of the MakerDAO DSChief contract.
*  Tools should output the correct transaction trace (see source link).
*/

contract SimpleDSChief {
    mapping(bytes32=>address) public slates;
    mapping(address=>bytes32) public votes;
    mapping(address=>uint256) public approvals;
    mapping(address=>uint256) public deposits;

    function lock(uint wad) public {
        deposits[msg.sender] = add(deposits[msg.sender], wad);
        addWeight(wad, votes[msg.sender]);
    }

    function free(uint wad) public {
        deposits[msg.sender] = sub(deposits[msg.sender], wad);
        subWeight(wad, votes[msg.sender]);
    }

    function voteYays(address yay) public returns (bytes32){
        bytes32 slate = etch(yay);
        voteSlate(slate);

        return slate;
    }

    function etch(address yay) public returns (bytes32 slate) {
        bytes32 hash = keccak256(abi.encodePacked(yay));

        slates[hash] = yay;

        return hash;
    }

    function voteSlate(bytes32 slate) public {
        uint weight = deposits[msg.sender];
        subWeight(weight, votes[msg.sender]);
        votes[msg.sender] = slate;
        addWeight(weight, votes[msg.sender]);
    }

    function addWeight(uint weight, bytes32 slate) internal {
        address yay = slates[slate];
        approvals[yay] = add(approvals[yay], weight);
    }

    function subWeight(uint weight, bytes32 slate) internal {
        address yay = slates[slate];
        approvals[yay] = sub(approvals[yay], weight);
    }

    function add(uint x, uint y) internal pure returns (uint z) {
        require((z = x + y) >= x);
    }

    function sub(uint x, uint y) internal pure returns (uint z) {
        require((z = x - y) <= x);
    }

   function checkAnInvariant() public {
        bytes32 senderSlate = votes[msg.sender];
        address option = slates[senderSlate];
        uint256 senderDeposit = deposits[msg.sender];

        assert(approvals[option] >= senderDeposit);
    }
}