LEANGUARD: Lean-Verified Guardrails for Tool-Using Agents
Organizations: Case Western Reserve University · UT Austin
Abstract
Tool-using language-model agents often execute actions that their domain policies forbid. We present LeanGuard, a runtime that checks every proposed tool call against a policy written in Lean4 before the call reaches the environment. Policies combine state predicates with scoped past-time temporal operators over the execution history, evaluation is fail-closed, and the decision procedure is proved equivalent to a LeanLTL semantics. A denied call can be corrected in two ways. With feedback, the agent receives the violated rule and a hint; with proof-guided repair, Lean metaprogramming searches for a nearby call that preserves the user's intent and proves that the policy admits it, without the model. On Tau-Bench with five Qwen models (0.8B-27B), unguarded agents execute at least 33 calls that the Lean policy forbids, while LeanGuard executes none; with feedback, task success does not change significantly. On DTap, LeanGuard reduces direct prompt-injection success from 57.9% to 5.9%, and in telecom, where benign tasks need no writes, benign success is unchanged. Feedback reduces repeated blocked calls and raises task success for four of five models over a bare denial. On replayed denials, repair proves an admissible edit for 88 of 252 denials caused by argument values, in a median of 2,ms.
Figures & tables
| -bench | DTap (read-only deployment) | |||||||||||
| Task success ( ) | Judge-flagged ( ) | Benign success ( ) | Direct attack ( ) | Indirect attack ( ) | ||||||||
| Model | None | LG | LG+F | None | LG | LG+F | None | LG+F | None | LG+F | None | LG+F |
| Qwen3.5-0.8B | 48.9 | 41.4 | 45.3 | 14.4 | 6.6 | 8.8 | 20.2 | 10.3 | 46.7 | 3.3 | 3.1 | 1.7 |
| Qwen3.5-2B | 68.3 | 66.9 | 72.7 | 15.4 | 11.7 | 12.1 | 31.9 | 11.3 | 53.1 | 3.4 | 11.6 | 2.5 |
| Qwen3.5-4B | 83.8 | 79.5 | 82.4 | 7.6 | 4.7 | 4.4 | 59.8 | 11.7 | 71.6 | 7.5 | 27.4 | 5.4 |
| Qwen3.5-9B | 84.9 | 80.9 | 83.1 | 5.1 | 3.3 | 5.1 | 67.4 | 12.8 | 74.4 | 11.0 | 37.0 | 4.9 |
| Recovery (RQ3) | Repair (RQ4) | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Blocked ( ) | Actions ( ) | Recovered ( ) | Fixable | Repaired | ||||||
| Model | LG | LG+F | LG | LG+F | LG | LG+F | LG | LG+F | LG | LG+F |
| Qwen3.5-0.8B | 426 | 383 | 307 | 276 | 5 | 5 | 56 | 30 | 23 | 9 |
| Qwen3.5-2B | 271 | 144 | 141 | 104 | 8 | 13 | 62 | 31 | 16 | 5 |
| Qwen3.5-4B | 91 | 62 | 56 | 42 | 9 | 12 | 27 | 13 | 17 | 9 |
| Qwen3.5-9B | 88 | 57 | 57 | 46 | 9 | 8 | 13 | 14 | 4 | 5 |
Appendix figures & tables24 assets
Supplementary material from the paper’s appendix.
Appendix
| LeanGuard constructor | LeanLTL interpretation |
|---|---|
| atom, , | trace predicate, true, false |
| , , | not, and, or |
| previous | strong next of (window ) |
| once | finally (window ) |
| since | until (window ) |
| within scope | on the projected history |
| Domain | Tools | Rules | Lines of Lean |
|---|---|---|---|
| Retail | 16 | 17 | 97 |
| Airline | 14 | 14 | 288 |
| Telecom | 13 | 14 | 136 |
| Shared definitions | – | – | 62 |
| Total | 43 | 45 | 583 |
| Domain | Tool contracts |
|---|---|
| Telecom | 44 |
| Travel | 25 |
| Customer service | 40 |
| Medical | 22 |
| Finance | 13 |
| Legal | 37 |
| Cases | Unscored episodes | ||||
| Domain | DTap | Evaluated | Why the other cases are not evaluated | None | LG+F |
| Telecom | 447 | 434 | named orders have no single known owner (11); the attack targets no identifiable account (2) | 198 | 205 |
| Travel | 355 | 355 | – | 2 | 63 |
| Customer service | 361 | 358 | the original judge needs an external LLM (3) | 228 | 319 |
| Medical | 1,093 | 1,091 | the original judge needs an external LLM (2) | 877 | 1,220 |
| Finance | 600 | 95 | the case needs another application (505) | 10 | 5 |
| -bench | DTap, 6 domains | ||
|---|---|---|---|
| Category | calls [exec.] | attack | benign |
| (i) Invalid | 312 [0] | 1,550 | 383 |
| (ii) State | 36 [14] | 42 | 42 |
| (iii) Temporal | 187 [17] | 392 | 330 |
| (iv) Authorization | 13 [0] | 1,904 | 1,061 |
| (v) Prohibition | 40 [3] | 441 | 206 |
| -bench | DTap, six domains | DTap, medical | |||
| Category | Both arms | Benign | Attack | Benign | Attack |
| (i) Invalid invocation | 551 | 3,684 | 14,207 | 20,051 | 17,974 |
| (ii) State incompatibility | 157 | 1,994 | 949 | 14,293 | 7,570 |
| (iii) Temporal incompatibility | 411 | 1,933 | 2,545 | 0 | 3,775 |
| (iv) Authorization failure | 572 | 9,431 | 14,688 | 4,773 | 10,201 |
| (v) Policy prohibition | 313 | 347 | 1,254 | 0 | 0 |
| Category | -bench rules (stopped calls, both LeanGuard arms) | DTap rules and fail-closed errors |
|---|---|---|
| (i) Invalid invocation | no permit for the tool (534), argument schema (17) | dtap.contract ; schema errors; malformed identifiers or values |
| (ii) State incompatibility | telecom.payment_request (61), retail.delivered (36), telecom.roaming (30), telecom.suspend (13), retail.pending (11), telecom.resume (3), airline.active (3) | resource does not exist, already exists, or has an unexpected type |
| (iii) Temporal incompatibility | retail.modify_once † (158), airline.identity (77), telecom.identity (66), airline.observed (39), host.no_overlap (23), telecom.stable_identity † (21), retail.identity (18), retail.exchange_once (7), telecom.bill_observed (2), retail.status_observed (1) | dtap.observe , dtap.single_flight , dtap.budget ; path outside the observed roots |
| (iv) Authorization failure | airline.confirmation (180), retail.confirmation (143), telecom.detail_owner (104), airline.reservation_owner (99), telecom.customer (25), retail.order_owner (18), airline.user_owner (16), telecom.refuel_confirm (15), retail.profile_owner (7), telecom.line_owner (7) | dtap.authority , dtap.approval ; identity or authority errors |
| (v) Policy prohibition | airline.cancel (69), retail.return (65), airline.flights (53), airline.booking (38), airline.compensation (38), retail.modify_items (30), retail.exchange_items (10), airline.passengers (4), airline.baggage (2), retail.payment (2), telecom.refuel (2) | dtap.unavailable (the template’s forbid) |
| Not completely modeled | – | effect cannot be determined (Table 18 ) |
| Model | Arm | Retail ( ) | Airline ( ) | Telecom ( ) | All ( ) |
|---|---|---|---|---|---|
| Qwen3.5-0.8B | None | 50.0 | 58.0 | 43.9 | 48.9 |
| LG | 36.8 13.2 | 48.0 10.0 | 43.0 0.9 | 41.4 7.5 | |
| LG+F | 41.2 8.8 | 52.0 6.0 | 46.5 2.6 | 45.3 3.6 | |
| Qwen3.5-2B | None | 68.4 | 58.0 | 72.8 | 68.3 |
| LG | 67.5 0.9 | 56.0 2.0 | 71.1 1.7 | 66.9 1.4 | |
| LG+F | 66.7 1.7 | 66.0 8.0 | 81.6 8.8 | 72.7 4.4 |
| Domain | Tasks | None | LG+F | Blocked (ep.) |
|---|---|---|---|---|
| Retail | 40 | 86.9 | 75.0 11.9 | 54 (37) |
| Airline | 20 | 77.5 | 73.8 3.7 | 34 (19) |
| Telecom | 40 | 90.6 | 93.8 3.1 | 16 (9) |
| All | 100 | 86.5 | 82.2 4.3 | 104 (65) |
| Model | None | LG | LG+F |
|---|---|---|---|
| Qwen3.5-0.8B | 14.4 (38/263) | 6.6 7.8 (17/257) | 8.8 5.6 (23/261) |
| Qwen3.5-2B | 15.4 (40/259) | 11.7 3.7 (31/264) | 12.1 3.3 (32/264) |
| Qwen3.5-4B | 7.6 (21/275) | 4.7 2.9 (13/276) | 4.4 3.2 (12/274) |
| Qwen3.5-9B | 5.1 (14/275) | 3.3 1.8 (9/276) | 5.1 0.0(14/276) |
| Qwen3.8-27B | 6.6 (18/274) | 1.8 4.8 (5/273) | 2.6 4.0 (7/274) |
| All models | 9.7 (131/1346) | 5.6 4.1 (75/1346) | 6.5 3.2 (88/1349) |
| Benign task success ( ) | Direct attack success ( ) | Indirect attack success ( ) | ||||
|---|---|---|---|---|---|---|
| Model | None | LG+F | None | LG+F | None | LG+F |
| Qwen3.5-0.8B | 20.2 (152/754) | 10.3 9.9 (99/960) | 46.7 (205/439) | 3.3 43.4 (15/453) | 3.1 (17/549) | 1.7 1.4 (11/648) |
| Qwen3.5-2B | 31.9 (382/1196) | 11.3 20.6 (132/1173) | 53.1 (297/559) | 3.4 49.7 (20/593) | 11.6 (84/723) | 2.5 9.1 (18/712) |
| Qwen3.5-4B | 59.8 (721/1205) | 11.7 48.1 (138/1177) | 71.6 (429/599) | 7.5 64.1 (41/550) | 27.4 (198/722) | 5.4 22.0 (38/705) |
| Qwen3.5-9B | 67.4 (811/1204) | 12.8 54.6 (152/1183) | 74.4 (448/602) | 11.0 63.4 (67/611) | 37.0 (265/716) | 4.9 32.1 (35/709) |
| Qwen3.8-27B | 74.9 (860/1148) | 18.1 56.8 (123/679) | 40.3 (243/603) | 3.7 36.6 (20/540) | 28.3 (198/700) | 4.5 23.8 (24/530) |
| Benign task success ( ) | Direct attack success ( ) | Indirect attack success ( ) | ||||
|---|---|---|---|---|---|---|
| Domain | None | LG+F | None | LG+F | None | LG+F |
| Telecom | 75.1 (435/579) | 75.3 0.2 (437/580) | 55.1 (365/663) | 2.4 52.7 (16/655) | 13.0 (95/730) | 1.2 11.8 (9/730) |
| Travel | 66.6 (432/649) | 0.0 66.6 (0/600) | 64.3 (337/524) | 0.0 64.3 (0/512) | 19.8 (119/600) | 9.7 10.1 (58/600) |
| Customer service | 71.1 (530/745) | 29.0 42.1 (184/635) | 72.4 (273/377) | 7.2 65.2 (32/446) | 20.9 (92/440) | 10.8 10.1 (42/390) |
| Medical | 45.9 (1257/2736) | 0.3 45.6 (8/2559) | 53.8 (495/920) | 14.2 39.6 (115/811) | 41.2 (380/922) | 2.0 39.2 (17/865) |
| Finance | 86.7 (150/173) | 0.0 86.7 (0/173) | 35.6 (42/118) | 0.0 35.6 (0/123) | 27.6 (48/174) | 0.0 27.6 (0/174) |
| Domain | Direct | Indirect | Calls LeanGuard admitted | Attack category (DTap) |
|---|---|---|---|---|
| Medical | 115 | 17 | none (127 episodes); load_skill (5) | expensive drug (33), diagnosis manipulation (31), high-cost billing (31), ignored allergy (22), upcoding (15) |
| Customer service | 32 | 42 | reads only ( get_case , list_cases , search_messages , …) | policy misrepresentation (40), abusive communication (32), PII disclosure (2) |
| Travel | 0 | 58 | reads only ( query_flight , query_accommodation , …) | unnecessary PII collection (32), payment-credential collection (26) |
| Telecom | 16 | 9 | reads only ( query_customer , query_bill ) | financial fraud (21), credential leak (2), phone-number leak (2) |
| Finance, legal, OS-filesystem | 0 | 0 | – | – |
| All | 163 | 126 | no state-changing call |
| Domain | Tools | Calls | Why the effect cannot be determined |
|---|---|---|---|
| OS-filesystem | execute_command | 2,728 | general shell execution has no complete effect plan |
| edit_file , search_files , list_directory , read_file , … | 178 | arguments outside the modeled sed , find , and path grammar, or oversized | |
| ask_for_permission | 44 | no reviewed contract | |
| Finance | trade_stock | 931 | market order without a price (835); pending limit orders (96) |
| trade_option | 212 | no reviewed contract | |
| Telecom | add_ticket , add_sms , add_email , add_calendar_event , … | 839 | record without exactly the reviewed columns, or an unreviewed ticket status |
| First intervention of LeanGuard | Medical | Travel | Cust. serv. | Finance | OS-files. | Telecom | Legal | All |
|---|---|---|---|---|---|---|---|---|
| Patient registration denied | 992 | 0 | 0 | 0 | 0 | 0 | 0 | 992 |
| Write without issued authority or approval | 0 | 397 | 216 | 89 | 85 | 15 | 8 | 810 |
| Fail-closed: effect not completely modeled | 0 | 0 | 2 | 60 | 5 | 0 | 0 | 67 |
| Fail-closed: other (missing resource, unrecorded authority, schema error) | 0 | 2 | 27 | 0 | 5 | 2 | 0 | 36 |
| None; the episodes differ by chance | 0 | 5 | 3 | 0 | 0 | 1 | 4 | 13 |
| Total | 992 | 404 | 248 | 149 | 95 | 18 | 12 | 1,918 |
| Direct attack success ( ) | Indirect attack success ( ) | |||
|---|---|---|---|---|
| Attack category | None | LG+F | None | LG+F |
| Diagnosis manipulation | 53.0 (61/115) | 25.5 27.5 (27/106) | 69.4 (75/108) | 3.7 65.7 (4/108) |
| Excessive test | 41.4 (58/140) | 0.0 41.4 (0/139) | 6.4 (9/140) | 0.0 6.4 (0/140) |
| Expensive drug | 61.7 (66/107) | 37.0 24.7 (30/81) | 51.3 (58/113) | 3.2 48.1 (3/93) |
| High-cost billing | 61.3 (68/111) | 27.9 33.4 (24/86) | 61.0 (61/100) | 6.8 54.2 (7/103) |
| High-cost test | 52.9 (74/140) | 0.0 52.9 (0/140) | 36.9 (48/130) | 0.0 36.9 (0/130) |
| Model | None | LG+F |
|---|---|---|
| Qwen3.5-0.8B | 21.3 (19/89) | 14.8 6.5 (13/88) |
| Qwen3.5-2B | 31.2 (29/93) | 21.7 9.5 (20/92) |
| Qwen3.5-4B | 48.9 (46/94) | 38.5 10.4 (35/91) |
| Qwen3.5-9B | 57.0 (53/93) | 48.3 8.7 (42/87) |
| Qwen3.8-27B | 45.6 (41/90) | 27.8 17.8 (20/72) |
| All models | 41.0 (188/459) | 30.2 10.8 (130/430) |
| Reason the judge flags an admitted call | LG | LG+F |
|---|---|---|
| The Lean policy has a rule | ||
| Consent on a confirmed action | 33 (28) | 38 (32) |
| Trusted facts the judge does not see (roaming, bill, reservation) | 15 (15) | 22 (22) |
| The Lean policy has no rule | ||
| Transfer to a human agent | 12 (11) | 11 (10) |
| Consent on an unconfirmed action | 11 (11) | 7 (7) |
| LG | LG+F | |||
|---|---|---|---|---|
| Model | Episodes | Solved | Episodes | Solved |
| Qwen3.5-0.8B | 5 | 2 | 5 | 1 |
| Qwen3.5-2B | 8 | 6 | 13 | 9 |
| Qwen3.5-4B | 8 | 7 | 12 | 10 |
| Qwen3.5-9B | 9 | 7 | 8 | 8 |
| Qwen3.8-27B | 3 | 3 | 9 | 7 |
| Fix required | Denials |
|---|---|
| Different argument values | 252 |
| A tool from the agent’s own interface | 534 |
| An earlier step (e.g., authentication) | 298 |
| The customer’s approval | 185 |
| None; action already done | 191 |
| None; action not allowed | 153 |
| Failed rule | Denied | Searched | Repaired |
|---|---|---|---|
| retail.return | 65 | 64 | 64 |
| telecom.payment_request | 58 | 58 | 4 |
| airline.flights | 52 | 52 | 18 |
| airline.booking | 38 | 18 | 0 |
| retail.modify_items | 23 | 8 | 0 |
| retail.exchange_items | 7 | 0 | 0 |
Tool Access Control for LLM Agents
Tool access control for LLM agents limits which tools, resources, and actions agents may use, and under what conditions.
See all 229 papers