Trail of Bits fixes mermaid-to-proverif, which read ProVerif's results backwards

2 hours ago

Trail of Bits fixed mermaid-to-proverif, the trailmark skill that turns a Mermaid sequence diagram of a cryptographic protocol into a ProVerif model. It read ProVerif's reachability results backwards, and its forward-secrecy test leaked the long-term keys too early. Both are fixed in trailmark 0.12.1. https://github.com/trailofbits/skills/pull/367 https://github.com/trailofbits/skills

Ask

Ask about this presentation

Answers are generated from this presentation.

Chapters

  1. 0:00Trail of Bits fixes mermaid-to-proverif, which read ProVerif's results backwards
  2. 0:26ProVerif prints is false when the event can happen
  3. 0:46Every other query rests on the reachability check
  4. 1:09The forward-secrecy test now leaks the keys after the sessions
  5. 1:28The skill's own example has a replay finding
  6. 1:50What changed in the trailmark plugin, and what stayed the same
Show transcript

Trail of Bits fixes mermaid-to-proverif, which read ProVerif's results backwards

github.com/trailofbits/skillstrailmark plugin
is false · model broken
event reachable · model fine
trailofbits/skills PR #367 · merged Oct 14, 2026

Trail of Bits has fixed mermaid-to-proverif, the skill that turns a Mermaid sequence diagram of a cryptographic protocol into a ProVerif model. It read the ProVerif reachability check backwards. So a correct model looked broken, and a broken model looked fine. If you have formally verified a protocol with this skill, those verdicts are worth a second look.

ProVerif prints is false when the event can happen

mermaid-to-proverif · reachabilityProVerif 2.05

ProVerif prints "is false" when the event can happen

query event(endR(pk_i, pk_r, k)).
RESULT not event(endR(...)) is false.
is falseevent fires: the expected result
is trueevent never fires: the model is stuck
PR #367 · mermaid-to-proverif/SKILL.md, step 5

ProVerif checks whether an event can happen by trying to prove it never does. So when the event is reachable, it prints "not event, is false." The skill told the model that false meant a structural bug. Now false is the good case, and true means the event never fires.

Every other query rests on the reachability check

mermaid-to-proverif · reachability5 places corrected

Every secrecy and authentication result rests on the reachability check

reachability passed
model never ran its last step
PR #367 · SKILL.md · references/proverif-syntax.md · references/security-properties.md

That check is the skill's first query. If the protocol's last step can't be reached, every secrecy and authentication result after it is meaningless. With the reading flipped, a stuck model passed that check. The skill, both of its reference files and its example all carried the backwards reading, five places in total.

The forward-secrecy test now leaks the keys after the sessions

mermaid-to-proverif · forward secrecyProVerif 2.05

The forward-secrecy test now leaks the long-term keys after the sessions

before: keys leaked at the start
new sk_I: skey; out(c, pk(sk_I)); out(c, sk_I);
secrecy: is false for any authenticated protocol
after: keys leaked in phase 1
(phase 1; out(c, sk_I); out(c, sk_R))
example's secrecy queries: is true
PR #367 · references/security-properties.md, Forward Secrecy

The forward secrecy pattern had a second problem. It handed both long-term keys to the attacker at the very start, so the attacker could impersonate either side, and secrecy failed for every authenticated protocol. Now the keys leak after the sessions finish, and on the example both secrecy queries hold.

The skill's own example has a replay finding

mermaid-to-proverif · simple-handshake exampleProVerif 2.05

The skill's own handshake example lets a replayed first message start another session

RESULT inj-event(endR(...)) ==> inj-event(beginI(...)) is false.
weak, non-injective authentication: holds
PR #367 · examples/simple-handshake/sample-output.pv, query Q3

The example the skill teaches from had a finding of its own. Its handshake has no challenge from the responder, so replaying the first message completes another responder session, and the replay check fails. The weaker authentication property holds. The example now reports that replay as a real finding.

What changed in the trailmark plugin, and what stayed the same

github.com/trailofbits/skillstrailmark plugin

The guidance changed, and the generated models did not

Same model logic, skill name and workflow. A new test checks the wording against ProVerif's output, and runs ProVerif itself only where it is installed.

github.com/trailofbits/skills/pull/367
PR #367 · tests/test_guidance.py

The models the skill writes are unchanged. What changed is how it reads ProVerif's answers, and how it tests forward secrecy. A new test keeps that guidance matched to ProVerif's output, and only runs ProVerif itself where it is installed. The update ships in the trailmark plugin, which loads in Claude Code and in Codex.