AI agents are the new plague ships.

In 1423 Venice stopped letting ships sail straight into the city. Their cargo waited on an island, the lazaretto, until inspectors cleared it. Contaminated goods were burned. Clean goods came ashore.

Lazaret does the same for your API. Every write waits in a ledger at the edge, an independent Claude reviewer inspects it, and only what passes reaches your database. The reviewer can only judge; it has no way to act.

Fire an attack at a real helpdesk

Tidewater Support is a small helpdesk with its own AI support agent, running behind a real Lazaret deployment. Send it something below and follow the write through the ledger: held, sealed into a batch, reviewed, then committed or dropped.

Connecting to the ledger…

Attack console

Each button sends a case from the evaluation corpus as a signed-in Tidewater customer. Sending needs a quick bot check, because every write is reviewed by a paid model.

    Responses from the gateway appear here.

    The ledger

        No writes yet this hour. Send one from the console, or open Tidewater and write a ticket yourself.

        Decided at the edge

        Logins, API keys and credits can't wait for a batch, so a fast model reviews them inline, under a 3 second deadline. Blocked routes never reach a model at all.

          Waiting for a human

          Writes the reviewer wouldn't clear, or declined to judge, are held here. An operator releases or drops each one, and that decision becomes a training label for the Memory.

            How a write gets through

            Five stages between a client and your database. Select one to see what it does.

            The gateway normalises the path, matches a route, and scores the request: attack signatures, mass-assignment fields, per-session and per-route behaviour (bursts, failed logins), and rules the Memory has learned. Reads pass through. Blocked routes stop here. The score travels with the write as evidence.

            Read the code

            Five rules it is built on

            The harness owns the loop

            The Ledger runs the state machine. The reviewer is called by it, sandboxed, and can only return a verdict.

            Watch a batch step through its states in the ledger above. The reviewer never starts or ends anything.

            The brain is separate from the hands

            The reviewer judges and a separate committer acts. A prompt-injected reviewer has nothing to act with.

            All 8 prompt injections aimed at the reviewer were stopped in the last live eval.

            The log is the source of truth

            State is rebuilt by replaying the event log, so an eviction or crash loses nothing that was acknowledged.

            The ledger view is itself a replay: reload this page and it rebuilds from the same event log.

            Retry instead of restarting

            Review resumes from checkpoints, and commits carry an idempotency key, so a retry never commits twice.

            A failed review attempt shows as Retrying on its batch, and resumes from the last finished step.

            Learn from the logs

            Patterns the reviewer confirms become deterministic gate rules, so the system gets cheaper and faster over time.

            The Memory section below shows the rules learned so far and what they caught.

            Measured against real attacks

            120 labelled requests, 63 attacks and 57 honest ones, sent through the real gateway, Ledger and reviewer with live Claude models. Run of 29 October 2026, from evals/results/live-latest.json.

            Attacks stopped
            63/63 recall 100%
            Honest writes stopped
            0/57 false positive rate 0%
            Stopped by the gate alone
            5/63 with no model call and 0 false positives
            Cost
            $0.23 per run, $2.12 per 1,000 reviewed writes

            Where the 63 stopped writes were caught

            63 attacks and 0 honest writes, by the stage that stopped them. Most never needed the stronger model.

            StageWrites stopped
            Gate, before any model call5
            Inline review10
            Inline review unavailable (failed closed)0
            Batch review45
            Escalation to the stronger model0
            Taint3
            Its first write was stopped at the gate0

            Attacks stopped, by kind

            KindStopped
            Prompt injection aimed at the support agent10 of 10
            Stored XSS8 of 8
            Prompt injection aimed at the reviewer8 of 8
            SQL injection8 of 8
            Refund fraud7 of 7
            Mass assignment5 of 5
            Credential stuffing and spraying4 of 4
            Taint (follow-ups to an attack)3 of 3
            Privilege escalation3 of 3
            Spam2 of 2
            Path traversal1 of 1
            Template injection1 of 1
            Server-side request forgery1 of 1
            NoSQL injection1 of 1
            Command injection1 of 1

            Inline review is fast, not instant

            Logins, keys and credits wait on a fast model before they reach Tidewater. Its first token alone takes about 0.8 s, so no inline verdict can be quicker than that. A call past the 3.0 s deadline fails closed; in this run that happened 0 times.

            Batch review isn't on anyone's critical path: a batch of writes took 4.2 s at the median and 7.2 s at p95, after the 30 second cycle.

            How often the model declined to judge

            A model can decline a request it reads as cyber-offensive. Lazaret never lets anything else decide in its place: a declined write is held for a human, never allowed.

            ReviewerCallsDeclinedWhy
            Batch (Sonnet 5.5)200 (0%)none
            Escalation (Opus 5.5)40 (0%)none
            Inline (Haiku 5.5)820 (0%)none

            It learns from what it catches

            Every verdict is archived. After a batch with drops, a model proposes a deterministic rule. The rule is tested against past traffic, watched on live traffic, and only then allowed to flag or block at the gate, where it costs nothing and takes microseconds. Where a rule and the reviewer disagree, a person decides.

            Under a sustained attack, the gate takes over

            6 windows of about 50 writes, 30% of them attack variants. 3 learned rules were promoted to block. Model calls per 1,000 writes went from 327 to 283, and the gate made 33% of the stops in the last window, up from 0%. Cost per 1,000 writes did not fall: $2.32 in the first window, $2.48 in the last, because honest writes still all need a model and they are most of the traffic. The learned rules did not stop any attack family held out of training: each rule fits the payloads it was learned from.

            Model calls per 1,000 writesLower is cheaper and faster: a write the gate decides never waits on a model.
            Share of stops made by the gateHigher means more attacks were stopped by a learned rule, before any model.
            Unseen attack families stopped at the gateFresh variants of attacks the Memory never trained on. Higher means it learned the kind of attack, not just the payload.
            Show the numbers, window by window
            WindowWritesAttacks stoppedHonest writes stoppedModel calls per 1,000Cost per 1,000Stops at the gateUnseen families at the gateRule changes
            15215 of 150 of 35327$2.320 of 150%1 to shadow
            25215 of 150 of 35423$2.800 of 150%2 to shadow
            35115 of 151 of 35333$2.560 of 160%2 to flag, 2 to shadow
            45315 of 150 of 35358$2.570 of 150%2 to block, 2 to flag, 1 to shadow, 1 rejected
            55015 of 151 of 35320$2.661 of 160%1 to block, 1 to flag, 4 to shadow, 1 rejected
            65315 of 150 of 35283$2.485 of 150%1 to flag, 3 to shadow
            • The human queue and disputed writes were worked by a simulated operator, labelling from the eval corpus 1 window later. A real deployment gets those labels only from a person.
            • The traffic is generated: each corpus attack is re-sent as encoded, re-cased, split and moved variants (no model writes them), mixed with benign variants. It is not captured production traffic.
            • 16 attack families were held out of training entirely; the third chart measures only them, with the gate alone.

            Live campaign run of 29 October 2026: Claude reviewing, Claude proposing the rules, $0.80 in all (evals/results/campaign-latest.json).

            Rules the demo has learned

            Loading the live Memory…

              Put it in front of your own API

              Lazaret is a TypeScript library for Cloudflare Workers. The deployment that protects Tidewater is one config file: which routes are held, which are reviewed inline, which never reach origin, and what each write touches.

              export const config = defineLazaret({
                origin: "https://api.example.com",
                routes: [
                  { match: "POST /api/login", policy: "INLINE_REVIEW" },
                  { match: "POST /api/tickets", policy: "ESCROW",
                    resources: ["ticket:{receipt}"] },
                  { match: "* /admin/*", policy: "BLOCK" },
                  { match: "GET /*", policy: "PASS" },
                ],
                review: { dailyBudgetUsd: 10 },
              });