Paweł Rejkowicz
6
min read
Last Update:
March 27, 2023

Have you thought about the security of permissionless smart contracts? If you think they’re mostly safe if the code is safe, read this.

And no, I’m not going to talk about some front-end or wallet hacks.

A malicious actor can develop and release a safe & sound contract and still make users lose their deposited assets. The trick is in one detail that you should check before interacting with the contract.

The proof

To expose that contract safety does not depend only on its TEAL code, let’s look at an example code released on Algorand testnet. 

What’s visible under this link in the Algorand Explorer is this:


#pragma version 
err

Such application can’t be created and released on Algorand blockchain. But it’s right there, in a valid explorer.

How is it possible?

Let’s clear up some things, first. The AVM is working correctly and indeed, it is impossible to create such an application.

However, the TEAL code passed during an update is not evaluated and can contain literally anything. 

In the previous section, I used an extremely simple piece of code to demonstrate to you the possibility of setting any TEAL code in a smart contract update. But let’s look at a real-world example, too.

Real use case

Let’s create a simple contract, which is creating 1:1 ALGO wrapper without any fee.

In pseudo-code, it would look like:


if not ApplicationID:    
	appl //fund application    
	acfg //create wrapped ALGO asset
else:    
	if gtxns[txn.GroupIndex - 1].TypeEnum == pay:        
		xfer gtxns[txn.GroupIndex - 1].Amount of txn.Assets[0] to txn.Sender    
	else:        
		pay gtxns[txn.GroupIndex - 1].AssetAmount to txn.Sender    
	return txn.OnCompletion == NoOp

It seems to be perfectly safe. Nobody has been granted any special permissions here.

However, if our analysis is based on the code downloaded using indexer API, we could miss that the code, which was initially deployed is:


if not ApplicationID:   
	itxn appl //fund application    
	itxn acfg //create asset
else:    
	xfer 10**12 of txn.Assets[0] to txn.Sender //Free tokens for creator!!!    
	return 1

This code means that if users start to deposit their ALGOs in the contract, to receive sALGOs–an alternative asset created by the contract developer–one day they would be surprised that all real ALGOs are gone from the contract deposit.

That would happen as the creator will swap all his sALGOs (received during app creation) back for ALGOs, stealing the real funds for a now quite worthless token.

How to avoid such a hack?

The described case might be an edge case, but it's possible. This is way auditors and creators of monitoring tools should pay attention to smart contract updates and not only analyze the latest version.

So how to avoid such situation as the end user? The simplest rule is–stay cautious with permissionless contracts having a number of revisions greater than 1.

Of course, an updated contract can be entirely safe, but the analysis is just harder and less straightforward.

On the other hand, updating the contract is a perfect tool for decreasing contract size and complexity. During deployment, all the state, assets, and other things can be set up, and then, the initialization code can be replaced with only “runtime” code.

Every stick has two ends–the update mechanism can be used in a malicious manner as well as for achieving better performance. As users, we just need to stay aware of how can it be used against us.

Written by
Paweł Rejkowicz
Blockchain Security Researcher

Build the Top Web3 Dev Team

8 years of experience in one ebook. Check it out

Download