Mutation Testing
Trail of BitsOfficialPublished by Trail of Bits
- Skill
- Tool integration
- Software development
- CC-BY-SA-4.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to mutation testing using the mewt or muton tools. It guides users through the entire lifecycle of a mutation testing campaign, from initial configuration and execution to the analysis of surviving mutants. By systematically injecting faults into source code and observing test behavior, it helps developers distinguish between equivalent mutants and genuine testing gaps, ultimately revealing bugs that standard coverage metrics might miss.
What it does
- Configures and executes mutation testing campaigns via mewt or muton.
- Provides commands to filter, inspect, and re-test specific mutants.
- Categorizes mutation results into caught, uncaught, timeout, or skipped outcomes.
- Offers a framework for identifying equivalent mutants to reduce false positives.
- Prioritizes investigation based on mutation severity and language-specific patterns.
- Supports advanced analysis for blockchain-specific constructs like Solidity and Move.
When to use it
- When you need to validate the effectiveness of your existing test suite.
- When you want to identify untested code paths or weak assertions.
- When you need to analyze why specific mutants survived your test execution.
- When you are working on a project that requires high-assurance testing, such as blockchain smart contracts.
Advantages
- Uncovers subtle bugs that traditional line coverage metrics fail to detect.
- Provides a clear, actionable workflow for triaging and resolving surviving mutants.
- Reduces noise by helping developers identify and ignore semantically equivalent mutants.
- Enables targeted re-testing of specific code segments to verify fixes.
Usage examples
- “Run a mutation testing campaign on the src/auth directory.”
- The agent will execute the mutation campaign specifically targeting the auth module and provide a summary of the results.
- “Show me all uncaught mutants in the current project.”
- The agent will list the surviving mutants, allowing you to investigate potential testing gaps.
- “How do I investigate a high-severity surviving mutant?”
- The agent will guide you through inspecting the mutated code and suggest how to write a test to catch it.
- “Is this mutant equivalent to the original code?”
- The agent will apply the verification procedure to help you determine if the mutation is semantically identical or a genuine testing gap.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/trailofbits/mutation-testing/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip mutation-testing.zip -d .agents/skills
Documentation by Trail of Bits
Mutation Testing (mewt/muton)
Routes to the right mutation testing workflow and loads the references that workflow needs.
Note: muton and mewt share identical interfaces. Examples use
mewt; substitutemutonand its file names (muton.toml,muton.sqlite) for muton projects.
mewt --help and mewt <subcommand> --help are the source of truth for command-line behavior. Examples below reflect the mewt 4.x API; run --help when a flag looks unfamiliar or a command fails.
When to Use
Use this skill when the user:
Mentions "mewt", "muton", or "mutation testing"
Wants to configure, scope, or speed up a mutation testing campaign
Wants to analyze mutation results — surviving/uncaught mutants, equivalent mutants, kill rate
Wants to use mutation results to find bugs in the source code
When NOT to Use
Do not use this skill when the user asks about tests or line coverage without any mutation testing context.
Routing
Pick the workflow, then load it together with the references listed for it. Workflows and references do not load each other — that decision belongs here.
Setting up, scoping, or speeding up a campaign → workflows/configuration.md → Also load references/optimization-strategies.md when the campaign estimate is long enough to need trimming, or the user asks to make it faster.
Campaign finished, hunting for bugs in untested code → workflows/bug-hunter.md
Turning results into a formal analysis report → workflows/analyzing-results.md, plus:
references/equivalent-mutants.md — equivalence catalog and verification procedure
references/severity-classification.md — severity tier criteria
references/report-template.md — report structure
references/blockchain-patterns.md — only for Solidity, Move, FunC/Tolk, Cairo, or Solana Rust targets
references/input-formats.md — unless the results came from mewt or muton. Foreign tool output may not be self-describing; this covers the parsing anchors for slither-mutate, mull, and dextool-mutate
Anything else → run mewt --help or mewt <subcommand> --help, then assist directly.
Essential Commands
# Set up and run
mewt init # Create config and database
mewt mutate [paths] # Generate mutants without testing them
mewt run [paths] # Generate mutants and run the campaign
# Read results
mewt status # Overview with per-file breakdown
mewt results # Uncaught mutants (default view)
mewt results --all # Every outcome, not just uncaught
mewt results --format json # json | sarif | ids | table
# Narrow down (these filters work on both `results` and `print mutants`)
mewt results --target 'src/auth/**' # Quote globs so the shell does not expand them
mewt results --severity high,medium
mewt results --mutation-types ER,CR
mewt results --status Uncaught # Uncaught | TestFail | Skipped | Timeout
mewt results --line 42
# Investigate and re-test
mewt print mutant --id [id] # View the mutated code
mewt test --ids [ids] # Re-test specific mutants
mewt test --ids-file uncaught_ids.txt # Re-test IDs from a file, or '-' for stdin
# Inspect configuration
mewt print config # Effective config
mewt print targets # Files actually mutated
mewt print mutations --language [lang] # Mutations and severities for a languageLanguage labels are canonical family or family/dialect values in mewt 4.x — for example rust, javascript/ts, move/sui, move/iota.
What Results Mean
Caught/TestFail: tests detected the mutation (good)
Uncaught: tests did not detect the change. Inspect the code to distinguish a testing gap from an equivalent mutation.
Timeout: tests took too long — inconclusive, not evidence of coverage
Skipped: a less severe mutant was skipped because a more severe mutant on the same line was uncaught
Interpreting Mutation Types
mewt print mutations --language [lang] lists every mutation slug, description, and severity for a language, and is authoritative — the operator set grows with each release. What that output does not tell you is what a survivor means, which is where prioritization comes from:
| Severity | Representative slugs | What an uncaught mutant tells you |
|---|---|---|
| High | ER (Error Replacement) | Tests tolerate the injected error. Investigate whether the path executes, whether error handling masks the change, and whether assertions check the outcome. |
| Medium | CR (Comment Replacement) | Removing the statement does not fail the tests. Check whether its effects matter and whether assertions observe them. |
| Medium | IF/IT (If False/True), NR (Negation Removal) | Tests do not distinguish the changed condition. Both constant replacements surviving can indicate an unexecuted condition or weak assertions on the branch outcomes. |
| Low | Operator shuffles (AOS, COS, LOS, BOS, shift/assignment variants), BL, AS, LC, WF | Check boundary inputs, arithmetic assertions, and semantic equivalence. The mutation result alone does not establish whether the code executed. |
Severity ranks the mutation, not the risk. A low-severity survivor in a fee calculation matters more than a high-severity survivor in a log line — weigh what the mutated code does. Filter with --severity to work through the results in priority order.
Files
- ATTRIBUTION.mdAdded by AutoGineer942 B
- LICENSELicence file added by AutoGineer19.7 KiB
- SKILL.md6.1 KiB
- agents/openai.yaml243 B
- assets/trail-of-bits-mark.svg3.0 KiB
- references/blockchain-patterns.md4.8 KiB
- references/equivalent-mutants.md7.0 KiB
- references/input-formats.md2.4 KiB
- references/optimization-strategies.md8.7 KiB
- references/report-template.md4.3 KiB
- references/severity-classification.md5.9 KiB
- workflows/analyzing-results.md6.7 KiB
- workflows/bug-hunter.md7.4 KiB
- workflows/configuration.md11.3 KiB
workflows/bug-hunter.md
Bug Hunting with Mutation Testing
Uses mutation testing results as a map to untested code, then hunts for real bugs there.
Core Principle
Uncaught mutants reveal blind spots in testing, and blind spots are where bugs hide.
A missing test is not a bug — it is a signal about where to look. The deliverable of this workflow is confirmed bugs with proof-of-concept reproductions, not a list of coverage gaps. Report an uncaught mutant only after investigating the code behind it and finding something actually wrong.
Use this workflow for security audits, code review, risk assessment of legacy code, and pre-release validation. It does not guide test implementation or assess test quality — for a structured report on testing gaps themselves, use the analyzing-results workflow instead.
Prerequisites
A completed campaign (mewt run [paths]) with results available (mewt status).
Workflow
Step 1: Identify High-Risk Code
Entry: Campaign finished, results available.
Get the overview with
mewt statusand identify files with surviving mutations. Record the campaign scope and inconclusive results before using scores to prioritize.Cross-reference against sensitivity. Security-sensitive areas — auth, crypto, parsing, input validation — and core business logic deserve attention regardless of score; recently changed code with a low score deserves it most.
Pull the survivors for those areas:
mewt results --target 'src/auth/**' mewt results --target 'src/crypto/**' --severity high
Rank targets as: critical code with a low score, then critical code at any score (crypto at 80% is still worth reading), then core logic with a low score, then everything else.
Exit: Prioritized list of files to investigate.
Step 2: Prioritize Individual Mutants
Entry: Step 1 complete.
Within those files, order the survivors by what they reveal. Consult the High-Risk Patterns below for the combinations that most reliably indicate bugs.
Investigate immediately: ER in auth, crypto, parsing, or validation; ER clusters spanning consecutive lines; IF and IT both uncaught in security code; CR on an authorization check.
Investigate next: ER in error-handling paths; IF/IT in complex conditionals; CR on state-changing operations; any function with several survivors clustered in it.
Lower priority: isolated operator mutations, survivors in utility functions, and dead code — which is tech debt to remove, not a bug to debug.
Exit: Prioritized mutant list.
Step 3: Investigate for Bugs
Entry: Step 2 complete.
For each high-priority target:
Read the code.
mewt print mutant --id <id>shows the mutation; read the surrounding function for context. Establish the intended behavior. Investigate the original source: a defect deliberately introduced by a mutation is not evidence that the original program is vulnerable.Determine why it is untested. Dead code (never called), new code (tests not yet written), an edge case tests never trigger, an error path behind happy-path-only tests, or a unit/integration gap. Each points at a different kind of bug.
Assess risk: can attacker-controlled input reach this code, what happens if it is wrong, and does it sit on a security boundary?
Look for the bug classes that fit the mutation type:
ER— walk the code path manually; check error handling and input validation for paths that silently succeedIF/IT— exercise the untested branch; look for off-by-one errors and unhandled null/empty valuesCR— check whether the statement is necessary at all, and whether its state change actually happensOperator mutations — verify the comparison or arithmetic is the intended one, and test the boundary
Try to reproduce. Write a proof-of-concept test, run it, and confirm the impact. A hypothesis you could not reproduce is a "likely bug," not a confirmed one.
Exit: Each target resolved as a confirmed bug, a likely bug, dead code, or correct-but-weakly-tested code.
Step 4: Document Findings
Entry: Step 3 complete.
Each finding gets a location, the evidence (mutation result plus what manual testing showed), the issue, impact and severity, a reproduction, and a fix. Example:
## Bug: Expired Tokens Accepted
**Location:** `src/auth/verify.rs:78`
**Evidence:**
- Mutation testing: [ER #42] line 78 is completely untested
- Manual testing: a token that expired an hour ago verifies successfully
**Issue:** The expiry check is inverted. `if token.exp > now { return Err(Expired) }`
returns an error for tokens that are still valid and accepts tokens that have expired.
The error path has no test coverage, so the inversion went unnoticed.
**Impact:** Expired authentication tokens remain valid indefinitely. Severity: CRITICAL.
**Reproduction:**
```rust
#[test]
fn test_expired_token() {
let token = create_token_with_expiry(-3600); // expired 1 hour ago
assert!(matches!(verify_token(&token), Err(Expired))); // fails today
}
```
**Fix:** Compare with `<` on line 78.Classify every finding as confirmed (reproducible PoC, verified impact), likely (strong evidence, not yet reproduced), dead code (unreachable, remove it), or not a bug (correct code, weak tests). Keep the last two categories out of the bug list — dead code belongs in a cleanup recommendation.
Close with a short summary: campaign statistics, counts per category, the confirmed bugs with locations and severities, and recommendations.
Exit: Findings documented.
High-Risk Patterns
ER clusters. Several consecutive ER survivors can indicate an unexecuted block or tests that tolerate errors. Inspect execution and assertions before choosing either explanation. Determine whether the code is reachable in supported use.
IF and IT both uncaught on one line. The tests do not distinguish either constant replacement. The condition might be unexecuted, or both branches might run without assertions on the differing results. Check mewt results --line 42, then examine the tests and exercise the branch outcomes.
ER in error handling. Survivors in catch blocks and error-return paths mean failure modes are entirely unvalidated. Ask which errors can actually occur, whether an attacker can trigger them, and whether they leak information or crash the process.
Many survivors of mixed types in one security-sensitive file. Critical code with broadly weak coverage. Review the logic by hand rather than mutant by mutant, looking for bypasses in the security checks.
Working Effectively
Investigate one file or area at a time and focus on the top 10-20 priority mutants — comprehensive coverage of a large result set is not the goal, high-impact findings are. Summarize as you go rather than holding every finding in context.
Prioritize ruthlessly when there are too many survivors to investigate: start with ER in auth, crypto, and validation, favor clusters over isolated mutants, and accept that some areas go uninvestigated.
When you cannot tell whether untested code is buggy, test it — write the PoC, run the path, and compare actual behavior against intended behavior. When the code turns out to be correct and only the tests are weak, that is a legitimate outcome; say so. If the investigation confirms no bugs, report that outcome with its scope and unresolved cases. It does not establish that the area is free of bugs.
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Declares allowed tools
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Published by
- Trail of Bits
- Publisher
- Trail of Bits (Official)
- Source
- trailofbits/skills · plugins/mutation-testing/skills/mutation-testing · commit e4dd0bb
- Licence
- Creative Commons Attribution-ShareAlike 4.0 International (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Trail of Bits.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download mutation-testing.zip