Freedom, dignity, and justice for Palestinians.

Documentation / How analysis works

How analysis works

How Verifpal executes a model, derives attacker knowledge and searches for attacks.

A result depends on the attacker’s capabilities, the executions searched and the conditions under which a failure is recorded. This guide explains each of these. The companion paper (Kobeissi 2026) gives formal definitions of the language, the primitive rules and the queries.

From model to result

Verifpal processes a model in four stages:

  1. Read the source. The parser identifies declarations, assignments, messages, phases, scenarios and queries. It reports a source location when the syntax is invalid.

  2. Expand the runs. Scenarios create copies with different peer bindings. Session replication creates the requested number of runs of each principal. Generated values become distinct in each copy; long-term knowledge stays shared.

  3. Check the model. Verifpal checks names, knowledge, message uses, primitive arguments, query options and phase numbers. It also evaluates the baseline computations. A failed checked primitive in a run that is honest when the check runs is a model error; a corrupt-peer run may halt legitimately.

  4. Analyze and report. The engine executes the protocol honestly and computes what the attacker learns from it. When the attacker is active, it then searches for permitted message substitutions, running each candidate as a complete execution of the model. Queries are evaluated on every execution. A contradicted query receives a trace of the execution that contradicts it; a passing query receives a description of the search limits.

A parse or validation error means Verifpal could not analyze the model. Fix the error and run it again. A valid model can still describe an insecure protocol.

An analysis combines three activities. Execution runs every principal of the model, in every session and scenario copy, under a chosen set of attacker substitutions. Deduction computes what the attacker can learn from what that execution discloses. Search chooses which substitutions to execute. Only an execution can contradict a query; search decides which executions to try.

Execution

An execution runs each principal copy at most once, performing its actions in the order the model declares them. The attacker may leave a copy unstarted, as though that session never began. Principals advance whenever they can, so their actions interleave. Phases are barriers: no principal performs a phase 1 action until every principal that can still move has finished phase 0.

Queries are evaluated at the end of every phase, on the state every principal copy has reached by then and the attacker knowledge of that phase. Because each copy runs at most once and every substituted value is derived from earlier disclosures in the same execution, a later output cannot justify an earlier delivery, and the attacker cannot combine what two incompatible runs of the same principal would have revealed. No separate check has to reconstruct a consistent history afterward: the execution is that history.

Deduction

The attacker starts with public values and learns every value a principal sends or leaks during the execution. It then applies the primitive deduction rules to the available terms.

New knowledge can enable another rule: a leaked key opens a ciphertext, its plaintext supplies a hash input, and that hash may be another decryption key. Deduction continues until another pass adds nothing. This is the fixed point or knowledge closure.

The set of terms the attacker could construct is infinite: it could keep hashing public values, for example. Verifpal uses a finite set of relevant terms and checks whether others can be constructed as needed. It records how it obtained each value; the attack trace is built from these records. Knowledge belongs to one execution. What the attacker learns in one execution cannot be spent in another.

A passive attacker changes no messages. Its analysis therefore needs only the honest execution, including the declared session and scenario copies. Later phases may disclose keys that open previously recorded traffic.

An active attacker can replace permitted network inputs. Verifpal first analyzes the honest execution, then works backward from queries that remain unresolved. For a confidentiality query on an encrypted message, the search may ask how the attacker could obtain the decryption key. If the key comes from an unauthenticated Diffie–Hellman exchange, that question suggests replacing a public key.

The solver represents inputs the attacker can control as variables, then looks for values to assign to them. Some replacements must be made together: replacing an identity key without its signature would fail the recipient’s check. A compatible set of replacements is a proposal, and each proposal is run as an execution.

The search also tries patterns that a single backward goal may miss: changing one field while leaving others honest, rebuilding the inputs of a check that stopped an execution, forwarding related fields together from another session, filling in the rest of a partly replaced message, leaving one copy of a sender unstarted so that another copy’s value can be delivered in its place, and building a tuple from values the attacker already holds. If replacing an input with a variable hides a useful honest computation, a refinement restores that input and tries again. These methods can find more attacks, but still miss some.

The search pools what the attacker learned across the executions it has tried, but only to choose new proposals. A proposed value that only another execution produced is not delivered on that basis: the search runs the two sets of substitutions together, and the value is delivered only if the combined execution actually produces it first. Search ends when every query has a contradiction or when a complete round teaches the pool nothing new. Finding one counterexample is enough to fail a query; the report is not a catalog of every possible attack on it.

An execution delivers a proposed replacement only when:

A replacement that never becomes derivable leaves its recipient waiting. The principal’s ordinary computations and checks then determine what happens. For example, a signature the attacker cannot construct is never delivered, even if it would pass the recipient’s check.

What each principal sees

Each principal keeps its own copy of the values it knows. If the attacker changes a message from Alice to Bob, Alice retains what she sent and Bob receives the replacement. A name such as e can therefore resolve differently in their states.

The engine calls each stored local value a slot. A slot records the value before and after rewriting, which principal sent it, and whether the attacker supplied it, either directly or through an honest principal that forwarded a value it received from the attacker.

These distinctions explain several query results. A confidentiality query may concern a received replacement rather than the original secret. An authentication query asks about the accepted sending, so an honestly forwarded value must retain its sender. An equivalence query compares values that were actually reached in the same execution.

A slot is controllable only if it is an eligible received value in the phase being analyzed. Locally generated secrets cannot be replaced directly. The search considers received values used in computations and values named by equivalence queries, even when those queried values have no later primitive use.

Search limits

The active search uses these limits to keep the number of terms and executions finite:

When a proposal exceeds the depth bound, a diagnostic identifies the affected term and slot. Every query still unresolved at that point carries [search truncated: term depth] if it passes. The flag does not mean that the rejected proposal would have affected that query. A query unresolved when the solver runs out of variables carries [search truncated: solver variables] instead.

Otherwise, a pass includes a note such as [search exhausted at 2 sessions]. This means Verifpal finished its search, not that it checked every symbolic execution at two sessions. It can miss an attack requiring an unsupported term structure without issuing a truncation warning.

Reading an attack trace

A trace narrates the execution that contradicts the query and ends with the condition it violates. Read the conclusion first to identify the claimed failure, then follow the steps that support it. Substitutions appear in the order the execution delivered them, each after the observations and deductions that let the attacker build it; the deductions behind the final violation come last.

HTML and LaTeX reports also show these steps in an attack diagram, with the same numbers as the text trace. The compact result code records only pass or fail; it omits the explanation and any subtype qualifier.

Reducing a trace

The execution that first contradicts a query may carry substitutions it does not need, such as changes made for another query. Before reporting a failure, Verifpal removes one substitution at a time, or two from the same message, runs the execution again and keeps each removal while the same query still fails in the same phase. It repeats until nothing more can be removed, then narrates the resulting execution.

The reported trace is minimal only with respect to these removals; a different set of substitutions might explain the same failure more simply. The chosen execution and its step order may change between versions even when the same query fails.

What a result establishes

A reported failure is a violation of the query’s defined condition in one execution of the model: each principal copy ran at most once, and every substituted value was derivable from what that execution had already disclosed. The trace narrates that execution. Only the query evaluator, applied to an execution, records a failure. The solver can miss attacks, but a solver defect alone cannot report one.

A result can still be wrong if the parser, primitive rules, executor or query definitions contain defects. The model can also misrepresent the implementation: an execution of the model is a symbolic execution of what the model says, not of the deployed code.

Sessions and execution histories

Session replication gives each run its own generated values and shares long-term knowledge. Assignments with different session names may still compute equal terms from shared inputs.

In one execution, each session copy runs at most once with its own generated values; nothing restarts a run or reuses its nonce in a second history, and a copy the attacker leaves unstarted takes no action at all. The attacker can route messages between copies: an unguarded receive may take a value that another copy sent, and the trace labels such a delivery a replay. Copies of the same principal share long-term keys, so one copy can supply a value, or reach a leak, that another copy needs. The search tries many executions, but a finding always comes from one of them.

Check a finding by reconstructing each participant’s actions from the trace, including which copy sent and received each value, and comparing them with the query’s exact condition.

For choosing a session count and comparing successive counts, see the command-line guide.

What the model leaves out

The language also limits what a model can represent:

If you need an unbounded proof, behavioral equivalence or algebra outside Verifpal’s language, use a verifier that supports it. To compare results across tools, first check that their models, assumptions and queries mean the same thing.

Sources

Kobeissi, Nadim. 2026. From Toy to Instrument: Seven Years of Verifpal. Cryptology ePrint Archive, Paper 2026/1654.