Code Security

$16.77M Minted With the Team's Own Keys [The Fetch.ai Attack Explained]

Amartya | CodeAnt AI Code Review Platform
Sonali Sood

Founding GTM, CodeAnt AI

Someone minted and drained about $16.77 million in tokens across three linked crypto projects in roughly thirteen hours. Every transaction carried a valid cryptographic signature.

That is the detail that matters. The contracts were not tricked. There was no reentrancy, no math error, no clever call sequence. The attacker held the keys, and the keys were all the code ever asked for.

This is a walkthrough of what happened across Fetch.ai, NuNet, and SingularityNET, why a valid signature is the hardest kind of attack to catch, and where the security boundary has quietly moved.

It is written for engineers, and it is careful to separate what the sources confirm from what is still under investigation.

Why this sits on a code-security blog: the failure here was not in the audited contract logic. It was in the custody of the keys that the logic trusts. CodeAnt AI does not audit Solidity, and this article does not pretend the fix was a smart-contract review. What it does cover is the part of this class that lives in application code and configuration, which is exactly where a stolen signing key usually starts its life.

What Happened in the Fetch.ai Hack?

The timeline, assembled from Fetch.ai's on-chain analysis and multiple security-firm reports, is tight and coordinated. On the evening of September 19, 2026, an attacker drained the TokenConversionManagerV3 contract, the Ethereum-side component of the SingularityNET cross-chain bridge, of its entire FET balance.

A single call to the contract's conversionIn function paid out 8,721,530 FET, roughly $1.55 million, to an attacker-controlled wallet. Within the same window, a separately compromised NuNet minting key was used to mint 408.5 million NTX, about 42% of the token's total supply, from the NuNet deployer account.

Both operations were coordinated and initiated within about a minute of each other. By the following day, the same attack cluster had minted a further 260 million AGIX and 53.8 million WMTx on Ethereum. Security monitors valued the cluster's holdings at approximately $16.77 million.

Item

Detail

Date

September 19 to 20, 2026

FET drained

8,721,530 FET (~$1.55M) via conversionIn on the SingularityNET bridge

NTX minted

408.5 million (~42% of supply) via a compromised NuNet mint key

AGIX minted

260 million on Ethereum

WMTx minted

53.8 million on Ethereum

Total attacker holdings

~$16.77 million at time of reporting

Root cause

Compromised signing and minting keys, not a smart-contract code flaw

Contracts affected

SingularityNET bridge and NuNet mint. Fetch.ai says its own contracts are safe

One clarification the sources stress. Fetch.ai has repeatedly stated that its own smart contracts remain safe and that FET continues to operate normally. The affected components were the SingularityNET bridge and the NuNet mint path, which are connected to Fetch.ai through the ASI Alliance token merger rather than being Fetch.ai's own contracts.

The Signature Was Valid, Which is the Whole Story

This is the part worth slowing down on, because it inverts the usual mental model of a crypto exploit. A smart-contract exploit normally means the code did something its authors did not intend.

A reentrancy bug, an integer overflow, a missing access check, an oracle that could be manipulated. The defense is an audit that finds the flawed logic. This was not that. Fetch.ai's analysis describes the drain as authorized by a valid signature from the bridge's own conversion authorizer, a nonce-zero offline key that exists solely to sign backend approvals.

That said, the compromise occurred in key custody or the signing service rather than in the contract code.

Read that carefully. The conversionIn function did exactly what it was written to do. It received a request bearing a valid signature from the authorized signer, and it honoured it, because honouring valid signatures from the authorized signer is the entire purpose of the function.

The verified contract did not fail. It succeeded, on behalf of an attacker holding a key it had every reason to trust. The NuNet side is the same lesson in a more dramatic form. The mint key is authorized to create new supply.

In the attacker's hands, that authority produced 42% of the token's supply out of nothing, and the contract had no reason to object, because minting is what a mint key is for.

Why a Compromised Private Key Is Harder to Detect Than a Code Bug

A code bug is a static property of the contract. It is there in the source, it is there before deployment, and a sufficiently good audit finds it. The whole discipline of smart-contract auditing exists to catch exactly that.

A stolen key produces transactions that are indistinguishable from legitimate ones, because cryptographically they are legitimate. There is no malformed input to reject, no anomalous call pattern that a well-written require statement would block.

The signature verifies. The transaction is valid. On-chain, it looks like the authorized signer doing authorized things.


Code-flaw exploit

Key-compromise exploit

Where the fault is

In the contract source

In key custody or the signing service

When it is introduced

Before deployment

Any time the key leaks

What an audit catches it

Smart-contract audit

Not a contract audit at all

What the transaction looks like

Anomalous, potentially rejectable

Perfectly valid, signed by the real signer

The defensive discipline

Code review and audit

Secrets management and key custody

This is why the incident is genuinely hard to defend against at the contract layer. You cannot write a check that distinguishes the real signer from a thief holding the real signer's key. The distinction does not exist in the data the contract can see.

The defense has to be somewhere else entirely. It has to be in never letting the key leak, in scoping what any single key can do, and in detecting anomalous use of a key even when the signature is valid.

The Audit Boundary Moved, and Most Audits Have Not

Here is the reframe that this incident forces.

For years, the security question for a crypto project was "is the contract audited." That question is necessary and it is no longer sufficient. Because an audited contract faithfully executed an attacker's will.

The audit was not wrong. It was scoped to the wrong half of the system. The security of a signed system rests on two things. The correctness of the code that verifies signatures, and the custody of the keys that produce them. Auditing has historically concentrated almost entirely on the first, and this attack lived entirely in the second.

Your audit does not stop at the contract anymore. It stops at the key. And the key does not live in the contract. It lives in a signing service, a backend, a deployment pipeline, a configuration file, an environment variable, or in the worst case, a line of source code.

That last list is the important one, because it is not blockchain territory at all. It is ordinary application security, and it is where a code-security platform actually operates.

Where this Becomes an Application Security Problem

A signing key or a mint key does not begin its life on-chain. It begins in the infrastructure that holds it, and that infrastructure is code and configuration that a team wrote.

The ways such a key leaks are the same ways any high-value credential leaks.

  • Hardcoded in source. A key committed directly into application code, where it exists in version history, on developer machines, and anywhere the repository is reachable. This is the single most common and most preventable failure.

  • Exposed in a configuration file or environment dump. A key that reaches a log, an error report, a misconfigured environment, or a shipped bundle.

  • Over-permissioned. A backend key that can do far more than its one job requires, so that its compromise is catastrophic rather than contained. The conversionIn authorizer and the NuNet mint key were each single points of total failure.

  • Long-lived and un-rotated. A key with no expiry, so that a compromise weeks earlier is still fully valid when it is finally used.

Every one of those is detectable in application code and configuration, before the key is ever used to sign anything. That is the layer where this attack could have been cut off, and it is a code-review problem rather than a smart-contract problem.

How CodeAnt AI Addresses the Key-custody Layer

Precision matters here, so this is stated narrowly. CodeAnt does not audit smart contracts, and a Solidity audit is the right and separate tool for contract logic.

What CodeAnt covers is the application-code and configuration layer where signing keys and mint keys are created, stored, and leaked.

Secret scanning at the pull request

CodeAnt's secret scanning inspects every pull request for hardcoded credentials, from cloud keys to API tokens and private keys, and flags them before they reach production or version history. A signing key committed to source is caught at the diff, which is before it can ever authorize a transaction.

It also detects values that are obfuscated or embedded in dynamic strings. And it recommends moving them to an environment variable or a secret manager with the correct syntax, which is the custody fix that prevents this class.

Full pull-request review, not a pattern match

A leaked key is one finding. AI code review reads the whole change in context, so a hardcoded credential is caught alongside the authorization gaps, configuration errors, and injection flaws that surround it. The over-permissioned backend that made a single key catastrophic is a design issue visible in code review.

Continuous exposure analysis on the live surface

The AI penetration testing pipeline mines production bundles and the external surface for exactly this class of exposure, pulling JavaScript for API keys, internal hostnames, and source-map artifacts that leak original paths. A key already shipped and reachable from the outside is something you want to find before an attacker does.

The relevant credential is the track record. CodeAnt has found 150+ CVEs, including a CVSS 10.0 vulnerability in pac4j that went undetected for six years, across projects representing 2B+ monthly downloads protected.

The discipline that finds a maximum-severity flaw in reviewed open-source code is the discipline that flags a signing key in a diff.

Why Penetration Testing Still Matters After a Smart Contract Audit

Catching a key at review keeps it out of the code. Testing the running system finds the keys that are already out there, and this is the half most crypto security programs skip. A penetration test of the infrastructure around a bridge asks the questions an audit of the contract never does.

  • Where are the signing keys stored, and is any of that reachable?

  • What can the backend authorizer actually do, and is its scope minimal?

  • Are keys rotated, and is anomalous signing detected even when the signature is valid?

Those are the questions that map to this incident. The contract was fine. The infrastructure holding the key was not tested with the same rigour the contract was, and the gap between those two levels of scrutiny is precisely where $16.77 million went.

The two halves compose into a complete picture. Secret scanning and code review keep new keys out of the code.

Penetration testing and attack surface analysis find the keys already exposed and probe whether the systems holding them can be reached. A contract audit covers the logic. All three are required, and this attack is what it looks like when only one of them is done well.

What Every Team Running Signed Infrastructure Should Do

Six actions, ordered by where they cut off the attack.

  • Scan every commit for keys. A signing or mint key in source code is the earliest and cheapest point to catch this. Block it at the pull request, before it is ever live.

  • Scope every key to one job. A key that can only do one narrow thing limits what its compromise can reach. The authorizer and the mint key here were each able to cause total loss on their own.

  • Rotate keys and use short lifetimes. A key compromised weeks ago should not still be valid. Rotation shrinks the window whether or not you ever detect the leak.

  • Keep keys out of application environments the code can read. A signing key should live in a hardware security module or a dedicated signing service, not in an environment variable a subprocess can print.

  • Monitor for anomalous signing, not just invalid signatures. A valid signature from an unusual context, at an unusual time, moving unusual value, is the only on-chain signal a key compromise produces. Watch for it.

  • Test the infrastructure, not only the contract. Audit the contract, and separately penetration-test the systems that hold the keys the contract trusts. The second is where this attack lived.

Where This Leaves You?

This attack will be filed as a crypto hack and a bridge exploit. Underneath both, it is a key-custody story, and key custody is application security rather than blockchain magic.

Every signature was valid. The audited contract worked perfectly. And $16.77 million moved, because the security of a signed system is only ever as strong as the custody of the keys behind the signatures. And that custody lives in ordinary code and configuration that a review can read.

The contract audit was necessary and it was not enough. The question for any team running signed infrastructure is not only whether the contract is audited. It is whether a signing key would survive their next pull request, and whether anyone has tested the systems that hold it.

Sources

FAQs

What caused the Fetch.ai and SingularityNET attack?

Was the smart contract hacked?

How did one attacker hit three projects?

What is the difference between a code exploit and a key compromise?

How do you prevent a signing key from being stolen?

Start Your 14-Day Free Trial

AI code reviews, security and quality trusted by modern engineering teams.

Table of Content
No headings found on page

Ship clean & secure code faster

Get Pentest Report

NO CC REQUIRED