Dangerous Unary Expressions
id: LS16M
title: Dangerous Unary Expressions
baseSeverity: M
category: logic
language: solidity
blockchain: [ethereum]
impact: Wrong calculations, state overwrite, or logic bypass
status: draft
complexity: low
attack_vector: internal
mitigation_difficulty: easy
versions: [">=0.4.0", "<=0.8.25"]
cwe: CWE-682
swc: SWC-135
π Description
- In Solidity, unary expressions like ++, --, -, and ! can behave unexpectedly when:
- Used within inline statements
- Misordered relative to assignments
- Applied to uint types, causing silent underflow in older versions (<0.8.0)
- In particular, confusing use of ++var vs var++ and mixing assignment and side effects in one line can lead to incorrect state changes. If these expressions are used without clarity or boundaries, they may:
- Cause off-by-one errors
- Increment or decrement the wrong value
- Overwrite important mappings or state variables incorrectly
π¨ Vulnerable Code
pragma solidity ^0.8.0;
contract Counter {
mapping(address => uint256) public counts;
function logAndIncrement() external {
counts[msg.sender] = counts[msg.sender]++;
// β Value is not incremented as expected
}
}
π§ͺ Exploit Scenario
- A staking contract logs participation by incrementing a user count.
- It uses storage[addr] = storage[addr]++ as shorthand.
- The ++ is applied but its value is lost due to reassignment.
- User staking count remains stuck at 0.
- Rewards, permissions, or unlocks based on stake count never trigger, locking users out or enabling repeat rewards due to failure to advance state.
Assumptions:
- The logic uses ++ or -- in expressions with assignment or mapping access.
- There is no validation or test to detect silent failures.
β Fixed Code
pragma solidity ^0.8.0;
contract SafeCounter {
mapping(address => uint256) public counts;
function logAndIncrement() external {
counts[msg.sender] += 1; // β
Clear and correct
}
}
π§ Contextual Severity
- context: "Default"
severity: M
reasoning: "Common logic bug leading to skipped updates or miscounted state."
- context: "Reward distribution or vote limits"
severity: H
reasoning: "Can cause partial payouts or exploit permission logic."
- context: "Testnet or private/internal functions"
severity: L
reasoning: "Limited risk in isolated or non-production environments."
π‘οΈ Prevention
Primary Defenses
- Avoid combining ++ or -- with assignment (x = x++).
- Use += 1 or -= 1 to make intent explicit.
Additional Safeguards
- Add test cases that assert variable changes across all mutations.
- Avoid in-line increment/decrement inside expressions that also mutate state.
Detection Methods
- Search for lines containing both = and ++ or --.
- Tools: Slither (dangerous-unary), Solhint (no-unchecked-unary-expressions), manual review
π°οΈ Historical Exploits
- Name: Solidity Unary Plus Operator Misuse
- Date: 2017
- Loss: Potential for unintended behavior due to misuse of unary plus operator
- Post-mortem: Link to post-mortem
π Further Reading
β Vulnerability Report
id: LS16M
title: Dangerous Unary Expressions
severity: M
score:
impact: 3
exploitability: 2
reachability: 4
complexity: 1
detectability: 5
finalScore: 2.9
π Justifications & Analysis
- Impact: State may be mutated incorrectly or not at all, blocking flows or enabling unintended behavior.
- Exploitability: Primarily internal misuse; users can't exploit it directly, but may benefit indirectly (e.g., repeat access).
- Reachability: Occurs in many contract typesβlotteries, staking, counters.
- Complexity: A very simple syntax error with high consequence.
- Detectability: Readily caught by Slither or manual logic testing.