Reproduced Exploit
Alchemix: A veALCX holder calls poke() 3x within one epoch (poke lacks the onlyNewEpoch guard that v
Chain
Other
Category
untagged
Date
Jan 1970
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: 38189-lack-of-access-control-in-poke-function-allows-in-unlimited. The historical source/toolchain is unavailable; this entry is documentation only and claims no executable Forge PoC.
Vulnerability classes: vuln/unfair-mint
Reproduction: a faithful minimal reproduction of the vulnerable finding — the vulnerable function is reproduced verbatim (marked
@>) with faithful minimal doubles; local deploy, no fork.
Root cause#
A veALCX holder calls poke() 3x within one epoch (poke lacks the onlyNewEpoch guard that vote()/reset() have), re-accruing FLUX each call so unclaimedFlux reaches 3x the legitimate per-epoch entitlement — 2e18 excess FLUX over-minted to the attacker.
// Previous boost will be taken into account with weights being pulled from the votes mapping
uint256 _boost = 0;
if (msg.sender != admin) {
require(IVotingEscrow(veALCX).isApprovedOrOwner(msg.sender, _tokenId), "not approved or owner");
}
Why it's exploitable here#
A veALCX holder calls poke() 3x within one epoch (poke lacks the onlyNewEpoch guard that vote()/reset() have), re-accruing FLUX each call so unclaimedFlux reaches 3x the legitimate per-epoch entitlement — 2e18 excess FLUX over-minted to the attacker.
Attack path#
Marked-line walkthrough (Playground)#
The EVM Playground pins each step to the exact executed source line in 0xce01759b82…:
- L138 — Once-per-epoch guard vote() has:
vote()enforces one action per epoch via thislastVotedcheck — the exact guardpoke()is missing, which is the whole bug. - L155 — poke's only gate is admin check: Root cause:
poke()'s sole check ismsg.sender != admin, with no per-epoch guard, so any holder can re-poke repeatedly within one epoch. - L163 — Loop over the token's pools: poke iterates the token's pools to rebuild its current vote weights before re-casting them.
- L164 — Copy existing per-pool votes: Each pool's prior weight is read from
votes[_tokenId], so poke replays the same vote and re-triggers FLUX accrual every call. - L170 — Funnel into internal _vote: poke calls
_vote, the shared routine that accrues FLUX — with no epoch check, each poke re-runs it and re-accrues. - L176 — Stamp lastVoted timestamp:
_voteupdateslastVoted, but because poke never reads it, this stamp never stops the repeated accrual. - L185 — Epoch length is two weeks:
DURATIONdefines the 2-week epoch that the missing guard was meant to bound FLUX accrual to.
PoC#
Registry (Foundry, local deploy — verbatim vulnerable source + harm-asserting test + negative control):
cd 38189-lack-of-access-control-in-poke-function-allows-in-unlimited_exp
forge test -vvv
The browser Playground replays the same synthetic opcode-for-opcode and measures the harm: A veALCX holder calls poke() 3x within one epoch (poke lacks the onlyNewEpoch guard that vote()/reset() have), re-accruing FLUX each call so. Both gates are green (registry forge test PASS + Playground _verify-poc VERDICT: PASS).
Sources & further analysis#
Reproductions & code
- No executable Forge reproduction is claimed; the historical source/toolchain was unavailable for this finding.
- AuditVault finding: 38189-lack-of-access-control-in-poke-function-allows-in-unlimited.
- Upstream DeFiHackLabs PoC directory: src/test.
Alerts & third-party analyses
- DeFiHackLabs incident explorer: [search "Alchemix: A veALCX holder calls poke() 3x within one epoch (poke lacks the onlyNewEpoch guard that v"](https://defihacklabs.io/explorer/index.html?q=Alchemix%3A%20A%20veALCX%20holder%20calls%20poke()%203x%20within%20one%20epoch%20(poke%20lacks%20the%20onlyNewEpoch%20guard%20that%20v).
- Web3Sec X hacked database: search.
- Rekt leaderboard: [search](https://rekt.news/?s=Alchemix%3A%20A%20veALCX%20holder%20calls%20poke()%203x%20within%20one%20epoch%20(poke%20lacks%20the%20onlyNewEpoch%20guard%20that%20v).
- Solodit incident search: [search](https://solodit.xyz/issues?search=Alchemix%3A%20A%20veALCX%20holder%20calls%20poke()%203x%20within%20one%20epoch%20(poke%20lacks%20the%20onlyNewEpoch%20guard%20that%20v).
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.