SpecGuard: Proving a Task Is Broken Before the Agent Cheats
Organizations: MATS · Google DeepMind
Abstract
As autonomous coding agents get increasingly deployed, the risk that accidental or adversarially injected misspecifications in tasks lead to dangerous agent behavior is critical to address. Prior work has shown that agents given such tasks rarely flag the conflict and instead cheat, editing tests or hard-coding expected outputs, and the actions taken to cheat can cause real damage, such as deleting a security defense to make a corrupted test pass. It remains unclear whether such conflicts can be established with independently verifiable evidence before the agent acts. We present SpecGuard, which detects and formally certifies these conflicts between task intent and tests. Given only the task description and codebase, SpecGuard autoformalizes the intended behaviour into a Lean 4 specification. The tests are formalized independently, and the Lean kernel checks whether any implementation could satisfy both formalizations, producing a machine-checked certificate when none can. On conflicted SWE-bench tasks, SpecGuard detects up to 72.8% of conflicts and formally certifies up to 51.1%, with a nearly five-fold lower conflict miss rate than model-based judgment. SpecGuard provides a pre-execution safety check that identifies reward-hacking opportunities through formal certification of task-level conflicts, before any agent behavior is observed. Our code is available at https://github.com/prmbiy/specguard.
Figures & tables
Appendix figures & tables12 assets
Supplementary material from the paper’s appendix.
Appendix
| Level | Supporting artifact | What it establishes |
|---|---|---|
| Model judgment | Model output | The model judges that a conflict exists. |
| Execution checked | Executable disagreement | Reproducible disagreement on represented cases. |
| Property tested | Generated tests or counterexamples | Broader empirical evidence over explored behavior. |
| Formally certified | Kernel-checked theorem | Formal inconsistency between represented intent and tests. |
| Human verified | Certificate + semantic inspection | Additionally checks correspondence between the formal artifacts and the source task. |
| Dimension | Categories |
|---|---|
| Relation to issue | On-issue 251 (72%), adjacent 47 (13%), off-issue 51 (15%) |
| Observed property | Value 196 (56%), string format 85 (24%), side effect 23 (7%), identity/type 22 (6%), exception 9 (3%), numeric 7 (2%), ordering 6 (2%), rendered 1 ( 1%) |
| Required information | Framework 202 (58%), pure 81 (23%), fixture data 28 (8%), stateful sequence 18 (5%), heavy algorithm 15 (4%), external 5 (1%) |
| Additional flags | Many assertions 83 (24%), parametrized 53 (15%), type nuance 20 (6%), configuration default 19 (5%) |
| Relation | Detected | Certified | Inconclusive | Incorrect | |
|---|---|---|---|---|---|
| On-issue | 251 | 60.3 | 55.0 | 29.7 | 10.0 |
| Adjacent | 47 | 58.2 | 51.1 | 37.6 | 3.5 |
| Off-issue | 51 | 39.9 | 32.0 | 56.9 | 3.3 |
| Required information | Detected | Certified | Inconclusive | Incorrect | |
|---|---|---|---|---|---|
| Stateful sequence | 18 | 72.2 | 68.5 | 22.2 | 5.6 |
| Pure | 81 | 71.6 | 63.4 | 27.6 | 0.8 |
| Framework | 202 | 55.9 | 51.0 | 35.3 | 8.6 |
| External | 5 | 40.0 | 40.0 | 33.3 | 26.7 |
| Fixture data | 28 | 31.0 | 25.0 | 41.7 | 27.4 |
| Heavy algorithm | 15 | 28.9 | 17.8 | 68.9 | 2.2 |
| Outcome | Task-runs | Share | Audited |
|---|---|---|---|
| Partial connection | 399 | 50% | 101 |
| Incorrect verdict | 153 | 19% | 99 |
| No connection constructed | 139 | 18% | 26 |
| Partial connection with proposition-valued tests | 64 | 8% | 16 |
| Agent failure, timeout, or not evaluable | 38 | 5% | 0 |
| Total | 793 | 100% | 242 |
| Certificates ( ) | Mean score (1–5) | ||||||
|---|---|---|---|---|---|---|---|
| Model | Faithful | Weak | Spurious | Spec | Test | Conn. | Genuine |
| Claude Fable 5 | 15 | 0 | 0 | 4.80 | 4.87 | 4.87 | 4.87 |
| Claude Opus 5 | 15 | 0 | 0 | 4.36 | 4.86 | 4.86 | 4.71 |
| Kimi K3 | 10 | 1 | 4 | 3.38 | 4.23 | 3.85 | 3.38 |
| GPT-5.6 Sol | 12 | 1 | 2 | 4.27 | 4.93 | 4.80 | 4.20 |
| Evaluation | Conflict (P/E) | No-conf. | Wrong | Inconcl. | |
|---|---|---|---|---|---|
| LiveCodeBench | 95 | 80 (0/80) | – | 4 | 11 |
| GitHub issues | 22 | 9 (8/1) | 1 | – | 12 |
| Model | Detected | Certified | FN | Inconcl. | FP |
|---|---|---|---|---|---|
| GPT-5.6 Sol | 57.0 [52.5, 61.5] | 51.1 [46.7, 55.5] | 8.1 [5.8, 10.6] | 34.9 [30.7, 39.2] | 6.0 [3.7, 8.6] |
| Claude Opus 5 | 70.5 [65.6, 75.1] | 47.0 [41.8, 52.1] | 4.3 [2.3, 6.6] | 25.2 [20.6, 29.8] | 3.4 [1.7, 5.4] |
| Claude Fable 5 | 72.8 [68.2, 77.4] | 49.6 [44.4, 54.7] | 6.6 [4.0, 9.2] | 20.6 [16.3, 24.9] | 4.0 [2.0, 6.3] |
| Kimi K3 | 58.5 [53.3, 63.6] | 47.9 [42.7, 53.0] | 8.6 [5.7, 11.8] | 33.0 [28.1, 37.8] | 12.0 [8.6, 15.5] |
| Run | Detected | Certified | FN | Inconclusive |
|---|---|---|---|---|
| 1 | 55.9 | 50.4 | 6.6 | 37.5 |
| 2 | 55.6 | 49.6 | 8.9 | 35.5 |
| 3 | 59.6 | 53.3 | 8.9 | 31.5 |
| Mean | 57.0 | 51.1 | 8.1 | 34.9 |
| SD | 2.24 | 1.95 | 1.32 | 3.06 |
| Method | Detected | Certified | FN | Inconcl. |
|---|---|---|---|---|
| SpecGuard | 57.0 | 51.1 | 8.1 | 34.9 |
| SpecGuard (paired tests) | 73.9 | 67.0 | 4.9 | 21.2 |
| Judge Agent ( ) | 60.2 | – | 39.8 | 0.0 |
| Python Reference (paired tests) | 74.8 | – | 3.2 | 22.1 |
| Model | Paired detected | Paired certified | ||
|---|---|---|---|---|
| GPT-5.6 Sol | 73.9 [69.3, 78.5] | +16.9 | 67.0 [62.2, 71.9] | +15.9 |
| Claude Opus 5 | 87.1 [83.7, 90.5] | +16.6 | 58.2 [53.0, 63.3] | +11.2 |
| Claude Fable 5 | 89.4 [86.0, 92.6] | +16.6 | 60.2 [55.0, 65.3] | +10.6 |
| Kimi K3 | 83.7 [79.7, 87.4] | +25.2 | 67.0 [62.2, 71.9] | +19.2 |
| Model | System / run | Cost per task |
|---|---|---|
| GPT-5.6 Sol | SpecGuard | $0.26 |
| GPT-5.6 Sol | SpecGuard (paired tests) | $0.46 |
| Opus 5 | SpecGuard | $0.43 |
| Fable 5 | SpecGuard | $0.70 |
| Kimi K3 | SpecGuard | $1.14 |
| GPT-5.6 Sol | Judge Agent ( ) | $0.84 |