# msg.value remains constant throughout a transaction enabling double-spend when referenced inside loops
When `msg.value` is checked inside a loop or called multiple times within a single transaction, the same ETH value is counted each iteration. A function that processes multiple operations and checks `require(msg.value >= price)` for each one allows the caller to pay once but execute many times. The Opyn hack exploited this pattern.
The defense is to track cumulative spending: decrement a running total rather than comparing against `msg.value` directly. Alternatively, restrict functions that process `msg.value` to single-operation execution. This is a concrete instance of the broader trend that [[logic errors climbed from seventh to third in owasp 2025 ranking indicating a shift toward business logic as primary attack surface|logic errors are the rising attack surface]] — the code is syntactically correct but semantically wrong about how ETH accounting should work.
---
Relevant Notes:
- [[reentrancy is possible whenever external calls precede state updates]] — another pattern where stale values enable exploitation
- [[logic errors climbed from seventh to third in owasp 2025 ranking indicating a shift toward business logic as primary attack surface]] — msg.value reuse is a business logic error
- [[low-level call and send return false on failure without reverting so unchecked return values cause silent fund loss]] — another value-handling pattern that causes silent fund loss
Topics:
- [[vulnerability-patterns]]