{"$schema":"https://projectx.invalid/schemas/ctf-manifest-v1.json","version":1,"name":"ProjectX Capture the Flag","description":"Challenges reproducing real audit findings from ProjectX v1.0, against a retired mainnet deployment holding no user funds.","website":"https://projectxprotocol.dev/ctf","scope":{"inScope":["The retired v1.0 package and pool listed above, and the objects they own.","The v1.0 Move logic: deposits, withdrawals, the draw, settlement, the oracle breaker.","Anything you can make true on chain by calling those contracts from your own wallet."],"outOfScope":["The live v1.0.1 pool and its treasury. Findings there are real — disclose, do not exploit.","Any wallet or address that is not yours, on any network.","Any deployment other than the retired v1.0 range named on this page.","The daemon, the read API, this website, and any RPC provider — infrastructure, not protocol.","Social engineering, phishing, and denial-of-service against shared services."],"outOfScopeAddresses":[{"id":"0x0742576b87852b237ac688dd25ad7e390a30d8ff0c6a34666afa8d0d374766c9","label":"Live v1.0.1 pool","reason":"Holds real user deposits. Findings here are real vulnerabilities — disclose privately, do not exploit."}],"disclosure":"https://projectxprotocol.dev/security"},"target":{"configured":true,"network":"Sui mainnet","label":"ProjectX v1.0 · retired in-situ deployment","packageId":"0xe338cb78badd67607b64c62661534572248a23500503c7e65f56bdba68e71952","poolId":"0x88cb9ac81e1ead1cc5cba24c69732044c835af2a8b4733f24180b50534b0fcd2","rpcUrl":"https://fullnode.mainnet.sui.io","explorerBaseUrl":"https://suiscan.xyz/mainnet"},"scoring":{"totalPoints":2700,"challengeCount":7,"flagFormat":"A transaction digest on the target network demonstrating the objective, plus a one-paragraph explanation of the mechanism.","submission":"https://projectxprotocol.dev/community"},"challenges":[{"id":"late-ticket","title":"The late ticket","finding":"F-02","category":"Access control","difficulty":"Warm-up","points":100,"premise":"v1.0 gated draw eligibility on a wall-clock timestamp. A deposit made in the closing seconds of an epoch was eligible for that epoch’s draw — a prize it contributed nothing to funding.","objective":"Win an epoch with principal that entered after that epoch’s yield was already earned."},{"id":"missing-gate","title":"The missing gate","finding":"F-04","category":"Access control","difficulty":"Warm-up","points":100,"premise":"Every governance entry point checked an object version before acting — except one. The treasury sweep path shipped without the guard the others all had.","objective":"Reach the sweep path on a treasury whose version the other entry points would have rejected."},{"id":"one-mist","title":"One MIST","finding":"F-16","category":"Economic","difficulty":"Standard","points":250,"premise":"Prize funding is permissionless and unbounded below. The rollover safety valve only triggers when the prize is exactly zero — so a single MIST of funding commits the pool to a full settlement cycle it may be unable to complete.","objective":"Drive the pool into its settlement phase for a prize too small to clear the circuit breaker’s floor."},{"id":"long-loop","title":"The long loop","finding":"F-06","category":"Resource","difficulty":"Standard","points":250,"premise":"The harvest iterates every stake object the pool holds. v1.0 placed no ceiling on how many there could be, so the loop’s gas cost was attacker-influenced and unbounded.","objective":"Make the pool hold enough stake objects that a harvest cannot complete within a block’s gas."},{"id":"settlers-spread","title":"The settler’s spread","finding":"F-03","category":"Oracle & MEV","difficulty":"Hard","points":500,"premise":"Settlement was permissionless. Whoever ran it could swap the prize at market, hand the contract only the oracle floor, and keep the difference — up to the full slippage bound, taken from the winner, every epoch.","objective":"Settle an epoch you did not win and end the transaction holding value that should have gone to the winner."},{"id":"zero-means-zero","title":"Zero means zero","finding":"F-09","category":"Oracle & MEV","difficulty":"Hard","points":500,"premise":"The circuit breaker checked variance as a ratio to the mean. With a mean of zero, both volatility checks divided into zero and passed trivially — a reading that should have been rejected sailed through.","objective":"Settle against an oracle attestation that the breaker was supposed to refuse."},{"id":"the-invariant","title":"The invariant","finding":"—","category":"Invariant","difficulty":"Capstone","points":1000,"premise":"One equation holds across the whole protocol: liquid + staked == total principal. It is enforced by the Move type system — no function taking an admin capability can reach principal at all. This challenge is not a known bug. It is the wall.","objective":"Make the invariant false by any path. Withdraw more than you put in, or leave the books unable to return everyone’s principal."}],"guidance":["Dry-run every state-changing transaction before sending it. Simulation is free and catches most mistakes.","Isolate failures by building two transactions that differ in exactly one way and comparing the results.","The operator of an agent is responsible for what it sends, including scope violations."]}