Full Report
Denial of Service (DoS) are attacks that come from disallowing access to a service. In the context of blockchain applications, this can be completely rejects access to the service to somebody else or to yourself accidentally. Both of these are valid findings are auditors on Code4rena. The first one the author mentions is DoS by Underflow. In Solidity, there are now built in protections to prevent overflows and underflows. However, if there is a flaw in the contract, the protection could become a DoS itself. An example of the underflow DoS was a contract where there is a senior and junior vault. When a junior vault would transfer it to the senior vault, it had to convert from WETH to USDC to stake. The senior vault gains value by increasing the debt of the junior vault. There is validation to ensure that the vault is not beyond its cap, which was covered by integer overflow protection. If that is true, then it will revert on the same call for withdraw and deposit. To solve this, return 0 on the value instead of underflowing. Another common bug is DoS via gas limit. In the example, a user deposit was tracked in an array. Later on, when withdrawing USDC, it goes from an index of 0 to an infinite size. By making the array too big, users may be denied access from gas limitations. This can be solved by programming without controllable array, removing previously used values that are no longer needed or having indexed based calls in cases where the array is too long. DoS by nonReentrant modifier. An example of this starts with contract had various operations related to staking, rewards and transferring funds with nonReentrant modifiers on them. There existed a unstaking code path that hit a transfer function where BOTH had the nonReentrant modifier on it. Since this was the case, all calls to the unstake function with the case of there being vault rewards to fail. The solution the problem could be done in a few ways. In particular, having an external function with the modifier and an internal function without the modifier to access the functionality. The next item refers to external calls reverting. The example they give is a chainlink oracle may reject calls. The solution to this appears to depend on the external call being made. However, to me, having a fallback for handling an oracle is dumb... the whole point is that this is a trusted entity that is secure. Any logic against this could lead to compromise. DoS via Malicious Receiver. There is commonly logic that allows for the arbitrary callback of contracts. If this is implemented for various bits of functionality, an attacker could force a revert to happen, blocking the contract forever. In the example case, it a contract with basic loan functions liquidate() and endAuction() which call the users defined function. An attacker can revert all of these calls to make it impossible to end an auction or liquidate. Overall, interesting post on denial of service problems in Solidity.
Analysis Summary
# Vulnerability: Multiple Denial of Service (DoS) Patterns in Solidity Smart Contracts
## CVE Details
- **CVE ID:** N/A (General Smart Contract Design Patterns/Weaknesses)
- **CVSS Score:** varies, typically 7.5 (High) for Availability impact in DeFi
- **CWE:**
- CWE-730: Overflow/Underflow
- CWE-400: Uncontrolled Resource Consumption (Gas)
- CWE-617: Reachable Assertion (Revert on nonReentrant)
## Affected Systems
- **Products:** Solidity-based Smart Contracts (primarily EVM-compatible)
- **Versions:** Solidity 0.8.x (for underflow-specific DoS); generic for gas/reentrancy issues.
- **Configurations:**
- Vault management systems (e.g., DnGmxJuniorVaultManager)
- Contracts utilizing unbounded arrays
- Contracts with nested `nonReentrant` modifier calls
- Protocols relying on external Oracle callbacks or user-defined receivers
## Vulnerability Description
Denial of Service in blockchain applications occurs when a transaction or contract state becomes permanently or temporarily Hors de Combat (unable to process). The article highlights five specific patterns:
1. **Underflow-Induced Revert:** In Solidity 0.8+, built-in overflow/underflow checks trigger a revert. If logic fails to account for values dropping below zero (e.g., debt calculations), essential functions like `withdraw` or `deposit` can be rendered unusable.
2. **Unbounded Gas Consumption:** Iterating over arrays that grow indefinitely (e.g., user deposit indices) eventually exceeds the Block Gas Limit, causing all associated transactions to fail.
3. **Cross-Function Reentrancy Deadlock:** Applying the `nonReentrant` modifier to both an external function and an internal child call causes the contract to revert on its own valid execution path.
4. **External Dependency Failure:** Reliance on external entities (e.g., Chainlink Oracles) that may revert or fail to respond, blocking the primary contract's execution flow.
5. **Malicious Receiver Callbacks:** Smart contracts that perform arbitrary calls to external addresses (e.g., for liquidations or auctions) can be blocked if the receiver is a contract specifically designed to `revert()`.
## Exploitation
- **Status:** PoCs available for specific audit findings (Code4rena).
- **Complexity:** Low to Medium
- **Attack Vector:** Network (On-chain transactions)
## Impact
- **Confidentiality:** None
- **Integrity:** Low (State cannot be updated)
- **Availability:** High (Users cannot withdraw funds or access services)
## Remediation
### Patches
- **Logic Correction:** Implement `math.max(0, value)` patterns to prevent underflows from triggering global reverts.
- **Architectural Change:** Replace unbounded arrays with mapping-based lookups or implement pagination for indexed calls.
- **Reentrancy Refactoring:** Use the "Internal Function" pattern—where a `public`/`external` function has the `nonReentrant` modifier and calls an `internal` function that performs the logic without the modifier.
### Workarounds
- **Pull vs. Push:** Use "Pull Payment" patterns to ensure a malicious receiver can only DoS their own withdrawal, not the entire protocol's auction or liquidation system.
- **Fail-safes:** Implement heartbeat checks or secondary oracles as fallbacks, though the author notes this must be done carefully to avoid introducing new trust assumptions.
## Detection
- **Indicators of Compromise:** Repeated "Out of Gas" errors for specific addresses; persistent reverts on core administrative functions (liquidations/harvesting).
- **Detection Methods and Tools:**
- Static Analysis (Slither, Mythril) for unbounded loops and modifier shadowing.
- Formal Verification for invariant checking (e.g., "Balance must always be withdrawable").
- Fuzzing (Foundry/Echidna) to identify edge-case underflows.
## References
- hxxps://medium[.]com/bloqarl/uncovering-real-life-examples-of-denial-of-service-attacks-on-smart-contracts-8bc220c2cdd0
- hxxps://code4rena[.]com/reports/ (Source for DnGmxJuniorVaultManager audit)
- hxxps://docs.soliditylang[.]org/en/v0.8.0/control-structures.html#checked-arithmetic