Reproduced Exploit
Oku OracleLess: `procureTokens` pulls from the order recipient, letting an attacker steal a victim's approved tokens
Chain
Other
Category
access-control
Date
Nov 2024
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 44378-h-8-insecure-calls-to-safetransferfrom-leads-to-users-tokens. Standalone Foundry PoC and full write-up: 44378-h-8-insecure-calls-to-safetransferfrom-leads-to-users-tokens_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/access-control/missing-check · vuln/defi/direct-drain · vuln/token/transferfrom-source
Reproduction: the test deploys the real, unmodified
OracleLessandAutomationMasterfrom the audited Oku repo (only the opaque tokens are minimal real ERC20s) and runs the real create → fill path, so an attacker turns a victim's leftover approval into a full token theft.
Root cause#
OracleLess.createOrder forwards the caller-supplied recipient straight into procureTokens, which then pulls tokens from that recipient, not from msg.sender:
function createOrder(..., address recipient, ...) external returns (uint96 orderId) {
procureTokens(tokenIn, amountIn, recipient, permit, permitPayload); // recipient = pull source
...
}
function procureTokens(IERC20 token, uint256 amount, address owner, ...) internal {
...
} else {
token.safeTransferFrom(owner, address(this), amount); // owner == recipient == victim
}
}
Any address with a residual allowance to the protocol can be named as recipient by an attacker, and its tokens are pulled into an attacker-crafted order without consent. The attacker then fills their own order through the arbitrary target/txData call in fillOrder → execute, keeping the escrowed tokenIn and returning only dust tokenOut. The same pattern exists in Bracket.modifyOrder and StopLimit; OracleLess.procureTokens is the location cited by the finding.
The real contract is vendored at src/oku/contracts/automatedTrigger/OracleLess.sol (procureTokens at L259-282, execute at L227-257).
Exploit walkthrough (numbers from the test)#
Precondition: the victim holds 100e18 of a valuable token and has a leftover 100e18 approval to OracleLess (e.g. an over-approval from an earlier intended trade).
- Attacker calls
createOrder(tokenIn, tokenOut, amountIn = 100e18, minAmountOut = 1, recipient = victim, …).procureTokenspulls100e18from the victim intoOracleLess. - Attacker calls
fillOrder(0, orderId, target = attacker, txData = swap()).executeapproves the attacker's contract for100e18oftokenIn, then calls it. - The attacker's
swap()doestransferFrom(OracleLess → attacker, 100e18)and returns2wei of the worthlesstokenOut— enough to clear the> minAmountOutandover spendchecks. fillOrdersends the2weitokenOutto the recipient (victim). Result: attacker gains100e18of the victim's valuable token; the victim is left with2wei of a worthless token.
Reproduce#
# from the evm-hack-registry root
_shared/run-poc/run_poc.sh 44378-h-8-insecure-calls-to-safetransferfrom-leads-to-users-tokens_exp -vvvvv
Expected: 1 passed. The test in test/44378-…_exp.sol asserts the attacker contract ends holding the victim's 100e18 while the victim is left with only 2 wei of a worthless token.
Sources#
- AuditVault finding #44378
- Sherlock Oku contest (issue #789)
- Audited source:
sherlock-audit/2024-11-oku@ee3f781 - Fix: gfx-labs/oku-custom-order-types PR #1
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 44378-h-8-insecure-calls-to-safetransferfrom-leads-to-users-tokens_exp (evm-hack-registry mirror).
- AuditVault finding: 44378-h-8-insecure-calls-to-safetransferfrom-leads-to-users-tokens.
- Upstream DeFiHackLabs PoC directory: src/test.
Alerts & third-party analyses
- DeFiHackLabs incident explorer: search "Oku OracleLess:
procureTokenspulls from the order recipient, letting an attacker steal a victim's approved tokens". - Web3Sec X hacked database: search.
- Rekt leaderboard: search.
- Solodit incident search: search.
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.