Skip to main content
Ayaz Mammadov

Browsing for Bugs: Finding and Reporting a $3M Bug in Premia Finance

How Zellic found a critical security vulnerability affecting all three million dollars worth of staked Premia Finance tokens
Article heading

I'm Ayaz Mammadov, a security engineer at Zellic. I often come across vulnerabilities in code. One day, I was browsing projects during my spare time and found something interesting from Premia Finance — an uncaught bug that could have led to millions of dollars in lost funds.

Though now resolved, this story serves as an interesting example of the process security engineers take to discover bugs. From finding targets to exploring a codebase, we’ll go over the steps it takes to find and expose a vulnerability and how the Premia Finance bug was caught.

Finding a Target

There are several factors that come into play when finding a target.

Platforms, ecosystems, and languages. These are most important to consider when finding a target. Newer and less mature platforms that use different languages present more opportunity for finding security flaws — developer knowledge and confidence is not yet strong, which leaves more room for error. Further, when searching for vulnerabilities in less mature platforms, there is less competition (because of limited information and a high barrier to entry). An experienced security researcher has a significant advantage in finding bugs on newer platforms because of their domain expertise. However, there are disadvantages when it comes to newer platforms: there are far fewer projects available, and on average those projects have a smaller total value locked (TVL).

The TVL range. The larger the TVL of the project, the more severe the bugs are. Apart from obvious criticals that cause loss of funds, even less severe bugs that would occasionally be disregarded as user error or an unlikely incident can have far-reaching and spread-out effects. This is especially true when other nonstandard contracts/tokens (e.g., ERC-777s) are involved that have special features that are not accounted for. Large projects usually also have more audits from different auditing companies and bug bounty systems, which greatly reduce low-hanging fruit. However, small projects might not have auditor bug bounties.

Project type and its mechanisms. Crypto shows up in many fields, whether it be in video games, casinos, markets/DeFi, NFT marketplaces, escrow systems, mixers, wallets, and so on. Here, a security researcher's personal preference is most important, as experience with and knowledge of the common pitfalls of specific projects and their interactions with well-known DeFi projects (e.g., Compound, Uniswap) is greatly appreciated. The trade-offs here are obvious, as finance-related protocols usually contain higher TVLs. On the contrary, other crypto projects may contain less TVL but more lines of on-chain code and higher complexity, which makes it easier to find security flaws.

"Forktasticity". This is an unspoken topic; it describes how forked a project is and how likely it's to be used as a base for other projects. One may notice that a lot of decentralized apps (dApps) are altered forks of other popular protocols (e.g., Compound, AAVE, Uniswap). These projects may have few changes that a security researcher can quickly cover if they are already up-to-date with the original protocol and the possible side effects that changes have. Conversely, they also usually contain widely reviewed code that is unlikely to have any issues. These projects also expose opportunities: when an exploit affects a protocol, it usually affects many of its forks. Security researchers who are on the watch and following recent news, or use tools like Zellic's Forky (coming soon), can often take advantage of being an early bird to secure other protocols.

Methodology of Finding Bugs

There are three main ways of exploring code: focusing on breadth, focusing on depth, and focusing on speed.

The breadth-first style of security research relies on common, low-hanging fruit, which are issues that present themselves in a similar manner. The upside of this approach is that a security researcher can cover more code with just a quick skim and without much consideration of the underlying intentions, effects, and architectural decisions taken during the development phase. This type of security research is also context-free, meaning that it can be done without having to take notes and piecing together how things work. This type of security research is advantageous because it can be employed at any time, when energy is low, and when there isn't that much free time, and it can be done on a whim. But the downside is that it is difficult to find in-depth bugs in secure and popular protocols.

The depth-first style of security research prefers to uncover every detail and inner workings of a protocol, methodically going over each line of code and thinking about various consequences and possible exploitation. This would ideally be the only style of security research, as if it is effectively implemented, it results in uncovering deep, hard-to-catch bugs. However, there are clear downsides: if the protocol being looked at is not fairly large or commonly seen and results are not found, the effort spent deeply thinking about the protocol is not of much value. This style of security research is preferred for larger projects (e.g., Compound, AAVE) because even if issues are not found, the knowledge gained from conducting the research is easily applicable to forks and other protocols. When a security researcher inevitably encounters the same code they've already read, they'll be able to get up to speed a lot faster.

Lastly, a speed-based approach can be employed where a security researcher keeps their eyes out for accounts on social media (such as Twitter/Telegram) that report issues that affect popular protocols. This information can be used to target similar forks or projects, tailoring the vulnerability to them. This requires a security researcher to be up-to-date and vigilant.

Finding the Protocols

There are multiple sources for finding protocols, from websites to social media to news feeds. I personally use websites such as DeFiLlama to browse through DeFi protocols as they provide values for the TVL and the platform on which the project is based. Other important pieces of information like previous audits or links to documentation can also be quickly found. The website DappRadar is an alternative. A lot of upcoming projects won't be listed on any aggregators but need to be discovered through social media such as Twitter and Telegram.

Finding the Bug

During my spare time, I decided to open up DeFiLlama. My preference is to look at projects with a TVL greater than five million dollars and ones that contain bug bounties. Bug bounties are a win-win situation — they ensure protocols are secured while supporting the work and efforts of security researchers.

I looked through several projects, glancing at their descriptions and doing a very brief overlook of the project structure to determine my interest. Then, I stumbled upon Premia Finance. When finding a new project, I look at its documentation and get a bird's-eye view of how everything works and what the purpose of the protocol is. In this case, it was an options-based market.

The first thing to look at is the project structure to determine certain pieces of information:

  • Is the code original, or is it a fork? If the latter, is it altered fork code?

  • What is the topmost function being called by users? (Usually, these functions are external/public, but that's not always the case as it could be called by another contract, so do due diligence with cross-referencing.)

  • Are there commonly shared implementations (ERC-20s, etc.)?

  • Are there custom implementations for things that have already established implementations (custom onlyOwner, nonReentrant, etc.)?

The Bug

After exploring the project, I came across a function called sendFrom that is responsible for sending staked users' tokens across chains.

A user can allocate allowance to another user such that they can manage their tokens across chains. The function responsible for this in the invocation of sendFrom is _debitFrom. The _debitFrom checks that the user calling sendFrom has been allocated allowance from the from address, and if that is the case, it then burns the tokens that are to be sent across chains. Otherwise, it reverts.

function _debitFrom(
address from,
uint16,
bytes memory,
uint256 amount
) internal virtual override {
address spender = msg.sender;

if (from != spender) {
unchecked {
mapping(address => uint256)
storage allowances = ERC20BaseStorage.layout().allowances[
spender
]; // (1)

uint256 allowance = allowances[spender]; // (2)
if (amount > allowance) revert OFT_InsufficientAllowance();

_approve(
from,
spender,
allowances[spender] = allowance - amount
);
}
}

_burn(from, amount);
}

The issue arises in the allowance check — specifically the allowance being checked. When simplified, the allowance being checked is allowances[msg.sender][msg.sender] (see lines (1) and (2)). As a result, any user can grant allowance to themself to arbitrarily cause cross-chain transfers of other users' tokens to an arbitrary address. In conclusion, any user can steal any other user's funds using cross-chain transfers.

The Impact

At the time this vulnerability was discovered, there were three million dollars' worth of Premia tokens staked across multiple chains. All of these staked tokens were at risk of being stolen.

The Fix

The function was fixed by properly retrieving the allowances variable using the from address and not spender.

function _debitFrom(
address from,
uint16,
bytes memory,
uint256 amount
) internal virtual override {
address spender = msg.sender;

if (from != spender) {
unchecked {
mapping(address => uint256)
storage allowances = ERC20BaseStorage.layout().allowances[
from
];

uint256 allowance = allowances[spender];
if (amount > allowance) revert OFT_InsufficientAllowance();

_approve(
from,
spender,
allowances[spender] = allowance - amount
);
}
}

_burn(from, amount);
}

After this fix, if a malicious user were to supply a from address that hadn't granted allowance to them, the check would confirm this, as it would then use the from address's allowance and not the msg.sender's allowance.

Conclusion

We hope this was an interesting and informative read about the different methods for finding targets, the advantages and downsides of certain protocols/projects, the different sources to find said protocols, and an example bug that we found.

This story aimed to help researchers optimize their bug-hunting process. We encourage all security researchers to get out there — go secure protocols in the wild!

Disclosure Timeline

  • 7/12/2023 — We get in touch with the Premia Finance team.

  • 7/13/2023 — They confirm the issue and start working on remediation.

  • 7/25/2023 — The bug bounty was rewarded.

  • 7/31/2023 — The bug is fixed, and the vulnerability can be disclosed.

A big thanks to the Premia Finance team for getting back to us quickly and handling communications in a timely manner.

About Us

Zellic specializes in securing emerging technologies. Our security researchers have uncovered vulnerabilities in the most valuable targets, from Fortune 500s to DeFi giants.

Developers, founders, and investors trust our security assessments to ship quickly, confidently, and without critical vulnerabilities. With our background in real-world offensive security research, we find what others miss.

Contact us for an audit that’s better than the rest. Real audits, not rubber stamps.