I consider myself a versatile cybersecurity professional, passionate about finding vulnerabilities, securing smart contracts, and investigating digital threats. In this article, I'll share a real example of a Web3 exploit and show you how to identify and prevent such risks.

πŸ“Œ Introduction

Access control defines who is allowed to call which function in a smart contract. When access control is implemented incorrectly β€” or not at all β€” any attacker can execute privileged functions, leading to stolen funds, destroyed contracts, or complete loss of ownership.

Access control bugs are among the most common and most dangerous vulnerabilities in Ethereum smart contracts, often resulting in irreversible financial losses.

πŸ” What Is an Access Control Vulnerability?

An access control vulnerability occurs when:

  • Critical functions are publicly callable
  • Ownership is not verified
  • msg.sender is not properly checked
  • Admin roles are misconfigured
  • πŸ‘‰ In simple words:

The contract forgets to ask: "Are you allowed to do this?"

❌ Vulnerable Smart Contract Example

Below is a contract that looks fine, but contains a serious access control flaw.

None

🚩 What's the Problem?

  • withdrawAll() is marked public
  • No check for msg.sender == owner
  • Anyone can drain the entire contract balance

βš”οΈ Attack Scenario (Step-by-Step)

  1. Contract is deployed by the owner
  2. Owner deposits ETH into the contract
  3. Attacker notices withdrawAll() has no access restriction
  4. Attacker calls withdrawAll()
  5. πŸ’₯ Entire balance is transferred to the attacker

No hacking tools. No exploits. Just one function call.

Secure Smart Contract (Fixed Version)

Let's fix the vulnerability using proper access control.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SecureVault {
    address public owner;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Not authorized");
        _;
    }

    function withdrawAll() public onlyOwner {
        payable(owner).transfer(address(this).balance);
    }

    receive() external payable {}
}

βœ… Why This Is Secure

Uses an onlyOwner modifier

Verifies msg.sender

Prevents unauthorized withdrawals

Follows best practices

πŸ§ͺ Medium-Level Demo Using Remix IDE

You can demonstrate this vulnerability live using Remix.

πŸ”§ Step 1: Open Remix

Visit: https://remix.ethereum.org

  • Create two files:
  • VulnerableVault.sol
  • SecureVault.so

πŸ”§ Step 2: Deploy Vulnerable Contract

  • Compile VulnerableVault.sol
  • Deploy using Account 1
  • Send some ETH to the contract

πŸ”§ Step 3: Attack the Contract

  • Switch to Account 2
  • Call withdrawAll()
  • βœ… ETH is transferred to attacker account
  • πŸ’₯ Attack successful

πŸ”§ Step 4: Deploy Secure Contract

  • Compile & deploy SecureVault.sol
  • Fund the contract
  • Switch to Account 2
  • Try calling withdrawAll()

❌ Transaction reverts: "Not authorized"

βœ… Attack prevented

🧠 Real-World Impact

Access control bugs have caused:

  • Millions of dollars in losses
  • DAO takeovers
  • Permanent contract destruction

Even experienced developers make this mistake when:

  • Rushing deployments
  • Copy-pasting code
  • Forgetting modifiers

πŸ› οΈ Best Practices to Prevent Access Control Bugs

βœ” Always restrict critical functions βœ” Use onlyOwner or role-based access βœ” Prefer OpenZeppelin's Ownable / AccessControl βœ” Write unit tests for authorization βœ” Perform security audits

🏁 Conclusion

Access control vulnerabilities are simple but catastrophic. One missing require() can destroy an entire protocol.

πŸ” If a function changes money, ownership, or state β€” protect it.

buymeacoffee.com/vinaysati1