Prerequisites
Description
Lean accepts a checked declaration containing a projection whose structure name does not match the value being projected.
The repro below uses the ordinary checked addDecl path. It then proves False with no axioms. It does not use sorry, unsafeCast, debug.skipKernelTC, addDeclWithoutChecking, FFI, or a modified .olean file.
Context
Found while reviewing a proof by @xrchz of the Collatz Conjecture in less than 300 lines:
https://github.com/xrchz/CollatzLean/blob/a79357462a33d2a6babd4cf6c8d8bcd25425d653/Collatz/Main.lean
I found related projection and soundness reports, but this appears to be distinct.
Steps to Reproduce
- Save this file as
Bug.lean.
import Lean
open Lean Elab Command
inductive P : Prop where | mk (b : Bool)
structure C where b : Bool
inductive W : Type where | mk (p : P)
inductive L (α : Type) (b : Bool) : Type where | mk
inductive T : Bool → Prop where | mk : T true
def pad (e : Expr) (n : Nat) : Expr :=
mkApp (mkLambda `x .default (mkConst ``Nat) e) (.lit (.natVal n))
meta def build : CommandElabM Unit := do
let f := pad (mkConst ``Bool.false) 78670
let t := pad (mkConst ``Bool.true) 24083
unless f.hash == t.hash && f.approxDepth == t.approxDepth do
throwError "hash collision failed"
let fw := mkApp (mkConst ``W.mk) (mkApp (mkConst ``P.mk) f)
let tw := mkApp (mkConst ``W.mk) (mkApp (mkConst ``P.mk) t)
let w := mkBVar 0
let Ew := mkApp (mkConst `E) w
let b := mkProj ``C 0 (mkProj ``C 0 w)
let l := mkApp2 (mkConst ``L) Ew b
let Et := mkForall `w .default (mkConst ``W) (mkSort 1)
let ct := mkForall `w .default (mkConst ``W) <|
mkForall `l .default l (mkApp (mkConst `E) (mkBVar 1))
liftCoreM <| addDecl <| .inductDecl [] 1 [{
name := `E, type := Et, ctors := [{ name := `E.mk, type := ct }] }] false
let Et := mkApp (mkConst `E) tw
let l := mkApp2 (mkConst ``L.mk) Et (mkConst ``Bool.true)
liftCoreM <| addDecl <| .defnDecl {
name := `e, levelParams := [], type := Et,
value := mkApp2 (mkConst `E.mk) tw l,
hints := .abbrev, safety := .safe }
liftCoreM <| addDecl <| .defnDecl {
name := `good', levelParams := [],
type := mkApp (mkConst ``T) t, value := mkConst ``T.mk,
hints := .abbrev, safety := .safe }
let Ef := mkApp (mkConst `E) fw
let Et := mkApp (mkConst `E) tw
let a := mkApp2 (mkConst `E.mk) fw (mkProj `E 0 (mkConst `e))
let tl := mkApp2 (mkConst ``L.mk) Et (mkConst ``Bool.true)
let b := mkApp2 (mkConst `E.mk) tw tl
let cT := mkApp2 (mkConst ``L) Et t
let c := mkApp (mkLambda `l .default cT (mkConst ``Unit.unit)) tl
let fl := mkApp2 (mkConst ``L.mk) Ef f
let d := mkApp2 (mkConst `E.mk) fw fl
let v := Expr.letE `a Ef a
(.letE `b Et b
(.letE `c (mkConst ``Unit) c
(.letE `d Ef d (mkConst `good') true) true) true) true
liftCoreM <| addDecl <| .thmDecl {
name := `bad, levelParams := [],
type := mkApp (mkConst ``T) f, value := v }
elab "mkbug" : command => build
mkbug
theorem boom : False := nomatch (bad : T false)
#print axioms bad
#print axioms boom
- Run:
- Lean accepts the file.
Expected behavior: Lean should reject the declaration of E, because its constructor type contains C projections applied to a W.
Actual behavior: Lean accepts the file and prints:
'bad' does not depend on any axioms
'boom' does not depend on any axioms
Versions
Lean (version 4.34.0-nightly-2026-07-27, arm64-apple-darwin24.6.0, commit 0bfc3acaef4ed0576307a77fbaa0c6e1a5dca402, Release)
OS:
Impact
Add 👍 to issues you consider important. If others are impacted by this issue, please ask them to add 👍 to it.
The issue affects checked-kernel soundness. An adversarial metaprogram can add declarations that ordinary Lean code then uses to prove False, with #print axioms reporting no axioms.
Prerequisites
https://github.com/leanprover/lean4/issues
Avoid dependencies to Mathlib or Batteries.
https://live.lean-lang.org/#project=lean-nightly
(You can also use the settings there to switch to “Lean nightly”)
Description
Lean accepts a checked declaration containing a projection whose structure name does not match the value being projected.
The repro below uses the ordinary checked
addDeclpath. It then provesFalsewith no axioms. It does not usesorry,unsafeCast,debug.skipKernelTC,addDeclWithoutChecking, FFI, or a modified.oleanfile.Context
Found while reviewing a proof by @xrchz of the Collatz Conjecture in less than 300 lines:
https://github.com/xrchz/CollatzLean/blob/a79357462a33d2a6babd4cf6c8d8bcd25425d653/Collatz/Main.lean
I found related projection and soundness reports, but this appears to be distinct.
Steps to Reproduce
Bug.lean.Expected behavior: Lean should reject the declaration of
E, because its constructor type containsCprojections applied to aW.Actual behavior: Lean accepts the file and prints:
Versions
OS:
Impact
Add 👍 to issues you consider important. If others are impacted by this issue, please ask them to add 👍 to it.
The issue affects checked-kernel soundness. An adversarial metaprogram can add declarations that ordinary Lean code then uses to prove
False, with#print axiomsreporting no axioms.