Audit Teardown

Extropy.IO
6 min readSep 23, 2024

This article illustrates the main sections of an audit report, using examples from recent audits we have conducted for clients.
When detailing vulnerabilities found by code inspection I have shown the approach used, or thinking behind the way that they were found.

A typical report will contain the following sections :

  • background — scope / dates / client
  • summary of business logic
  • methodology — code inspection and tools
  • executive summaries
  • issues
  • tools used and results from them

Issues Found

We’ll go out of order, starting with the issues, this section is the heart of the audit report where we list all the potential vulnerabilities that we have found.

Each issue will be reported in a standard format :

  • Title and risk categorisation
  • Location in the code
  • Description and code snippet
  • Recommendations
  • Status

Let’s have a look at some issues from recent audits :

Unbounded call in ‘setConfiguration‘ can exceed the block gas limit
Risk : LOW

Location : Utils.sol#62

The function setConfiguration() is used to set up a status for a number of addresses.

The function accepts a dynamic array of addresses and a dynamic array of bytes32 statuses. The gas costs for the unbounded loop in this call risks exceeding the block gas limit.

function setConfiguration( address[] memory addresses,bytes32[] memory status,
bool hasStatus ) external onlyOwner {

if (addresses.length != status.length) revert InvalidConfig);
uint256 length = status.length;
for (uint256 i; i < length; ) {
setStatus(addresses[i], status[i], hasStatus);
unchecked {
++i;
}
}
}
}

How did we find this ?
Unbounded loops are a well known vulnerability, so it makes sense to check all the loops in a contract

Swap Execution and Slippage Control in removeSurplus

Risk Low

Location Treasury.sol#57

The removeSurplus function in Treasury is designed to convert excess treasury ETH to ABC tokens.

However, its current implementation might allow for market manipulation, particularly if large amounts of ETH are involved. Specifically, the function’s reliance on a single liquidity pool and the fixed slippage parameter (acceptableSlippage) could be exploited.

An attacker could use a flash loan to temporarily manipulate the price of ABC in the liquidity pool, triggering removeSurplus to swap ETH for ABC at an inflated rate.

After the swap, the attacker could sell the acquired ABC tokens at a higher rate in other transactions within the same block, and then repay the flash loan.

Recommendation

  • Implement dynamic slippage control based on current market conditions.
  • Introduce a time-weighted average price (TWAP) mechanism to determine the swap rate, reducing vulnerability to short-term price manipulation.
  • Split large swaps into multiple smaller transactions to minimise market impact.
  • Utilise external price oracles for additional price verification.
  • Implement circuit breakers that pause swapping in case of detected abnormal activities, such as sudden large price movements.

Status

Resolved, with the addition of access control and mitigation against flash loans.

This issue is an economic attack. Manipulating prices is a common exploit, and flash loans can be used to increase the effect.

How can you spot issues like this ?

  • Adopt an attackers mindset
  • Look for ways that a price can be manipulated, in particular look at whether there is protection against slippage and flash loans.

The next two issues relate to controlling access to configuration changing functions, they illustrate two sides of the problem :

Missing modifier

Risk High

Affects Fees.sol

The function withdrawFees is missing a modifier allowing anyone to withdraw fees.

function withdrawFees(uint8 _node, uint8 month) {
...
}

Recommendation

Use the existing `onlyOwner` modifier to guard this function

Status

Resolved.

Critical addresses cannot be updated

Risk Low

Affects Treasury.sol

In the constructor the following addresses are set:

nft = NFT721(_nftAddress);
quoteErc20 = IERC20(_quoteErc20Address);
priceFeed = AggregatorV3Interface(_priceFeedAddress);

However no setter functions exist for changing these variables.
Therefore, the contract may become unusable should control of these addresses be lost.

Recommendation

Add functions to allow the addresses to be changed.

Status

Resolved.

How did we find these ?

It is vital when auditing a contract to have a clear idea of the privileged addresses used in the project.

These addresses may relate to

  • privileged roles able to perform administratrive functions
  • controllers of wallets, vaults or fund holding contracts.

Given that most attacks aim to steal funds, this area will be a prime target for attackers.

You need to check therefore that

  • Access control using these addresses is correct and complete
  • Functions used to change such configuration need to be absolutely secure.

On the other hand, we need to ensure that the security around configuration isn’t too brittle, it should be flexible enough to allow for the situation where, for example a private key being lost or compromised.

A good general solution is the use of multisigs, a standard solution is Gnosis Safe wallet.

Tickets may be processed out of order

Risk Medium

Location Ticket.sol

In process tickets function, there is no check to ensure that tickets are only processed for completed rounds and that rounds cannot be skipped

function processTickets(uint16 round) external onlyOwner() {

}

Recommendation
Use a monotic variable to track the last completed round, and only allow one round greater than that to be processed at a time.

Status

Resolved.

Tickets or loans of zero value may be purchased

Risk Medium

Location — multiple contracts

In multiple projects we have seen the assumption (which makes business sense) that users would not try to take out a loan, or buy a ticket having zero value.
This assumption has meant that there have been inadequate checks on input data, specifically not checking for zero value tickets / loans.
Such transactions could lead to compromised state iin the contract, or a denial of service attack.

Recommendation

Always check that input data is in a sensible range, beware of assumptions that have been made about user behaviour.

Status

Resolved.

Other sections

Executive Summary

The report requires a summary of the issues found, there may be a technical and a non technical summary to address the different audiences.

Background — scope / dates / client

The report usually starts with some background, establishing the timescale and scope of the report

Extropy was contracted by client ABC to conduct a code review and vulnerability assessment of the project. The review was carried out between 15th and 21st June.

Scope

The following contracts were audited:

Lottery.sol

Ticket.sol

User.sol

Utils.sol

The following contracts / files were out of scope:

TokenDistribution.sol

Marketplace.sol

System Overview

It is useful to include a description of the functionality of the project

The protocol allow users to play a game:…
Each round a winning combination will be generated …

Data Structures

Not only does this give the readers of the report an understanding of the project, it also shows the development team, the assumptions that the auditors have, which if incomplete can be addressed by the developers.

Methodology

There should be a section outlining the methodology used for the audit :

The risk rating given for issues follows the standard approach of the OWASP Foundation. We combine
two factors :

Likelihood of exploit

Impact of Exploit

The Categories we use are Critical, High, Medium, Low and Informational These categories may notalign with the categories used by other companies.
The informational category is used to contain suggestions for optimisation (where this is not seen as causing significant impact), or for alternative design or best practices.

Executive Summary

The report requires a summary of the issues found, there may be a technical and a non technical summary to address different audiences.

Where to go from here ?

For further examples of audit reports, visit our website :

Audit Report Examples

If you have a project that is ready to deploy, visit
Audit Proposal
to get an audit quote,

and if you mention this article you get a discount.

If you would like to expand your auditing skills, we run auditing courses, targeting EVM, Starknet and Mina.
You can find details of the upcoming courses on our education site :
Extropy Education

--

--

Extropy.IO

Oxford-based blockchain and zero knowledge consultancy and auditing firm