LABUBU:
TOY STORY
GONE WRONG

Executive Summary
On June 6, 2025, ALEX Lab Foundation’s on-chain contracts were exploited via a flaw in the self-listing verification logic.
An attacker managed to bypass the verification mechanism and add his malicious contract to the ALEX-approved token contracts. This allowed him to drain several asset pools, with a self-reported total loss of assets at that time of $8,373,227.13.
ALEX swiftly launched a compensation plan that allowed full token reimbursement using the ALEX Lab Foundation treasury.
The attack stood out for two factors:
1) The novel token verification bypass
Bypassing ALEX’s self-listing verification logic required intimate knowledge of how the Stacks blockchain operates, beyond its smart contract language capabilities.
2) The stolen tokens off-ramping orchestration
Post-hack, they attempted to extract liquidity from the Stacks ecosystem via multiple protocols, from swapping stolen assets before they were burned, to adding stolen assets as liquidity to borrow against them, they fully utilized the entire ecosystem.
The initial stolen amounts were: 8432480.981911
However, in the end, the attacker only managed to extract 21.85
An attacker managed to bypass the verification mechanism and add his malicious contract to the ALEX-approved token contracts. This allowed him to drain several asset pools, with a self-reported total loss of assets at that time of $8,373,227.13.
ALEX swiftly launched a compensation plan that allowed full token reimbursement using the ALEX Lab Foundation treasury.
The attack stood out for two factors:
1) The novel token verification bypass
Bypassing ALEX’s self-listing verification logic required intimate knowledge of how the Stacks blockchain operates, beyond its smart contract language capabilities.
2) The stolen tokens off-ramping orchestration
Post-hack, they attempted to extract liquidity from the Stacks ecosystem via multiple protocols, from swapping stolen assets before they were burned, to adding stolen assets as liquidity to borrow against them, they fully utilized the entire ecosystem.
The initial stolen amounts were: 8432480.981911
STX
, 50.73942482 aBTC
, 12.76470894 sBTC
, 119,419,656.0046488 ALEX
and 1,748,326.97784601 sUSDT
tokens.However, in the end, the attacker only managed to extract 21.85
BTC
to his Bitcoin address and $2,091,544 in stablecoins liquidity to his Ethereum holding address. An extra 120 native ETH received by the attacker during the hack is most likely also linked to the hack, although the link was not definitely made.
Timeline
The following is a timeline of events that lead up to the ALEX hack and afterwards. Each step is further detailed within this article at a later time.
UTC Time
Time from Hack
Event Description
2025-03-03 08:03:31 UTC-95d 0h 24m 38s
ALEX changed their existing self-listing logic to use a contract named self-listing-helper-v3, which uses the clarity-stacks library to ensure permissionless source code verification. From this point on, the protocol was vulnerable to being hacked. The self-listing-helper-v3a version of the contract, which was the one that was exploited, was deployed on the same day as the previous version but a few hours later, and contained only minor code improvements.
2025-06-06 08:20:22 UTC-7m 47s
Attacker initiated an intentionally-failing contract deploy transaction which meets ALEX’s self-service listing verification requirements. The failed-to-be deployed contract was named ssl-labubu-672d3.
2025-06-06 08:20:40 UTC-7m 29s
Attacker deployed a malicious contract with the same name as the failed deployment, ssl-labubu-672d3.
2025-06-06 08:20:59 UTC-7m 10s
Attacker deployed the missing labubu dependency, which caused the intentionally-failing contract deploy to revert.
2025-06-06 08:27:13 UTC-56s
Attacker gained an approved role via a privilege escalation attack on the ALEX’s self-listing service contract, self-listing-helper-v3a, using the failed deployment data and the current malicious ssl-labubu-672d3 contract as input.
2025-06-06 08:27:35 UTC-34s
Malicious mode was activated for the ssl-labubu-672d3 contract.
2025-06-06 08:28:09 UTC0
ALEX Protocol pool funds were stolen via a pool swap-x-for-y call on the amm-pool-v2-01 contract, which leveraged the approved malicious ssl-labubu-672d3 contract. The stolen amounts were: 8,403,867.567554 STX, 50.73942482 aBTC, 12.76470894 sBTC, 119,419,656.0046488 ALEX and 1,748,326.97784601 sUSDT tokens.
2025-06-06 08:29:56 UTC+1m 47s
Attacker started extracting liquidity from the Stacks ecosystem and withdrawing liquidity off-chain. Off-ramping funds was done through a mixture of sBTC withdrawals, bridging and (potential) CEX intermediary transfers.
2025-06-06 09:40:24 UTC+1h 12m 15s
Attacker reconfigures the exploit to only extract STX as opportunistic market participants added 28,613.414357 more STX to the still-vulnerable ALEX Pools.
2025-06-06 09:41:45 UTC+1h 13m 36s
Attacker redoes the exploit, resulting in a further 28,613.414357 STX amount being stolen.
2025-06-06 10:24:39 UTC+1h 56m 30s
The last hacker sBTC withdrawal reaches the attacker's Bitcoin address as BTC for a total amount of 21.85682803 BTC in stolen funds.
2025-06-06 10:44:52 UTC+2h 16m 43s
The last major stolen funds off-ramping (approximate $49.5K) was initiated by the attacker on Stacks.
2025-06-06 11:02:50 UTC+2h 34m 41s
The Brotocol bridge (formerly XLink and ALEX Bridge) governance burned the remaining hacker balances of 34.65082482 aBTC and 580,326.97784601 sUSDT tokens via an emergency governance proposal XIP 166.
2025-06-06 11:06:25 UTC+2h 38m 16s
ALEX Protocol burned the remaining the attacker's ALEX token balance of 100,719,101.4067526 tokens via an emergency ALEX Governance Proposal 517 (AGP).
2025-06-06 11:54:30 UTC+3h 26m 21s
ALEX Protocol disables the vulnerable ssl-labubu-672d3 contract via an emergency ALEX Governance Proposal 519 (AGP).
2025-06-06 14:07:23 UTC+5h 39m 14s
Last confirmed extracted liquidity reaches the attacker's Ethereum holding address as DAI for a total sum of 2,091,544.64940775 DAI in stolen funds
2025-06-06 15:44:00 UTC+7h 15m 51s
ALEX protocol announces the exploit and the compensation plan.
2025-06-07 07:55:26 UTC+23h 27m 17s
Attacker appears to have transferred his last remaining STX (relative) dust amounts to a CEX.
2025-06-07 08:21:11 UTC+23h 53m 2s
Last native ETH liquidity reaches the attacker's holding Ethereum address, most likely from the same hack but via CEX transfers, although not confirmed.
ALEX Protocol Self-Listing Tokens Feature
In order to properly describe how ALEX Protocol’s self listing token feature works, we first need to give some context on how contracts are deployed on the Stacks blockchain.
Deploying Contracts on Stacks
The Stacks blockchain has its own particularities and trade-offs with regard to smart contract development. Of relevance to the current hack is that, in Stacks, deploying a contract is done in its own separate transaction, of type
On EVM-compatible blockchains, a factory type smart contract simply deploys the type of contract that is needed, ensuring full compatibility with the desired behavior. On Stacks, this is inherently not possible. On EVM chains it is also possible to get the compiled code of each contract on-chain, allowing a type of introspection. Smart contract introspection is also currently supported in Clarity, the smart contract language of the Stacks blockchain.
While Clarity does offer traits, which are somewhat analogous to ERC165 in Ethereum, this mechanism only ensures that a Clarity smart contract has specific functions implemented, not what the content of the functions are.
This is relevant because it creates the following dilemma: on Stacks, how does one ensure, from within a smart contract, that another contract is of a specific type, meaning it has a specific source code?
For a long period of time, there was no clear answer to this.
clarity-stacks Library
While there were various attempts over the years at mimicking on-chain contract deployments, there was no definite method found. After the Stacks Nakamoto upgrade went live, the introduction of a new Clarity system function,
Marvin Janssen, a veteran and highly esteemed developer in the Stacks ecosystem, was the first to pioneer this solution and implemented it in his clarity-stacks public goods library. To quote from the repository:
this library allows you to check if a specific transaction has been mined in a Stacks block in Clarity. It is particularly useful to prove if a given contract has a specific code body. Since there is no Clarity function to fetch a transaction nor to read a contract code body, this is the next best thing.
The inability to deploy a contract from an existing contract is sometimes a limiting factor for protocols. Whilst this library does not provide such a feature, it does allow a protocol to accept a contract deployed by a third-party by verifying if the code body is as it expects.
The first version of the
ALEX Self-Service Listing
On 16 July 2024, ALEX Lab Foundation announced their first version of a self-service token listing mechanism that allowed projects to self list their own tokens. It is unclear what mechanism was used at that time, but it is not relevant for the current analysis.
On the 3rd of March 2025, ALEX changed the self-listing logic to use a contract named
How Self-Service Listing Worked
The self-service listing mechanism involved several steps:
1) deploying a wrapper token over an already-existing token contract. The wrapped token contract, or anchor token, is wrapped to ensure compatibility with the ALEX protocol which only supports 8 decimal tokens. By using an intermediary wrapper with a fixed 8 decimal precision, this limitation could be bypassed.
2) taking the deployed token along with the deployment transaction information and other parameters and passing them to the
All wrapped tokens must respect a specific template. The template is stored in the
Deploying Contracts on Stacks
The Stacks blockchain has its own particularities and trade-offs with regard to smart contract development. Of relevance to the current hack is that, in Stacks, deploying a contract is done in its own separate transaction, of type
Contract deploy
. This specific type of transaction cannot be initiated by any existing smart contract, it must be launched by a standard principal (a user with a private key). This is a very different behavior from Ethereum-compatible blockchains, where any smart contract can deploy any another smart contract.On EVM-compatible blockchains, a factory type smart contract simply deploys the type of contract that is needed, ensuring full compatibility with the desired behavior. On Stacks, this is inherently not possible. On EVM chains it is also possible to get the compiled code of each contract on-chain, allowing a type of introspection. Smart contract introspection is also currently supported in Clarity, the smart contract language of the Stacks blockchain.
While Clarity does offer traits, which are somewhat analogous to ERC165 in Ethereum, this mechanism only ensures that a Clarity smart contract has specific functions implemented, not what the content of the functions are.
This is relevant because it creates the following dilemma: on Stacks, how does one ensure, from within a smart contract, that another contract is of a specific type, meaning it has a specific source code?
For a long period of time, there was no clear answer to this.
clarity-stacks Library
While there were various attempts over the years at mimicking on-chain contract deployments, there was no definite method found. After the Stacks Nakamoto upgrade went live, the introduction of a new Clarity system function,
get-stacks-block-info
allowed for a different method of source code verification.get-stacks-block-info
gives information about a specific minted Stacks block, of which of relevance is the header-hash
field. In the calculation of this header hash, for Contract deploy
type transactions, the source code and name of a contract are also included. Thus, by providing these data points on-chain and recreating a specific stacks header, one can verify that a specific contract was included in a transaction in a specific block.Marvin Janssen, a veteran and highly esteemed developer in the Stacks ecosystem, was the first to pioneer this solution and implemented it in his clarity-stacks public goods library. To quote from the repository:
this library allows you to check if a specific transaction has been mined in a Stacks block in Clarity. It is particularly useful to prove if a given contract has a specific code body. Since there is no Clarity function to fetch a transaction nor to read a contract code body, this is the next best thing.
The inability to deploy a contract from an existing contract is sometimes a limiting factor for protocols. Whilst this library does not provide such a feature, it does allow a protocol to accept a contract deployed by a third-party by verifying if the code body is as it expects.
The first version of the
clarity-stacks
library has been available since the 26th of January 2025 for anyone to freely use.
ALEX Self-Service Listing
On 16 July 2024, ALEX Lab Foundation announced their first version of a self-service token listing mechanism that allowed projects to self list their own tokens. It is unclear what mechanism was used at that time, but it is not relevant for the current analysis.
On the 3rd of March 2025, ALEX changed the self-listing logic to use a contract named
self-listing-helper-v3
which uses the clarity-stacks
library to ensure source code verification. The self-listing-helper-v3a
version of the contract, which was the one that was exploited, was deployed on the same day but a few hours later, and contained minor code improvements.
How Self-Service Listing Worked
The self-service listing mechanism involved several steps:
1) deploying a wrapper token over an already-existing token contract. The wrapped token contract, or anchor token, is wrapped to ensure compatibility with the ALEX protocol which only supports 8 decimal tokens. By using an intermediary wrapper with a fixed 8 decimal precision, this limitation could be bypassed.
2) taking the deployed token along with the deployment transaction information and other parameters and passing them to the
create2
function from the self-listing-helper-v3a
contract. This creates a swapping pool for the underlying tokens. During the create2
call, liquidity is also provided by the caller.All wrapped tokens must respect a specific template. The template is stored in the
self-listing-helper-v3a
contract, and the latest version was set via the ALEX Governance Proposal 460. It can be retrieved by calling the get-wrapped-token-contract-code
function.
.png)
Extract from the template where the <WRAPPED_TOKENS> would be added
Attack Overview
Now that we have an understanding on how ALEX self-service listing worked, we’ll go through the hack itself.
From a high-level overview, the attack worked in multiple steps. All steps were carried out by the same standard principal address,
The attack can be separated into 6 high-level steps, which will be detailed moving forward:
1) The attacker initiated an intentionally-failing contract deploy transaction that meets ALEX’s self-listing-helper-v3a contract verification requirements. The contract deployment failed due to a missing dependency
2) The attacker deployed a malicious contract with the same name as the failed deployment
3) Missing
4) The attacker gained a trusted, approved role via a privilege escalation attack on the ALEX’s self-listing service contract
5) Malicious mode was activated for the
6) ALEX pool funds were stolen via a pool swap x-for-y call
The next image depicts the steps in a graphical manner:
From a high-level overview, the attack worked in multiple steps. All steps were carried out by the same standard principal address,
SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M
.The attack can be separated into 6 high-level steps, which will be detailed moving forward:
1) The attacker initiated an intentionally-failing contract deploy transaction that meets ALEX’s self-listing-helper-v3a contract verification requirements. The contract deployment failed due to a missing dependency
2) The attacker deployed a malicious contract with the same name as the failed deployment
3) Missing
labubu
dependency, which made the first deployment fail, was deployed
4) The attacker gained a trusted, approved role via a privilege escalation attack on the ALEX’s self-listing service contract
5) Malicious mode was activated for the
ssl-labubu-672d3
contract
6) ALEX pool funds were stolen via a pool swap x-for-y call
The next image depicts the steps in a graphical manner:

Step 1: The attacker initiated an intentionally-failing contract deploy transaction which meets ALEX’s self-service listing verification requirements
Attacker initiated the deployment of a contract named
- transaction nonce 2: 0x46b3a19665e27b611781f1c14868d0f72eeb468c7a353a87b05329c2a9b49ea9
ssl-labubu-672d3
which failed to deploy, but the transaction itself was minted on the blockchain:- transaction nonce 2: 0x46b3a19665e27b611781f1c14868d0f72eeb468c7a353a87b05329c2a9b49ea9
.png)
As noted in the explorer message, the transaction was minted (included in a block), although it did not succeed. This detail is very important and will be referenced further.
To understand why the deploy failed, we retrieve information with the Hiro details-for-transactions API from the failed transaction:
.png)
As we can see, a virtual machine error (
vm_error
) was encountered that indicated the use of an unresolved contract :0:0: use of unresolved contract 'SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M.labubu'
.
We also see that indeed, the unresolved
SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M.labubu
contract was referenced in the source code of the failed-to-deploy ssl-labubu-672d3
contract.
As simple as it is, the deployment failed because the ALEX wrapper template allows users to wrap any anchor tokens, even non-existing ones, and when the attacker deployed the contract, he ensured that the referenced internal contract,
SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M.labubu
, was not on-chain.
This step was needed in order to have valid transaction data, which would pass ALEX’s
self-listing-helper-v3a
contract verification requirements and can be confirmed via the clarity-stacks
library.Step 2: Attacker deployed a malicious contract with the same name as the failed deployment
The next step for the attacker was to deploy a malicious contract with the same name as the one that failed to deploy in step 1,
- transaction nonce 3: 0xd3f5da0463b6a0216ffb2ebff17bd9ce7cc328710e785d6436d3db1f550b5554
Since previous deployment transaction failed, within the Stacks blockchain the name was not registered, leaving room for the deployment of a new contract with the same name but with arbitrary source code.
The token exfiltration code is linked to the
Note, this was needed because during the pool deployment, in step 4 where the attacker gains elevated privileges, the
Malicious Contract Analysis
A quick analysis of the malicious
The malicious behavior is deactivated at deployment and depends on two data variables:
The role of each variable is as follows:
-
-
ssl-labubu-672d3
.- transaction nonce 3: 0xd3f5da0463b6a0216ffb2ebff17bd9ce7cc328710e785d6436d3db1f550b5554
Since previous deployment transaction failed, within the Stacks blockchain the name was not registered, leaving room for the deployment of a new contract with the same name but with arbitrary source code.
The token exfiltration code is linked to the
SIP-10:transfer
function, but ssl-labubu-672d3
was deployed with all the malicious exfiltration logic deactivated.Note, this was needed because during the pool deployment, in step 4 where the attacker gains elevated privileges, the
ssl-labubu-672d3::transfer
function is executed with the attacker as the caller. Thus having it activated during the verification bypass would have resulted in a failed exploit, as 0 balances of specific tokens would have been attempted to be transferred.Malicious Contract Analysis
A quick analysis of the malicious
ssl-labubu-672d3
contract source code shows that, at initial deployment, the contract behaves as any other wrapper contract.The malicious behavior is deactivated at deployment and depends on two data variables:
enable-farming
and amount-percent
. Both of these can only be changed by the deployer of the contract by calling specific functions set-enable-farming
and set-amount-percent
.The role of each variable is as follows:
-
amount-percent
is a percentage amount, defaulted to 100% equivalent-
enable-farming
is a flag-type variable, defaulted to 0. Different values result in different tokens being stolen from the caller calling the transfer
function. The amount of tokens depends on the amount-percent
flag.
enable-farming
transfer behavior
u0
normal SIP-10 behavior
u1
steal caller’s entire balance of STX tokens
u2
steal caller’s entire balance of aBTC tokens
u3
steal caller’s entire balance of sBTC tokens
u4
steal caller’s entire balance of ALEX tokens
u5
steal caller’s entire balance of sUSDT tokens
u9
steal caller’s entire balance of: STX, aBTC , sBTC, ALEX and sUSDT tokens
Step 3: Missing labubu dependency was deployed
- transaction nonce 4: 0x4005c1b14328370619cb9a43b4005415fad2e8c37317d5d1f520eaf35b9543a9
As the next step, the attacker deployed the missing
The source code of the
As the next step, the attacker deployed the missing
SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M.labubu
contract, which caused the initial deployment. This step is required in ALEX’s on-chain self-listing verification.The source code of the
labubu
contract indicates that it is a version of the malicious ssl-labubu-672d3
contract codebase but stripped of any exfiltration capabilities.Step 4: Attacker gained approved role via a privilege escalation attack on the ALEX’s self-listing service contract
- transaction nonce 5: 0xfb4822786771285238e082f46bee1203d9ccb9cedfd1b3e6e574a4908d53474f
The
Users who wanted to permissionlessly deploy a pool for an existing
The Self-lister contract does a multitude of input verification when attempting to list a
The
self-listing-helper-v3a
contract allows the permissionless creation of pools with self-deployed tokens via the create2
function.Users who wanted to permissionlessly deploy a pool for an existing
Y
, would first need to wrap it using their specific wrapping template — say, token Y-Wrapped
— and then provide these as inputs to the create2
function, alongside other information.The Self-lister contract does a multitude of input verification when attempting to list a
X-to-Y
pool. Of relevance to the attack and how the hacker bypassed them, follows:Verification on creating a X-to-Y pool
Attacker bypass/input
Verifies that the X paired token is only of the already approved tokens by the project (e.g. wSTX, ALEX, aBTC)
The attacker passed the ALEX's wSTX token
Verify that the Y paired token is a wrapper contract, that matches their specific source code template.
The check is done via blockchain transaction deployment proofs using the clarity-stacks library
The check is done via blockchain transaction deployment proofs using the clarity-stacks library
The attacker cleverly bypasses this by providing the failed transaction in Step 1, which passes the check, since there is no validation if the transaction actually succeeded.
Ensures that the underlying wrapped token, or anchor token, from the wrapper Y contract exists.
This check is implicitly done when validating the wrapper source code.
This check is implicitly done when validating the wrapper source code.
The attacker ensured this would pass by deploying the labubu token contract in Step 3.
The check is done when the get-wrapped-token-contract-code function is called from the verify-deploy function.
The check is done when the get-wrapped-token-contract-code function is called from the verify-deploy function.
Sanity checks on the provided pool configurations and liquidity requirements
The attacker ensured he passed valid inputs and had the underlying ssl-labubu-672d3 tokens to provide the initial pool liquidity amount.
Attacker made a pool with:
- 2000 wSTX as liquidity for the X token
- 100,000 labubu (ssl-labubu-672d3) tokens as liquidity for Y token
Attacker made a pool with:
- 2000 wSTX as liquidity for the X token
- 100,000 labubu (ssl-labubu-672d3) tokens as liquidity for Y token
The end result of passing the
As an observation, Step 2 and Step 3 could have been in reverse, as their order does not matter to the hack. The only hard requirements were that Step 1 be done first, and the first 3 steps be done before the 4th step, which is the privilege escalation.
create2
call is that the current ssl-labubu-672d3
malicious contract, deployed in Stage 2, is treated as how a wrapped token would be, and integrated into the internal pool logic of ALEX’s swap pools.As an observation, Step 2 and Step 3 could have been in reverse, as their order does not matter to the hack. The only hard requirements were that Step 1 be done first, and the first 3 steps be done before the 4th step, which is the privilege escalation.
Step 5: Malicious mode was activated for the ssl-labubu-672d3 contract
- transaction nonce 6: 0x5069e8aec07f766bba28b27fa6e8399019ba6f41e408640c4327933b29239703
The malicious exfiltration logic is only reachable during a SIP-10
After the successful verification bypass, the attacker calls the
The malicious exfiltration logic is only reachable during a SIP-10
ssl-labubu-672d3::transfer
call. During the privilege escalation (Step 4), the transfer
function was called on the ssl-labubu-672d3
contract to move the initial liquidity for the pool; as such, the attacker needed to have the malicious logic deactivated at that time.After the successful verification bypass, the attacker calls the
ssl-labubu-672d3::set-enable-farming
function with a flag:9
, which activates the malicious behavior on any further transfer
calls.Step 6: ALEX pool funds were stolen via a pool swap x-for-y call
- transaction nonce 7: 0xe8b2ac705dcbb35d487a4efd7a0fe384bbad1d1d97ea970410ad82a3cd0d9daf
At this point, all prerequirements for the hack were reached, and the attacker can now initiate the theft via a
As intended, the ALEX pool contract behaved as if both the swap tokens were wrapped, approved, versions.
The attacker intentionally initiated a swap of
The following diagram shows the execution flow through the ALEX AMM pool up to the point where the malicious token exaction is executed.
At this point, all prerequirements for the hack were reached, and the attacker can now initiate the theft via a
amm-pool-v2-01::swap-x-for-y
call.As intended, the ALEX pool contract behaved as if both the swap tokens were wrapped, approved, versions.
The attacker intentionally initiated a swap of
X
tokens (wSTX
) to Y
tokens (labubub (ssl-labubu-672d3)
) so that the implementation logic needed to withdraw tokens from the ALEX pool vault. This allowed the malicious token direct access to all tokens present in the pool vault.The following diagram shows the execution flow through the ALEX AMM pool up to the point where the malicious token exaction is executed.

At the end of this 6th step, the attacker has stolen the following amounts:
8,403,867.567554 STX,
50.73942482 aBTC,
12.76470894 sBTC,
119,419,656.0046488 ALEX,
1,748,326.97784601 sUSDT
Hack aftermath, funds flow, and a second exfiltration
After hacking the ALEX pool, the attacker initiated a series of swaps and transfers in an attempt to off-ramp the stolen tokens. While a full off-chain token tracking is out of the scope of this article, we will showcase, to the best of our extent, how funds flow accrued after the hack, including a subsequent re-hack of the same pool with the same exploit from the same attacker.
Funds Flow
Initial stolen funds were held in the
8,403,867.567554
Funds Flow
Initial stolen funds were held in the
SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M
and were:8,403,867.567554
STX
; 50.73942482 aBTC
; 12.76470894 sBTC
; 119,419,656.0046488 ALEX
; 1,748,326.97784601 sUSDT
To note, out of the stolen funds, aBTC and sUSDT are tokens issued by the ALEX Bridge (formerly known). Over time the bridge was transitioned to XLink and now Brotocol. Since the Brotocol bridge and the ALEX Foundation share a tight connection, the attacker tried to act quickly to not be blocked by the team.
There were 3 Stacks addresses in total used in the hack:
- SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M
- SP174BBVTRQSE3YAMBKD5NKG03TMDQSY6ZMJT14J6
- SP1SNT6GK28RWFHDZEQ4510MDC80XH2DANN553KZ4
There were also two EVM addresses and a Bitcoin address where the funds were transferred to:
- 0xe8a2cb2bfc0a1a716c43ab9fd5862c59e0ad76fd
- 0x6b696b3bfbcce8871408b02c2c851d6437908b6b
- 1A6obMMuvGs7HvZn9pZ2y7bVzxcTtUpyDM
There were 3 Stacks addresses in total used in the hack:
- SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M
- SP174BBVTRQSE3YAMBKD5NKG03TMDQSY6ZMJT14J6
- SP1SNT6GK28RWFHDZEQ4510MDC80XH2DANN553KZ4
There were also two EVM addresses and a Bitcoin address where the funds were transferred to:
- 0xe8a2cb2bfc0a1a716c43ab9fd5862c59e0ad76fd
- 0x6b696b3bfbcce8871408b02c2c851d6437908b6b
- 1A6obMMuvGs7HvZn9pZ2y7bVzxcTtUpyDM
Each address that was used in the hack had a different role, which we will briefly touch on:
SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M
- Deployed the initial malicious contract and initiated the token theft
- Swapped several large amounts of STX to Allbridge USDC aeUSDC and then transferred them to SP1SNT6GK28RWFHDZEQ4510MDC80XH2DANN553KZ4 (nonces 8, 10, 23-34, 44, 46-53)
- Also transferred all 50.73942482 aBTC tokens to SP174BBVTRQSE3YAMBKD5NKG03TMDQSY6ZMJT14J6 (nonce 15)
- Transferred 1,000,000 STX and all 119,419,656.0046488 ALEX tokens to SP174BBVTRQSE3YAMBKD5NKG03TMDQSY6ZMJT14J6 (nonces 13, 14)
- Initiated the bridging of sUSDT to multiple EVM chains, to 0xe8a2cb2bfc0a1a716c43ab9fd5862c59e0ad76fd, with varying degrees of success:
- bridged 50,000 sUSDT to Ethereum successfully (nonce: 16 on Stacks)
- bridged 38,000 sUSDT to BSC successfully (nonce 17 on Stacks)
- bridged 26,000 sUSDT to Base successfully (nonce 18 on Stacks)
- bridged 21,000 sUSDT to Arbitrum successfully (nonce 19 on Stacks)
- bridged 15,000 sUSDT to Avalanche C-Chain successfully (nonce 20 on Stacks)
- Initiates a bridging of 500,000 sUSDT to Ethereum (nonce 21 on Stacks) but the bridge did not fulfill the withdrawal
- Initiates a bridging of 18,000 sUSDT to Ethereum (nonce 40 on Stacks), but the bridge did not fulfill the withdrawal
- At this point, the remaining 58,0326.97784601 aUSDT tokens were burned by the Brotocol bridge through an emergency governance proposal, XIP 166
- The address initiated what appear to be CEX-like deposits with the following STX amounts:
- Transfer 20,000 STX to SP3ZBPG1F4ZCAZGEAZAA8MVGB605F095ACC376A0R (nonce 36)
- Transfer 50,000 STX to SP1EXWN15C7DCK7CMPWTR9JT6WJ49Y835DQ9BDSJG (nonce 41)
- Transfer 20,000 STX to SP2WCSP0YZ1BVRDP1TGXA5EHRRTJ27BW4SC3TXZPC (nonce 42)
- Transfer 20,000 STX to SP39JYAZR0ZGJ23VVVSM8ED11HF7E9N9SGDM7A62K (nonce 43)
- Transfer 20,000 STX to SPFQCE33T0P2C9DMHC6E098R436512J7RJBP1ZHD (nonce 45)
- Transfer 20,000 STX to SP17CMV5Q8GXTCFHNQCRA6Q1VH9KBQEK9P8654XJ1 (nonce 50)
- Transfer 2,958.359295 STX to SP2SGH71X3M379CMQKQ3WN5PSVDY7J7KTX6EWPWBE (nonce 55) - Cumulatively in 3 transactions (nonce 9, 12 and 22), the address also withdrew 21.85682803 sBTC in total to the 1A6obMMuvGs7HvZn9pZ2y7bVzxcTtUpyDM
- This address was responsible for initiating the bridging of all received aeUSDC to the 0xe8a2cb2bfc0a1a716c43ab9fd5862c59e0ad76fd address on Ethereum and extracting liquidity from the aBTC token
- Bridging received aeUSDC succeeded and can be seen on ERC20 transfers from the Allbridge on the receiving address
- There were multiple attempts at bridging 16.0886 aBTC, of which only 2 attempts were successful with a cumulated withdrawal of 1.8 BTC to EVM chains:
- 0.6 aBTC to Arbitrum (nonce 5 on Stacks)
- 1.2 aBTC to BSC (nonce 2 on Stacks) - The remaining 34.65082482 aBTC was at this point burned by the Brotocol bridge through an emergency governance proposal, XIP 166, which also burned 58,0326.97784601 aUSDT tokens
- This address received all the 119,419,656.00464880 ALEX tokens and 1,000,000 STX in order to extract liquidity from it
- Swapped 500,000 STX for 69,576.690635 USDA on Arkadiko (nonce 3) and then proceeded to swap the resulting USDA for 67,213.993504 aeUSDC (nonce 5) which it then sent to SP1SNT6GK28RWFHDZEQ4510MDC80XH2DANN553KZ4 for bridging (nonce 8)
- Attempted to supply the entire 119,419,656.00464880 ALEX amount into Zest so they could then borrow against it to extract liquidity from Zest while the hack itself was not yet priced-in (nonce 9)
- The Zest team was already aware of the hack by this time and had reduced both borrowing cap and supplying cap for the ALEX token through a series of emergency governance proposals, to protect user funds.
- The attacker, however, did manage to supply 17,700,554.5978962 ALEX tokens (nonce 10 and 11), which is only 14.8% of the stolen ALEX tokens
- With this collateral, the attacker borrowed 1.86533972 sBTC (nonce 13) and sent it to SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M for extraction - The remaining 500,000 STX of the initially sent million was sent back to SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M to be extracted using a different method
- At this point, the leftover 100719101.4067526 ALEX tokens, which the hacker didn’t off-ramp yet, were burned by an emergency ALEX Governance Proposal 517 (AGP)
- All stolen funds that were extract through the bridges (either through the Allbridge or the Brotocol bridge) were moved from all intermediary chains (BSC, Avalance, Arbitrum, Base) to Ethereum via Stargate
- There were also several native ETH deposits that seem to be connected to the hack, although not confirmed
- On Ethereum, all received stablecoins were converted into DAI tokens and then sent to 0x6b696b3bfbcce8871408b02c2c851d6437908b6b
- Besides Tornado.Cash, this address received native ETH from other sources, which may indicate which CEX-like service the attacker used on Stacks to bridge tokens
- ChangeNow (changenow.io) https://etherscan.io/tx/0x2f677a051306e38e7b394a2d26d1296ab0da1f366d1356c077f7c728df0cb4b1
- SideShift (sideshift.ai) https://etherscan.io/tx/0xa7da2e9c692a46efb85803de881bc9696d3d7d2b6588271eccd502b58514035c
- Union Chain (unionchain.ai) https://etherscan.io/tx/0x441e273bc2347ad7caa60369626339eb92d7714126f2fad5852770d7facde871
- This is the address where the attacker currently holds the EVM bridged stolen funds
- At the moment of writing this article, the address had almost 120 ETH worth $286,381.64 and 2,091,544.64940775 DAI
.png)
Note: it is unclear if all the native ETH deposits come from the ALEX hack, as the amounts are not fully consistent with unaccounted Stacks outflows.
- contains the withdrawn sBTC from the hack, a total of 22.84899662 BTC
- 21.85682803 BTC from the address are accounted via sBTC withdrawals.
- the account’s 3rd and transfer which added 1 BTC, seems unrelated to the current hack

A Second Hack and Theft
After the initial attack, while the threat actor was moving funds, the still-vulnerable ALEX Pools were gaining liquidity, most likely due to MEV Bots arbitraging the sudden change in market prices.
The original attacker (SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M) observed the added liquidity and redid the initial exploit as follows:
- the ssl-labubu-672d3 malicious contract was set to mode 1, which only exfiltrates STX(nonce 38)
- the swap-x-to-y function was again called, to trigger the exploit (nonce 39) which resulted in the additional theft of 28,613.414357 STX tokens
Note: this amount was already included in the amounts transferred breakdowns from the fund flow.
Resolving the Issue: Future Plans
After the hack, a warning was added to the clarity-stacks library, to ensure future integrators are aware of its limitation, and the Stacks development ecosystem started brainstorming a viable mechanism that would mitigate the attack vector.
The conclusion is that the attack vector can be completely blocked if there is a guaranteed way of retrieving the source code of a correctly-deployed smart contract on-chain. To that end, the solution presented by Marvin in clarity-lang:Issue 88 will most likely be the implemented one. Regardless of what solution will be adopted, the Stacks development team will make this attack vector unusable in Clarity 4.
The conclusion is that the attack vector can be completely blocked if there is a guaranteed way of retrieving the source code of a correctly-deployed smart contract on-chain. To that end, the solution presented by Marvin in clarity-lang:Issue 88 will most likely be the implemented one. Regardless of what solution will be adopted, the Stacks development team will make this attack vector unusable in Clarity 4.
Conclusion
The ALEX Self-Service Listing hack was a recent blow to the Stacks ecosystem that resulted in millions of dollars worth of funds being stolen.
The attack required deep knowledge of the Stacks ecosystem and the state of DeFi. The complexity of the attack can arguably make it one of, if it not the most complicated, hack on Stacks.
Besides the technical details themselves, the attacker then orchestrated a carefully thought-out off-ramping, which involved many key protocols of the ecosystem. Knowledge of those protocols and the execution of it all show that attackers are very carefully watching Stacks for any opportunity.
ALEX Foundation has shown tremendous resilience in the face of adversity, which we applaud, and we hope to see them recover and grow far beyond what they were pre-hack.
The ALEX self-listing functionality was audited only by one security firm (not Clarity Alliance), and they did not identify the vulnerability. As a smart contract security firm, a question that naturally comes up after a hack like this is, "Would Clarity Alliance have found the vulnerability?" The honest answer is that we don't know. In retrospect, all hacks are easy to identify once everything is laid out clearly. However, we can say with certainty that more scrutiny on any given codebase or protocol will always yield more insights and findings, gradually increasing security.
It is reassuring to see that the Stacks development community is already working on concrete solutions to ensure that this specific attack vector will be closed off entirely in Clarity 4 and beyond.
It has been said before, and we will say it again: security is a process, not a checklist, and we are here to make Stacks as secure as possible.
The attack required deep knowledge of the Stacks ecosystem and the state of DeFi. The complexity of the attack can arguably make it one of, if it not the most complicated, hack on Stacks.
Besides the technical details themselves, the attacker then orchestrated a carefully thought-out off-ramping, which involved many key protocols of the ecosystem. Knowledge of those protocols and the execution of it all show that attackers are very carefully watching Stacks for any opportunity.
ALEX Foundation has shown tremendous resilience in the face of adversity, which we applaud, and we hope to see them recover and grow far beyond what they were pre-hack.
The ALEX self-listing functionality was audited only by one security firm (not Clarity Alliance), and they did not identify the vulnerability. As a smart contract security firm, a question that naturally comes up after a hack like this is, "Would Clarity Alliance have found the vulnerability?" The honest answer is that we don't know. In retrospect, all hacks are easy to identify once everything is laid out clearly. However, we can say with certainty that more scrutiny on any given codebase or protocol will always yield more insights and findings, gradually increasing security.
It is reassuring to see that the Stacks development community is already working on concrete solutions to ensure that this specific attack vector will be closed off entirely in Clarity 4 and beyond.
It has been said before, and we will say it again: security is a process, not a checklist, and we are here to make Stacks as secure as possible.
Indicator-Of-Compromise (IOCs)
Attacker Addresses
Stacks SP2VCNXGRZCBTP8E9MQ6DJPFVXRBPWBN63FE06A1M Main hack entry point
Stacks SP174BBVTRQSE3YAMBKD5NKG03TMDQSY6ZMJT14J6 Stolen funds off-ramping
Stacks SP1SNT6GK28RWFHDZEQ4510MDC80XH2DANN553KZ4 Stolen funds off-ramping
EVM 0xe8a2cb2bfc0a1a716c43ab9fd5862c59e0ad76fd Stolen funds aggregation
EVM 0x6b696b3bfbcce8871408b02c2c851d6437908b6b Stolen funds currently held
Bitcoin 1A6obMMuvGs7HvZn9pZ2y7bVzxcTtUpyDM Stolen funds currently held
Stacks SP3ZBPG1F4ZCAZGEAZAA8MVGB605F095ACC376A0R Possible CEX address
Stacks SP1EXWN15C7DCK7CMPWTR9JT6WJ49Y835DQ9BDSJG Possible CEX address
Stacks SP2WCSP0YZ1BVRDP1TGXA5EHRRTJ27BW4SC3TXZPC Possible CEX address
Stacks SP39JYAZR0ZGJ23VVVSM8ED11HF7E9N9SGDM7A62K Possible CEX address
Stacks SPFQCE33T0P2C9DMHC6E098R436512J7RJBP1ZHD Possible CEX address
Stacks SP17CMV5Q8GXTCFHNQCRA6Q1VH9KBQEK9P8654XJ1 Possible CEX address
Stacks SP2SGH71X3M379CMQKQ3WN5PSVDY7J7KTX6EWPWBE Possible CEX address
Relevant Transactions
- Privilege escalation: https://explorer.hiro.so/txid/0xfb4822786771285238e082f46bee1203d9ccb9cedfd1b3e6e574a4908d53474f?chain=mainnet
- First hack TX: https://explorer.hiro.so/txid/0xe8b2ac705dcbb35d487a4efd7a0fe384bbad1d1d97ea970410ad82a3cd0d9daf?chain=mainnet
- Second hack TX: https://explorer.hiro.so/txid/0xe74617ae98bc675b882c863dfc99166dc4c5aad4cb24d11777f2ac9f48414ee2?chain=mainnet