Security testing
How we test the contracts, what each test covered, and a test you can run yourself.
Every change to the contracts or the app runs the contract test suites first. On top of that we attack the contracts on purpose, and we publish what we tested so you can check it rather than take our word for it.
Red-team test, 2 November 2026
We ran kaspa-redteam, an open-source tool by Kaspero Labs, against 16 transactions of the live mainnet contracts. The tool takes a valid transaction, changes it the way an attacker would, and asks Kaspa’s own consensus code (rusty-kaspa 2.1.0) whether the changed transaction would be accepted. A finding means consensus accepted a change it should have refused.
| What was attacked | Transactions |
|---|---|
| Curve buys and sells | 2 |
| Pool buys and sells, and a liquidity withdrawal | 4 |
| Creator fee claims, from a curve and from a pool | 2 |
| Token lock releases: one release, two at once, the last one, all at the end, after a waiting period, 100 releases, at a high network fee | 8 |
The transactions were built by the same transaction builder the app uses for your trades, with throwaway test keys and made-up coins, so they can never be broadcast. Their contract programs are the live ones: the pack checks each one against our public SDK on npm and, for the lock, against a real mainnet lock release read from api.kaspa.org.
What it found
| Attack | Result |
|---|---|
| Send a payout to the attacker | Refused on every transaction |
| Pay a payout less, or shorten a later one | Refused on every transaction |
| Two contract coins share one set of payouts | Refused on every transaction |
| Put an attacker’s coin in front of the contract | Refused on every transaction |
| Send the contract’s value to the miner | Refused on every transaction |
| Keep what is left over | Flagged, explained below |
- Trades and fee claims: the “leftover” is the network fee, paid from the sender’s own wallet coin. The tool counts that coin as the attacker’s, so the attacker only keeps their own fee.
- Lock releases: anyone may send a due release, and each release may spend up to 0.2 KAS of the lock’s deposit on its network fee; whoever sends it may keep what the fee does not use. The tokens and 1 KAS always go to the beneficiary. This is known, shown on the lock’s Review screen, and kept on purpose: it lets anyone, not only Kasseal, send a release (see Token locks).
No new issue was found.
Run it yourself
Download the test pack. It holds a step-by-step README, the 16 transactions (no private keys), the script that checks which contracts they spend, a script that runs the whole test, and our exact output to compare with yours. You need git, Rust 1.94 or later and Node 22 or later.
- Build kaspa-redteam at the version we ran, commit
eaa79c890a4fc00aa6c8ac12a1208aa8e6d6d23f(v0.15.0). - Run
node check-contracts.mjs baselines/*.json: it must end with “Every contract input is a mainnet program.” - Run the tool on each file,
kaspa-redteam --baseline baselines/pool.json -vand so on, and compare withexpected/.
./run.sh in the pack does all three.
What this test does not cover
The tool cannot yet test transactions that create a new contract (a launch, a graduation, a pool’s setup, a lock’s creation), transactions where your signature sits inside the token program’s data (adding liquidity, splitting a holding), or a lock extension, which only its beneficiary can sign. Our own tests cover these: the contract test suites on every change, a mutation fuzzer of the curve and pool (19 October 2026) and a stress test of the locks (29 October 2026).