Skip to content

Commit 6980311

Browse files
author
0xOpenClaw
committed
Fix exchange initializer spoofing (bind initializer to escrow)
1 parent 5970d0c commit 6980311

2 files changed

Lines changed: 30 additions & 0 deletions

File tree

programs/anchor-escrow/src/contexts/exchange.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ pub struct Exchange<'info> {
3838
pub initializer_ata_b: Box<Account<'info, TokenAccount>>,
3939
#[account(
4040
mut,
41+
// Critical: bind the passed-in `initializer` and `mint_a` to the escrow state.
42+
// Without this, a taker can spoof `initializer` to redirect the taker payment to themselves
43+
// and still withdraw `mint_a` from the vault.
44+
has_one = initializer,
45+
has_one = mint_a,
4146
has_one = mint_b,
4247
constraint = taker_ata_b.amount >= escrow.taker_amount,
4348
close = initializer,

tests/anchor-escrow.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,31 @@ describe("anchor-escrow", () => {
124124
.then(log);
125125
});
126126

127+
it("Exploit attempt: spoofed initializer should be rejected", async () => {
128+
// Before the fix, a taker could pass `initializer = taker` and `initializerAtaB = takerAtaB`.
129+
// That makes the taker payment a no-op (paying themselves), while still withdrawing `mintA`
130+
// from the vault — stealing the initializer's deposit.
131+
const spoofedAccounts = {
132+
...accounts,
133+
initializer: taker.publicKey,
134+
initializerAtaB: takerAtaB,
135+
};
136+
137+
let threw = false;
138+
try {
139+
await program.methods.exchange().accounts({ ...spoofedAccounts }).signers([taker]).rpc();
140+
} catch (e) {
141+
threw = true;
142+
// Anchor typically throws ConstraintHasOne on mismatch; we don't assert exact text to keep
143+
// the test stable across versions.
144+
// console.log("expected failure", e);
145+
}
146+
147+
if (!threw) {
148+
throw new Error("Exploit succeeded: escrow exchange accepted a spoofed initializer");
149+
}
150+
});
151+
127152
it("Exchange", async () => {
128153
await program.methods
129154
.exchange()

0 commit comments

Comments
 (0)