Access Control Vulnerability in DeFi | QuillAudits

Table of Contents:

What does “Access Control” mean?

Basically, access control means “who is allowed to carry out a specific duty”. Access controls outline the limitations on user roles and privileges in smart contracts.
Smart contracts include a number of critical functions that should be well safeguarded from access by malicious users, such as changing ownership and upgrading contracts. A malicious user calling these critical functions can cause a great deal of harm to the project.

Importance of use of access controls:

1. It helps protect critical functions from unauthorized access.

An access control mechanism can be used to limit the access of some functions to privileged users like admin/ owners. We can limit some critical operations, such as changing owners, creating tokens, halting contracts, etc., to being called only by owner roles. It assists in preventing other users from calling these functions and safeguards against unwanted access.

2. It helps in creating different levels of authorization.

In a contract, we can create different levels of authorization based on different roles. We can define multiple roles, and each is allowed to perform different sets of actions in a contract.
For example, in a crowdfunding contract, there can be different levels of authorization, like admin, manager, contributor, etc., and each of them may have been allotted different sets of actions.

3. It helps in Whitelisting and blacklisting users.

A whitelist is useful if you want to restrict access to a certain function or grant privileges to a certain group of users. Simple whitelists can be quite powerful. When the user calls the smart contract function, it checks if the address is on the whitelist. If it is, the function executes.
The same process is used with blacklisting. Administrators or owners can easily ban certain users if they don’t want them to call specific functions.

4. Granting and Revoking Roles:

Once a specific role is granted to the user, it can also be revoked quite easily. It comes in very handy when there is an upgrade in a role or a removal of the role. Roles can be granted and revoked dynamically via the grantRole and revokeRole functions.

Real-life Exploits Case Studies:

1. Rikkei Finance:

In this case, the SetOracleData() function’s visibility was set to public which means that it can be called externally. So, anyone can call SetOracleData and change Oracle data to manipulate the price. Approx $1 Million were stolen by the hackers.

function setOracleData(address rToken, oracleChainlink _oracle) external { //vulnerable point
oracleData[rToken] = _oracle;

2. Ragnarok Online Invasion:

In this case, the cause of the attack was a typical access control vulnerability of the ownership transfer function. The transferOwnership function’s visibility is set to "public". The attacker transferred ownership to himself and stole around 158 BNB from the contract.

function transferOwnership(address newOwner) public virtual {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;

3. UERII Token:

UERII token had a mint function whose visibility was set to public. Now, any user can mint unlimited tokens. The attacker minted 100 billion tokens and gained a profit of around $2,500.

function mint() public returns (bool) { 
_mint( msg.sender, 100000000000000000 );
return true;

Openzeppelin’s access control Libraries:

The best way to implement access control is by using Openzeppelin’s access control libraries:

1. Ownership and Ownable:

We can use Openzeppelin’s Ownable library to implement this. OpenZeppelin’s Ownable defines modifiers like “onlyOwner” that check if the user making a function call is the owner of the contract.

2. Role-Based Access Control (RBAC):

While the simplicity of ownership can be helpful for simple systems or quick prototyping, different levels of authorization are often needed.

A small challenge for you:

Objective: Become the owner of the contract and change the value of pwn to true.

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

conract accessControlVuln {

error notWhitelisted();
bool pwn;
address owner;
mapping(address => bool) whitelistedMinters;

constructor() {
owner = msg.sender;
modifier whitelisted(address addr) {
if(!whitelistedMinters[addr]) revert notWhitelisted();
function addToWhitelist(address addr) public {
require(addr != address(0), "Zero address");
whitelistedMinters[addr] = true;
function changeOwner(address addr) public whitelisted(addr) {
owner = msg.sender;
function pwnOwner() public {
require (msg.sender == owner);
pwn = true;

Web3 security- Need of the hour

Why QuillAudits for Web3 Security?
QuillAudits is well-equipped with tools and expertise to provide cybersecurity solutions saving the loss of millions in funds.

Want more Such Security Blogs & Reports?

Connect with QuillAudits on :
Linkedin | Twitter | Website | Newsletter | Discord | Telegram

Partner with QuillAudits :

- Affiliate program ( Refer and secure web3 )



Smart Contract Auditing Experts , Making web3 a safer place .

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store