Mutation Testing for Solidity with Slither (slither-mutate)
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
Mutation testing์ Solidity ์ฝ๋์ ์์ ๋ณ๊ฒฝ(mutants)์ ์ฒด๊ณ์ ์ผ๋ก ๋์ ํ๊ณ ํ ์คํธ ์ค์ํธ๋ฅผ ๋ค์ ์คํํจ์ผ๋ก์จ โํ ์คํธ๋ฅผ ํ ์คํธโํฉ๋๋ค. ํ ์คํธ๊ฐ ์คํจํ๋ฉด ํด๋น ๋ฎคํดํธ๋ killed๋ฉ๋๋ค. ํ ์คํธ๊ฐ ์ฌ์ ํ ํต๊ณผํ๋ฉด ๋ฎคํดํธ๋ ์ด์๋จ์ line/branch coverage๋ก๋ ํ์งํ ์ ์๋ ํ ์คํธ ์ค์ํธ์ ๋งน์ ์ ๋๋ฌ๋ ๋๋ค.
ํต์ฌ ์์ด๋์ด: Coverage๋ ์ฝ๋๊ฐ ์คํ๋์์์ ๋ณด์ฌ์ฃผ๊ณ ; mutation testing์ ๋์์ด ์ค์ ๋ก ๋จ์ธ(asserted)๋์๋์ง๋ฅผ ๋ณด์ฌ์ค๋๋ค.
Coverage๊ฐ ์ค๋ํ ์ ์๋ ์ด์
๋ค์์ ๊ฐ๋จํ threshold ๊ฒ์ฌ๋ฅผ ๊ณ ๋ คํด๋ณด์:
function verifyMinimumDeposit(uint256 deposit) public returns (bool) {
if (deposit >= 1 ether) {
return true;
} else {
return false;
}
}
Unit tests that only check a value below and a value above the threshold can reach 100% line/branch coverage while failing to assert the equality boundary (==). A refactor to deposit >= 2 ether would still pass such tests, silently breaking protocol logic.
Mutation testing exposes this gap by mutating the condition and verifying your tests fail.
Common Solidity mutation operators
Slitherโs mutation engine applies many small, semantics-changing edits, such as:
- Operator replacement:
+โ-,*โ/, etc. - Assignment replacement:
+=โ=,-=โ= - Constant replacement: non-zero โ
0,trueโfalse - Condition negation/replacement inside
if/loops - Comment out whole lines (CR: Comment Replacement)
- Replace a line with
revert() - Data type swaps: e.g.,
int128โint64
Goal: Kill 100% of generated mutants, or justify survivors with clear reasoning.
Running mutation testing with slither-mutate
Requirements: Slither v0.10.2+.
- List options and mutators:
slither-mutate --help
slither-mutate --list-mutators
- Foundry ์์ (๊ฒฐ๊ณผ ์บก์ฒ ๋ฐ ์ ์ฒด ๋ก๊ทธ ๋ณด๊ด):
slither-mutate ./src/contracts --test-cmd="forge test" &> >(tee mutation.results)
- Foundry๋ฅผ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ,
--test-cmd์(๋ฅผ) ํ ์คํธ ์คํ ๋ฐฉ๋ฒ(์:npx hardhat test,npm test)์ผ๋ก ๋ฐ๊ฟ์ฃผ์ธ์.
์ํฐํฉํธ์ ๋ฆฌํฌํธ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ./mutation_campaign์ ์ ์ฅ๋ฉ๋๋ค. ๊ฒ์ถ๋์ง ์์(์์กดํ) mutants๋ ๊ฒ์ฌ๋ฅผ ์ํด ๊ทธ๊ณณ์ ๋ณต์ฌ๋ฉ๋๋ค.
์ถ๋ ฅ ์ดํดํ๊ธฐ
๋ฆฌํฌํธ ๋ผ์ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค:
INFO:Slither-Mutate:Mutating contract ContractName
INFO:Slither-Mutate:[CR] Line 123: 'original line' ==> '//original line' --> UNCAUGHT
- ๋๊ดํธ ์์ ํ๊ทธ๋ ๋ฎคํ
์ดํฐ ๋ณ์นญ์
๋๋ค (์:
CR= Comment Replacement). UNCAUGHT๋ ๋ณํ๋ ๋์ ํ์์ ํ ์คํธ๊ฐ ํต๊ณผํ์์ ์๋ฏธํฉ๋๋ค โ ๋๋ฝ๋ assertion.
์คํ ์๊ฐ ๋จ์ถ: ์ํฅ๋ ฅ ์๋ ๋ฎคํดํธ ์ฐ์
Mutation ์บ ํ์ธ์ ์์๊ฐ์์ ์์ผ์ด ๊ฑธ๋ฆด ์ ์์ต๋๋ค. ๋น์ฉ์ ์ค์ด๊ธฐ ์ํ ํ:
- ๋ฒ์: ํต์ฌ contracts/๋๋ ํ ๋ฆฌ๋ถํฐ ์์ํ ๋ค ํ์ฅํ์ธ์.
- ๋ฎคํ ์ดํฐ ์ฐ์ ์์ ์ง์ : ํ ์ค์์ ์ฐ์ ์์๊ฐ ๋์ ๋ฎคํดํธ๊ฐ ์์กดํ๋ ๊ฒฝ์ฐ(์: ์ ์ฒด ์ค ์ฃผ์ ์ฒ๋ฆฌ) ํด๋น ์ค์ ๋ฎ์ ์ฐ์ ์ ๋ณํ์ ๊ฑด๋๋ธ ์ ์์ต๋๋ค.
- ๋ฌ๋์์ ํ์ฉํ๋ฉด ํ ์คํธ๋ฅผ ๋ณ๋ ฌํํ์ธ์; ์์กด์ฑ/๋น๋๋ฅผ ์บ์ํ์ธ์.
- Fail-fast: ๋ณ๊ฒฝ์ด ๋ช ๋ฐฑํ assertion ๊ฒฉ์ฐจ๋ฅผ ๋ณด์ฌ์ฃผ๋ฉด ์กฐ๊ธฐ์ ์ค๋จํ์ธ์.
์์กดํ ๋ฎคํดํธ์ ๋ํ ํธ๋ฆฌ์์ง ์ํฌํ๋ก์ฐ
- ๋ณ๊ฒฝ๋ ์ค๊ณผ ๋์์ ๊ฒ์ฌํฉ๋๋ค.
- ๋ณ๊ฒฝ๋ ์ค์ ์ ์ฉํ๊ณ ํน์ ํ ์คํธ๋ฅผ ์คํํด ๋ก์ปฌ์์ ์ฌํํ์ธ์.
- ํ ์คํธ๋ฅผ ๊ฐํํ์ฌ ์ํ(state)๋ฅผ ๋จ์ธ(assert)ํ์ธ์, ๋ฐํ๊ฐ๋ง์ด ์๋๋ผ.
- ๋๋ฑ์ฑ ๊ฒฝ๊ณ ๊ฒ์ฌ ์ถ๊ฐ(์: ์๊ณ๊ฐ
==ํ ์คํธ). - ํ์กฐ๊ฑด์ ๋จ์ธ: ์์ก, ์ด ๊ณต๊ธ๋(total supply), ๊ถํ ์ํฅ(authorization effects), ๋ฐ์ํ ์ด๋ฒคํธ(emitted events).
- ์ง๋์น๊ฒ ๊ด๋ํ mocks๋ฅผ ํ์ค์ ์ธ ๋์์ผ๋ก ๊ต์ฒดํ์ธ์.
- mocks๊ฐ ์ฒด์ธ ์์์ ๋ฐ์ํ๋ ์ ์ก(transfers), ์คํจ ๊ฒฝ๋ก(failure paths), ์ด๋ฒคํธ ๋ฐ์(event emissions)์ ๊ฐ์ ํ๋๋ก ํ์ธ์.
- ํผ์ฆ(fuzz) ํ ์คํธ๋ฅผ ์ํ ๋ถ๋ณ์ฑ(invariants)์ ์ถ๊ฐํ์ธ์.
- ์: ๊ฐ์น ๋ณด์กด(conservation of value), ์์ ๋ถ๊ฐ ์์ก(non-negative balances), ๊ถํ ๋ถ๋ณ์ฑ, ์ ์ฉ ๊ฐ๋ฅํ ๊ฒฝ์ฐ ๋จ์กฐ ์ฆ๊ฐํ๋ ๊ณต๊ธ๋(monotonic supply).
- slither-mutate๋ฅผ ๋ค์ ์คํํ์ฌ ์์กด์๊ฐ ์ ๊ฑฐ๋๊ฑฐ๋ ๋ช ํํ ์ ๋นํ๋ ๋๊น์ง ๋ฐ๋ณตํ์ธ์.
์ฌ๋ก ์ฐ๊ตฌ: ๋๋ฝ๋ ์ํ ๋จ์ธ ๋๋ฌ๋ด๊ธฐ (Arkis protocol)
Arkis DeFi protocol์ ๊ฐ์ฌ ์ค ์ํ๋ ๋ฎคํ ์ด์ ์บ ํ์ธ์์ ๋ค์๊ณผ ๊ฐ์ ์์กด์๊ฐ ๋ํ๋ฌ์ต๋๋ค:
INFO:Slither-Mutate:[CR] Line 33: 'cmdsToExecute.last().value = _cmd.value' ==> '//cmdsToExecute.last().value = _cmd.value' --> UNCAUGHT
ํ ๋น๋ฌธ์ ์ฃผ์ ์ฒ๋ฆฌํด๋ ํ
์คํธ๊ฐ ๊นจ์ง์ง ์์๋๋ฐ, ์ด๋ ์ฌํ ์ํ ๊ฒ์ฆ(post-state assertions)์ด ๋๋ฝ๋์์์ ์ฆ๋ช
ํ๋ค. ๊ทผ๋ณธ ์์ธ: ์ฝ๋๊ฐ ์ค์ ํ ํฐ ์ ์ก์ ๊ฒ์ฆํ์ง ์๊ณ ์ฌ์ฉ์ ์ ์ด _cmd.value๋ฅผ ์ ๋ขฐํ๋ค. ๊ณต๊ฒฉ์๋ ๊ธฐ๋๋ ์ ์ก๊ณผ ์ค์ ์ ์ก์ ๋น๋๊ธฐํ์์ผ ์๊ธ์ ํ์ทจํ ์ ์๋ค. ๊ฒฐ๊ณผ: ํ๋กํ ์ฝ ์ง๊ธ๋ฅ๋ ฅ์ ๋ํ ๋์ ์ฌ๊ฐ๋ ์ํ.
์ง์นจ: ๊ฐ์น ์ ์ก(value transfers), ํ๊ณ(accounting) ๋๋ ์ ๊ทผ ์ ์ด(access control)์ ์ํฅ์ ๋ฏธ์น๋ survivors๋ ์ ๊ฑฐ(killed)๋ ๋๊น์ง ๊ณ ์ํ์ผ๋ก ๊ฐ์ฃผํ๋ผ.
์ค๋ฌด ์ฒดํฌ๋ฆฌ์คํธ
- Run a targeted campaign:
slither-mutate ./src/contracts --test-cmd="forge test"- Triage survivors and write tests/invariants that would fail under the mutated behavior.
- Assert balances, supply, authorizations, and events.
- Add boundary tests (
==, overflows/underflows, zero-address, zero-amount, empty arrays). - Replace unrealistic mocks; simulate failure modes.
- Iterate until all mutants are killed or justified with comments and rationale.
References
- Use mutation testing to find the bugs your tests donโt catch (Trail of Bits)
- Arkis DeFi Prime Brokerage Security Review (Appendix C)
- Slither (GitHub)
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


