skills/vulnerability-patterns/msgvalue-loop/SKILL.md
- `msg.value` is referenced inside a loop (`for`, `while`) or in a function called multiple times within a single external call
npx skillsauth add apegurus/solidity-argus msgvalue-loopInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
msg.value is referenced inside a loop (for, while) or in a function called multiple times within a single external callmsg.value is "spent" per iterationfunction batchBuy(uint256[] calldata ids) external payable {
for (uint256 i = 0; i < ids.length; i++) {
// msg.value is the SAME on every iteration — it never decreases
// If price == 1 ETH and user sends 1 ETH, they can buy N items
require(msg.value >= price, "insufficient payment");
_mint(msg.sender, ids[i]);
}
// User paid 1 ETH but bought N items
}
// Payable multicall — same issue
function multicall(bytes[] calldata calls) external payable {
for (uint256 i = 0; i < calls.length; i++) {
// msg.value forwarded to each sub-call — reused each time
(bool s,) = address(this).delegatecall(calls[i]);
require(s);
}
}
msg.value usage inside for, while, or do-while loopsmsg.value in functions that are called via delegatecall in a loop (multicall patterns)msg.value is used in a require check inside a loop — passes on every iteration after a single paymentmsg.value and are called multiple times from a payable external functionmsg.value directlyremaining -= price)msg.value is only referenced once outside any loopmsg.value before the loop (e.g., require(msg.value == price * ids.length))require(msg.value == price * count)msg.value is consumed only once, or use a tracking variablefunction batchBuy(uint256[] calldata ids) external payable {
uint256 totalCost = price * ids.length;
require(msg.value >= totalCost, "insufficient payment");
for (uint256 i = 0; i < ids.length; i++) {
_mint(msg.sender, ids[i]);
}
// Refund excess
if (msg.value > totalCost) {
payable(msg.sender).transfer(msg.value - totalCost);
}
}
testing
Specialist profile for mechanically applying the attack-vector deck and classifying vectors as skip, drop, or investigate.
tools
Specialist profile for libraries, helpers, base contracts, adapters, encoders, wrappers, and integration glue.
testing
Specialist profile for rounding, scale, decimal, downcast, and arithmetic accounting edge cases.
testing
Specialist profile for extracting conservation laws and state couplings, then searching for violating paths.