Skip to content

01Thesis

Proven, not just tested.

Scope-Forge treats a policy as mathematics: every question about it is answered exactly, at build time, by a compiler whose own code is machine-checked with Verus. A proof covers every possible input, so the logic it covers has no untested case, which is exactly the case an attacker accelerated by AI searches for.

Why now. In 2026 Google's Threat Intelligence Group reported, for the first time, a threat actor using a zero-day exploit developed with AI, with "high confidence that the actor leveraged an AI model to support the discovery and weaponization of this vulnerability": a script that "enables the user to bypass two-factor authentication (2FA) on a popular open-source, web-based system administration tool" (Google Threat Intelligence Group, May 2026).

In November 2025 Anthropic reported a campaign in which "the threat actor was able to use AI to perform 80-90% of the campaign, with human intervention required only sporadically", at "an attack speed that would have been, for human hackers, simply impossible to match" (Anthropic, November 2025). In August 2026 the NSA, CISA, FBI, Department of Energy and EPA jointly advised that AI-generated exploitation scripts are "dramatically reducing the technical expertise and time required to develop working ICS exploitation scripts and malicious tools" (joint advisory, August 2026).

"31% of breaches now start with software vulnerabilities, beating stolen passwords as the top way attackers get in" (Verizon 2026 DBIR), and "the time between disclosure and exploitation has shrunk to days" (UK NCSC, May 2025). Testing checks the cases someone thought of; a proof has none.

  1. 001A policy describes exactly which requests are allowed; granting access is checking whether a request belongs to that set.In plain terms: Every access decision is one membership check.
  2. 002A policy that contradicts itself, or that no request could ever satisfy, does not build.In plain terms: Caught before anything is deployed.
  3. 003A security rule written into the policy is checked against every possible record; a change that breaks it stops the build with a counterexample.In plain terms: The rule cannot quietly erode over years of edits.
  4. 004Every policy question is decided by Scope-Forge's own verified set arithmetic; no solver runs when a policy is checked.In plain terms: The identical result on any machine.
  5. 005Policies compile ahead of time, through a verified back end, to native machine code.In plain terms: The policy that was proved is the policy that runs.
  6. 006Compiled policies integrate with existing applications and specialized systems through a dedicated Scope-Forge code generator.In plain terms: It fits the systems you already run.

If you run OPA or Cedar today: they evaluate each request against the policy you deployed, and Cedar's analysis can check a policy set when you run it. Scope-Forge makes the check the build: a contradiction does not compile, every security rule is held against every possible record, and the code that decides each request is itself machine-checked.

Go deeper: Type Algebra.

02Assertions

Security rules the build cannot skip.

Write the policy, not the proof. Write "contractors can never hold a clearance that permits restricted reads" into the policy once, and no later change can break it without the build failing, showing your reason, and producing the exact record that would have slipped through.

Below, that sentence as an assertion.

contractor-clearance.sf

Principal requires {
    employment: str where in "employee" || "contractor"
    clearance: str where in "none" || "confidential" || "secret"
}

Contractor requires Principal && {
    employment: str where == "contractor"
    clearance: str where == "none"
}

RestrictedRead requires Principal && {
    clearance: str where in "confidential" || "secret"
}

assert Contractor never in RestrictedRead
    because "contractors never hold a clearance that permits restricted reads"

accepted: 3 declarations, 1 assertion, 0 contradictions

The proof point, written as policy: contractors are never inside the set that permits restricted reads.

Months later, an edit grants contractors a confidential clearance.

contractor-clearance-edit.sf

Contractor requires Principal && {
    employment: str where == "contractor"
    clearance: str where in "none" || "confidential"
}

rejected: 1 assertion failed

The later edit: contractors are granted a confidential clearance.

contractor-clearance.sf

error: assertion failed: Contractor never in RestrictedRead

  because "contractors never hold a clearance that permits restricted reads"
  counterexample, a record in both sets
    { employment: "contractor", clearance: "confidential" }

The failed build shows the author's reason and a record that is in both sets.

An assertion relates two sets: in (a subset), not in, never in (no record in both), equal and not equal.

03Comparison

Against Cedar, OPA and XACML.

Cedar, behind Amazon Verified Permissions, is modeled and proved in Lean; its Rust engine is checked against that model by differential random testing, not proved. OPA evaluates Rego policies when an application queries it, and a XACML Policy Decision Point evaluates XML policies per request; OPA ships a test framework. Sources: How We Built Cedar; cedar-spec; cedar-policy-symcc; Cedar syntax; OPA; OPA testing; XACML 3.0.

Scope-Forge compared with Cedar
CriterionScope-ForgeCedar
The engine itselfMachine-checked with Verus, an SMT-backed verifier for Rust, for every possible input.A Lean model with proofs; the Rust engine is checked against it by differential testing, not proved.
A contradictionA compile error: why, where and a suggested fix.A validator warning, not an error; cedar symcc can prove an always-denying policy set when run, and at request time a deny from any forbid policy overrides an allow.
The author's security ruleWritten into the policy with a reason and checked against every possible record at every build; a breaking change stops the build with a counterexample.A separate analysis, cedar symcc, decides subsumption and disjointness with the cvc5 SMT solver and returns a counterexample when run.
Outside solverNone at policy-check time: its own verified set arithmetic, no time-outs. The compiler's own proofs are discharged by Verus when the compiler is built.The analysis above compiles policies to SMT-LIB and runs cvc5, and is itself verified in Lean; evaluation uses none.
ExecutionCompiled ahead of time, through a verified back end, to native machine code with no garbage collector.Evaluated per request by the Cedar engine or Amazon Verified Permissions.

The engine itself

Scope-Forge
Machine-checked with Verus, an SMT-backed verifier for Rust, for every possible input.
Cedar
A Lean model with proofs; the Rust engine is checked against it by differential testing, not proved.

A contradiction

Scope-Forge
A compile error: why, where and a suggested fix.
Cedar
A validator warning, not an error; cedar symcc can prove an always-denying policy set when run, and at request time a deny from any forbid policy overrides an allow.

The author's security rule

Scope-Forge
Written into the policy with a reason and checked against every possible record at every build; a breaking change stops the build with a counterexample.
Cedar
A separate analysis, cedar symcc, decides subsumption and disjointness with the cvc5 SMT solver and returns a counterexample when run.

Outside solver

Scope-Forge
None at policy-check time: its own verified set arithmetic, no time-outs. The compiler's own proofs are discharged by Verus when the compiler is built.
Cedar
The analysis above compiles policies to SMT-LIB and runs cvc5, and is itself verified in Lean; evaluation uses none.

Execution

Scope-Forge
Compiled ahead of time, through a verified back end, to native machine code with no garbage collector.
Cedar
Evaluated per request by the Cedar engine or Amazon Verified Permissions.

04Contradiction

A contradiction does not build.

The compiler says exactly why and where, with a suggested fix. Two rules whose requirements cannot both be met leave an empty set, and an empty set is a compile error.

contradictory-policy.sf

Cleared requires {
    clearance: num where in 4..5
}

Probationary requires {
    clearance: num where in 1..2
}

ProbationaryRelease requires Cleared && Probationary

rejected: 3 declarations, 1 contradiction

A contradictory policy and the report it produces.

contradictory-policy.sf

error: cannot admit `ProbationaryRelease.clearance`: no value satisfies the policy

  Cleared.clearance
    admits 4..5
  Probationary.clearance
    admits 1..2
  the intersection is empty
  help: widen one range until 4..5 and 1..2 overlap, or do not compose them

05No solver

No third-party solver in the decision.

The same answer on every machine, with no time-outs and no machine-dependent limits. When a policy is checked, Scope-Forge's own verified set arithmetic decides every question and no solver runs. The compiler's own proofs are discharged by Verus, an SMT-backed verifier for Rust, when IronVelo builds the compiler. What is proved: the compiler and the core libraries are machine-checked with Verus for every possible input, so the set arithmetic that decides each policy question is proved, not tested; the checked policy is then lowered into Pancake and compiled by the formally verified CakeML back end. Every verified system trusts its toolchain. Scope-Forge's trusted base is small, and every item on it is listed.

06Roles

Attributes, roles, or both.

Groups are described by what their members are and combined freely, so a person in several groups is natural. A role builds on any number of parent roles, and the whole hierarchy is checked at compile time.

scope-product.sf

DayShift requires {
    hour: num where in 6..18
    clearance: num where in 1..4
}

Mission requires {
    hour: num where in 10..22
    clearance: num where in 2..5
}

MissionDay requires DayShift && Mission

accepted: 3 declarations, 0 contradictions

MissionDay: hour 10..18, clearance 2..4

A role built on two parents: the region both admit.

A rule can also relate one field to another field of the same record: the approver must not be the requester; the request time must be before the credential's expiry. The relation is a comparison (before, after, at most, at least, equal, not equal) against the other field's resolved value, across nested records. Below, the expiry rule.

live-request.sf

PositiveTime: num where > 0

Request requires {
    expires: PositiveTime
    now: PositiveTime
}

Live requires Request && {
    now: PositiveTime where < resolved This.expires
}

Stale requires Request && {
    now: PositiveTime where >= resolved This.expires
}

assert Stale never in Live
    because "a request made at or after its credential's expiry is never live"

accepted: 4 declarations, 1 assertion, 0 contradictions

The request time must be before the credential's expiry: one field compared with another field of the same record.

Go deeper: Numeric Sets for rules on numbers, and Regular Languages for rules on text.

07Review

Built for review.

Definitions are private unless explicitly exported, and every import is explicit, so every permission can be traced to its origin. A reviewer audits a changed module through its imports alone: audits scale with the size of the change, not of the whole policy base.

shared-clearance.sf

use ops::Mission

Escort requires {
    clearance: Mission.clearance
    sector: Mission.sector
    speed_kts: num where in 120..450
}

pub relay_clearance: num where in Mission.clearance && != 5

accepted: 1 import, 2 declarations, 0 contradictions

One explicit import, one explicit export.

08Runtime

Native machine code, no collector.

The exact form verified at compile time is the form that runs: native machine code for ARMv7, ARMv8, x86-64, RISC-V, MIPS-64 and Silver, with no garbage collector, from data center servers to low-power field equipment. Scope-Forge lowers a policy into Pancake, the low-level language of the formally verified CakeML toolchain, which compiles it to native code. A compiled policy is native code that an existing application calls, generated for it by the Scope-Forge code generator, and runs beside the systems already in place. Everything decided at compile time is removed, so the running system executes only the checks that remain.

Go deeper: Native Code.

09Cross-domain

Classification labels and cross-domain rules.

An application of the approach, not a cross-domain product: the same set-based policies and compile-time checks apply to the policy layer of a cross-domain rule set, classification labels and the rules for moving data between security domains, as sets checked at build time.

cross-domain-band.sf

Label requires {
    level: num where in 0..4
    marking: str where in "NOFORN" || "REL" ++ (" " ++ ("A".."Z")+)+
}

CrossDomainTransfer requires Label && {
    level: num where in 1..3
    marking: str where not in "NOFORN"
}

accepted: 2 declarations, 0 contradictions

A transfer band between security domains, expressed as a set of labels.

Forged to secure IronVelo's own identity provider. Ready to secure yours.