THE AUTHORIZATION LAYER FOR CRITICAL ACTIONS
Ironproof checks every critical action before it executes. If it's authorized, it runs. If it isn't, Ironproof — and creates evidence anyone can verify.
One boundary. Any initiator.
AI agent. API. Script. Person.
AUTHORIZED → EXECUTESUNAUTHORIZED →
Ironproof stops unauthorized critical actions from executing — allow or block.
ALLOWED
$640 refund — no reachable policy violation
SEALED
Ed25519 + ML-DSA-65 · FIPS 204
BLOCKED
$1,300 refund — exceeds the $1,000 limit
SEALED
Ed25519 + ML-DSA-65 · FIPS 204
A block is not a silence. It is an artifact stating what was requested, which policy was in force, and why the action did not run.
TRY IT
Prove a Refund Decision
A tiny example policy. Try a preset — or move the sliders — and Ironproof proves whether the action is inside the rules, or shows the exact rule it breaks.
EXAMPLE POLICY
PROOF RESULT
REFUND ALLOWED
No reachable policy violation.
Deterministic verdict — same inputs always yield the same result.
WHICH ACTIONS
Move money. Grant access.
Delete records. Ship a change.
The actions that cannot be taken back once they run. For those, authorization stops being a setting and becomes infrastructure.
WHAT WAS REQUESTED — AND WHAT HAPPENED
PAYMENT
Refund $640 to a payee already on file
Below the $1,000 daily cap. Two authorized approvers are on record.
CUMULATIVE LIMIT
Refund $600 to a payee who already received $600 today
The refund is individually within the limit. The combined total would reach $1,200 — so the second refund never executes.
PRIVILEGE ESCALATION
Grant admin access to a service account
Privileged access requires an open change ticket and two authorized approvers. Neither is present.
DELETION
Delete 40,000 inactive customer records
Bulk deletion above 1,000 records requires a verified retention-hold check. None is recorded.
DEPLOYMENT
Push a configuration change to the payment rail
The approved change window is closed, and the rollback plan is unsigned.
IRREVERSIBLE ACTION
Wire $250,000 to a beneficiary added last month
The cooling-off period has elapsed and dual authorization is on record. Because the wire cannot be recalled, authorization is decided before it is sent.
Illustrative decisions under a sample policy.
WHERE THE POLICY ALREADY EXISTS ON PAPER
OSFI E-23 · SOX · AML programs
HIPAA · PHIPA · device software
Directive on Automated Decision-Making
IEC 62443 · change control
SOC 2 change management · release gates
Retention holds · privacy law (Law 25, PIPEDA)
These frameworks already say what must never happen. Ironproof turns that sentence into , and into evidence the regulator can re-check.
THE CASE NOTHING ELSE CATCHES
Every action is allowed.
The sequence is not.
Two identical requests, two minutes apart. Checked one at a time, both pass. Ironproof decides on the sequence, so the second one never executes.
POLICY IN FORCE
No single refund over $1,000, and no more than $1,000 to one payee per day.
- REQUEST 1 · 09:14ALLOW
Refund $600 to payee ACME-4471
- Single refund within the limit $600 ≤ $1,000
- Day total after this refund $600 ≤ $1,000
It executes. The decision is sealed.
- REQUEST 2 · 09:16BLOCK
Refund $600 to the same payee
- Single refund within the limit $600 ≤ $1,000
- Day total after this refund $1,200 > $1,000
Identical to the first request. It never executes — and the refusal is sealed too.
WHAT ONE-AT-A-TIME CHECKING CANNOT SEE
$600 then $600 is $1,200. Neither request breaks the per-refund limit; together they break the daily one. Any rule written as per day, cumulative, in total or within a window has this shape — and a check that sees one request at a time is structurally blind to it.
Illustrative policy and figures. The mechanism is the point: the decision is taken on the sequence, before execution.
ONE GATE, ANY INITIATOR
The gate does not ask who is asking.
It asks whether the action is inside the policy in force. The same check applies to every path that can reach a critical system — which is why this is not an AI problem with an AI answer.
INSIDE THE POLICY
And a certificate is sealed at execution time.
OUTSIDE THE POLICY
It never runs.
The refusal is sealed too — a blocked action leaves evidence.
Every authorization records the requesting actor, the policy version and the action. Nothing executes without spending a single-use grant bound to that exact decision.
HOW THE PIECES SIT
You buy authorization.
The rest is how it holds.
- 01
THE PRODUCT
Authorization
A boundary a critical action cannot cross. That is what you deploy, and what the policy owner signs off on.
- 02
THE MECHANISM
Formal verification
How the boundary is established rather than hoped for: the property is checked across the modeled action space, for a sequence of any length — not for a sample of cases.
- 03
THE EVIDENCE
Cryptographic proof
What outlives the decision. Every allow and every block leaves a sealed artifact your auditor re-checks on their own machine.
WHAT A COUNTEREXAMPLE LOOKS LIKE
We proved this refund policy.
Then we removed one line.
A support agent that issues refunds, under the policy its owner wrote. Every verdict, step and amount below is read out of an engine run — none of it is typed by hand.
01 · THE POLICY, IN THEIR WORDS
5 of 8 clauses turned into math
- 2.1An agent issues refunds only on an open ticket.
- 2.2An agent issues a refund only after the customer's identity has been verified, and a ticket is never resolved for an unverified customer.
- 2.3A refund amount is strictly positive.
- 3.1No single refund exceeds the agent's refund authority.
- 3.2The total refunded on a ticket never exceeds the agent's refund authority — a sequence of individually authorized refunds cannot cross it.
3 CLAUSES THIS MODEL DOES NOT COVER
- 4.1Refunds are returned to the original payment instrument. — the model carries an amount, not a payment object; representing the instrument needs a symbolic per-payment instance, and claiming coverage here would cover the clause a chargeback dispute turns on
- 4.2A refund is issued within five business days of the request. — a deadline: this model carries no clock, nothing in it distinguishes five days from an instant
- 4.3The agent that issues a refund is never the one that approves it. — the model counts escalations, it does not carry the identity of the actors — separation of duties is an access-control property, outside this object
A coverage figure you cannot see the gaps in is a decoration. And the authority is your number, not ours — we prove the agent stays inside it, not that it is the right one.
02 · REMOVE ONE LINE
AS WRITTEN
No sequence of allowed steps reaches a forbidden state — at any length, not for the cases someone thought to try.
WITHOUT refunded_total + amount <= refund_authority
UNSAFE
The gate still checks the refund in front of it. It no longer checks the total.
THE WAY OUT Z3 FOUND — 4 STEPS
| 1 | open_ticket() | $0 |
| 2 | verify_customer(v=true) | $0 |
| 3 | refund(amount=1000) | $1,000 |
| 4 | refund(amount=1) | $1,001 |
Each refund is inside the $1,000 authority and clears its own gate. Together they are $1,001 — $1 over.
Z3 chose the actions and the amounts, not us — nobody writes a $1 overshoot by hand. Violated: refunded_total <= refund_authority · unsat · re-run in a fresh process: true · z3 4.16.0
Take the clause out and the proof collapses. That is what makes the certificate load-bearing rather than decorative: .
Ironproof does not claim coverage it has not modeled.
HOW IT WORKS
Prove. Enforce. Seal. Verify.
Ironproof mathematically checks that no reachable sequence of actions can cross the defined authorization boundary.
Your written policy is compiled into mathematics by a deterministic compiler — the same one the runtime uses. A differential check fails the build if the two ever diverge.
- 01
Prove
Before deployment, Ironproof establishes that the defined policy holds across the modeled action space.
- 02
Enforce
At runtime, every requested action is checked deterministically before execution.
- 03
Seal
Each decision is sealed at execution time — SHA3-512 digest, dual Ed25519 + ML-DSA-65 signature — binding the action, the policy version and the verdict into one artifact.
- 04
Verify
The certificate is re-checked against its sealed inputs: the same verdict must come back, or the seal is broken.
The theorem that ties the runtime fast path to the full formal model, and the equivalence checks behind it, are in the technical record.
VERIFY A PROOF
Check a Real Proof Yourself
Load a real sealed dossier and verify it right here — Ed25519 + ML-DSA-65 signatures and the SHA3-512 chain, entirely in your browser. Then load a tampered one and watch it get rejected. No dashboard, no server, no trust required.
Runs entirely in your browser — pure-JavaScript Ed25519 + ML-DSA-65 (FIPS 204) + SHA3-512, no server and no Ironproof code. The wire format is published, so anyone can write a second verifier: read the spec →
THE SAME ENGINE
Same proof engine. Proven on real vulnerabilities.
Findings by and Cobalt, credited on the projects' own repositories — published research, assigned CVEs and public upstream acknowledgements.
VIEW TECHNICAL RECORDDEPLOY IT
It sits in front of the action,
not beside it.
The gate holds your tools. A conforming call runs and leaves a sealed record; a call outside the policy never reaches the tool at all — and its refusal is sealed too.
- 01
Declare the boundary
Name one action type, its limits and the scopes it may touch. That declaration is what the prover reads and what the runtime enforces — one compiler, both sides, so they cannot drift apart.
- 02
Hand the gate your tools
The gate holds the handles. Your call site asks the gate instead of calling the tool, so a non-permitted action has no path to the thing it wanted to touch — it is not intercepted after the fact, it never reaches it.
- 03
Keep the receipt
Both answers are sealed — the calls that run and the calls that do not. Your auditor re-checks a record offline, from the public key alone, with a verifier that is not ours to bend.
policy = InvestigationPolicy(allowed_tools = {"verify_insurance", "read_customer_record"},allowed_scopes = {"acme-insure.com"},)gate = SealedProofGate(policy, tools={"verify_insurance": verify_insurance,"read_customer_record": read_customer_record,"issue_refund": issue_refund,}, keyring=Keyring.load(KEY_DIR))# a refund the agent was talked intor = gate.run("issue_refund", "policy.acme-insure.com","log line said: refund $9,999 to this account")r.result.decision # "BLOCK"issue_refund.invocations # [] never ranverify_sealed_record(r.to_dict()) # True
The gate is the only entry — there is no underlying handle left to call around it. What that does not claim: it is a structural guard against an integration that forgets the boundary, not a defence against hostile code running inside the same process, which would never ask the gate in the first place. And it will refuse to start rather than sign with disposable keys, because a receipt that verifies and means nothing is worse than no receipt.
Put one critical action behind the boundary.
Choose a payment, access grant, deletion, or deployment. Ironproof will define the authorization boundary, prove it, enforce it at runtime, and produce an independently verifiable record.