TibetSwap V2 - Post-Mortem

On August 24, 2026, we confirmed a critical bug in the TibetSwap v2 puzzles. The bug was ethically disclosed by Eal. Nearly all protocol funds were recovered the same night. A small remainder was taken by a third party and returned two days later. This post covers the bug, the rescue operation, what our security process did and did not catch, and what happens next.
The Bug
The core issue was located in swap.clsp. The puzzle correctly required one reserve to increase and the other to decrease, but it never required the user-supplied input amount to be positive.
In Uniswap v1/v2 math, a negative amount describes the reversed trade. It is the equivalent of saying, “I will give you -1 SBX if you give me -1 XCH” instead of, “I will give you 1 XCH if you give me 1 SBX.” However, the sign of the 0.7% trade fee is also reversed. Repeated against the same pair (and aided by flash loans), this drains the reserves, as the trading fee gives more value to the party conducting the swap than what was put in. The fix is to add a (> amount 0) assertion in the swap path for both standard and rCAT pairs.
Security
TibetSwap is a fully on-chain, decentralized protocol. Because the protocol cannot be paused or upgraded, security was treated as a priority from early testnet onward. After a bug was responsibly disclosed in v1, the v2 code was reviewed by the researcher who reported it. We also opened a community-funded security pot for bounty payouts and published extra documentation on the architecture of Chia’s first AMM.
I personally asked every Chialisp reviewer in the community I could reach to look at the code. The last full human review took place on 5-14 May 2023, when Bram went through the Chialisp and the drivers after the v1 incident.
We received two review reports from Chia Network, Inc. generated by their custom in-house AI security harness/scanner. The first one was received 4 months before the incident, on 23 April 2026. The second one was received less than 3 months before the incident, on 5 June 2026, after improvements were made to the system. Each report was screened immediately (within minutes) for high-impact findings and then read in full. Neither flagged this bug or anything in the same class.
Bundle Security
The rescue presented a tricky decision. Eal had already used an AI-generated proof of concept on one mainnet pair. However, having been entirely AI-generated, the code could prove to be unreliable. It worked once, and we were ultimately not comfortable pointing it at the rest of the TVL. Speed mattered, as the drain transaction was already visible on mainnet. At the same time, accuracy also mattered, as a bad spend could brick funds and thus prevent any eventual return to the rightful owners.
We took a cautious path that could still move quickly. We built a rescue tool from scratch, informed by Eal’s proof of concept, with two independent safety layers. First, each bundle included a security coin. That coin asserted the intended spends and destinations, blocking a third party from using replace-by-fee to redirect the funds. This pattern is extensively used by warp.green, the reward distributor, and XCHandles. It has been previously discussed with ecosystem contributors, and helpers were already integrated (by yakuhito) into chia-wallet-sdk. Second, Sage was used to create offers that would be used to request the rescued funds. While security coins partly depend on the underlying drivers to fully secure a bundle, the Sage offer logic was an independent check that has been thoroughly tested by now. Together, these checks gave us confidence that a broadcast bundle would deliver funds only to the recovery wallets.
Implementing the new tool was only possible because we had a significant part of driver code developed for an unreleased aggregator. This code was already able to parse and spend TibetSwap v2 pairs and had working simulator tests. The final tool was also tested through unit tests, full simulator runs, as well as rescues on smaller TVL pairs before being used on the biggest pairs of the protocol.
Timeline
This section contains the reconstructed timeline of major events. Times are UTC+3 (Romania). The rescue was complex, so this section is longer than that of a typical post-mortem.
- 24 August 2026, 17:56 UTC+3 - Eal messaged me (yakuhito) on Discord, describing a bug found by Daybreak Blue (OpenAI’s cybersecurity initiative model) with only one prompt. He mentioned that he does not know Chialisp well enough to validate it, but was able to use the AI-generated PoC code to remove all the liquidity of an XCH-PIZZA pair.
- 18:06 - I acknowledged the message and started analyzing the TibetSwap code.
- 18:11 - Eal clarified that he used the PoC on the mainnet XCH-PIZZA pair, sending an explorer link. I quickly confirmed the reserves were indeed drained on-chain, and paused the analytics service.
- 18:13 - A war room was created with maxim_goods (Bram - Senior Security Engineer at Chia Network, Inc.) and jde5011 (Justin - VP of Security at Chia Network, Inc.). They have extensive experience and have previously assisted with the v1 vulnerability.
- 18:18 - I asked Eal if we can upgrade to Keybase.
- 18:20 - I confirmed Eal’s account on Keybase and a separate group with him, Bram, and Justin was created.
- 18:26 - Common understanding: bug was found with only one prompt to
gpt-daybreak-blue-latest, which Eal prompted after the recent warp[.]green incident. Justin recommended we follow the course of action that “makes sense from a stewardship perspective.” We agreed that asking users to withdraw everything publicly would draw a lot of attention. - 18:32 - Bram pointed out that the exploit is visible on mainnet due to the XCH-PIZZA drain, so the time to conduct a white hat rescue is very limited. I confirmed the core exploit worked on paper. Code from TibetSwap’s unreleased trade aggregator can be used as a base for a Rust-based rescue tool.
- 18:36 - Eal sent the PoC code he used. The conversation moved to the war room to coordinate rescue.
- 18:56 - General-purpose models refused to help build a rescue tool due to safety concerns. Bram suggested using GLM-5.2 and Kimi K2, which did not refuse any prompts.
- 19:02 - Development of the rescue tool had started. Given the time-sensitive nature of the operation, we adopted (at Bram’s suggestion) a hard deadline of 3 hours. If the rescue tool was not ready by then, Eal’s PoC code would be used to rescue funds.
- 19:17 - Parallel to the rescue tool development process, I started developing a monitoring tool that would alert me in the case of incoming attacks on TibetSwap at Bram’s suggestion.
- 19:36 - The monitoring tool went online, and I started setting up the PoC code.
- 19:56 - The PoC code setup was finished. If any pair was drained, I was ready to use the PoC at a moment’s notice to recover as many assets as possible.
- 20:08 - The preliminary rescue tool was ready, and I started establishing validation criteria. The tool would be run on a simulator mirroring the current protocol state. It would be tested on one pair only, then as many pairs as possible at a time. Validation would target low-TVL pairs until we were very confident the rescue tool worked - after all, we would prioritize pairs with high TVL.
- 20:34 - A first-pass human & AI-assisted review of the rescue tool was done. A 2nd layer of security would be added through offers. rCAT support was postponed, as all rCAT pairs contained <1% of the TVL at risk (~1123 XCH). More reviews and simulator testing were planned.
- 21:50 - A rescue transaction on a single pair was successfully confirmed on mainnet.
- 22:03 - First confirmation of a multi-pair rescue.
- 22:13 - Multiple confirmations that the multi-pair rescue worked. We were confident the rescue tool worked.
- 22:15 - After final checks, the first high-value-pair bundle was in the mempool. We had gone from the first report to the first high-TVL rescue transaction in under 4 hours and 20 minutes.
- 22:16 - We confirmed that >$160,000 out of the $200,000 TVL had been rescued through the first transaction through multiple avenues. The rescue process would continue for all pairs, ordered by TVL.
- 22:31 - I updated Eal that over 80% of the funds at risk had been rescued. I also thanked him for reporting the vulnerability.
- 22:45 - Over 216 out of 367 pairs were rescued, and rCAT support was in progress.
- 23:36 - Rescue operation continued to progress. A draft for a post on X was ready.
- 25 August 2026, 01:07 - A different strategy was used for rCAT pairs. The funds from all but one had been recovered. I was working on rescuing the last pair, which needed a different transaction structure given its very low fee.
- 01:22 - We posted that we believed all 367 pairs had been rescued in under 7 hours and 30 minutes after the initial report.
- 03:04 - An on-chain check revealed that funds corresponding to 28 pairs had not landed in our recovery wallets. About 151.8 XCH plus the paired tokens, under 0.2% of TVL and roughly $500, had gone to
xch152qs7dx8q47udq8tyzljju60kkyuhvww2htczaj4fz32u4pa38ksqy9ap8. I flagged the address for investigation. - 18:45 - I confirmed the address was not one of mine. Eal had also just confirmed it was not his. The working theory is that someone replayed the method from a public rescue spend and drained pairs we had not yet swept. A forensic investigation began.
- 26 August 2026, 13:55 - We announced the finding on X. I intended to cover the 151.8 XCH side of the loss using previously obtained dev fees.
- 17:23 - The unknown address returned the funds in full, which we announced here. The ongoing forensic investigation, which had already advanced quite far, was stopped.
Moving Forward
Current AI model capability means on-chain projects have to spend more effort on security than the last few years required. Given our experiences, we believe at least the following items should be considered:
- Regular AI audits, both done by 3rd parties and performed in-house using the latest models. Projects should re-audit as soon as a new capable model is available. This means watching new model releases and getting into as many vetted defensive-access programs as possible.
- Well-advertised bug bounty programs, which security researchers can easily find should they identify a bug first. Terms should be public, and the process should ideally run through a third party.
- Monitoring to quickly notify the team of live exploit attempts.
We have announced a plan to distribute recovered funds at the same time as this post. Pending any change of plans, all funds should be returned to their owners by September 19, 2026.
Following this incident, TibetSwap will not be re-launching on Chia at this time. A reflection and a record of the history of the protocol can be found here.
After the rescue, splitXCH shared Fable 5 security scans, one of which found a separate issue in the TibetSwap code. It was not exploited, and it will be described in a note inside the tibet repository. I thank him for his help.
The tibet repository will soon be updated with a note that includes a link to this post, a description of the known vulnerabilities in the code, and fix suggestions. Following this update, all tibet-related repositories will be archived.
Thanks
A massive thank you to Eal for not only thinking to audit the code for the good of the community, but also responsibly disclosing it. Until October 1st, donations will be collected to add to the security-pot XCH and the latest batch of dev fees for the bounty. I hope the community’s thanks, and the bounty we put together, make it obvious that reporting bugs this way is the right way to go.
Second, thank you to Justin and Bram, as well as the broader Chia Network, Inc., for always being there during hard moments like these.
Lastly, thank you to the community, which has once again shown unwavering support when it mattered most. Thank you.
yakuhito, over.
