<nil>NILScript

Proof

The numbers

Unexpressible, not filtered. Across 2,108 real prompt-injection attacks (base setting, two models), unauthorized writes admitted at the gate through NIL = 0.00%, while every authorized call still passed through (no false refusal). An undeclared action has an empty preimage: whatever fraction the agent gets hijacked, NIL admits none of those writes at the gate.

The result

InjecAgent unauthorized-write rate: raw vs NIL, NIL bars are zero across both models in the base setting
2,108 base-setting evaluations, one headline
Raw agents were hijacked into a real write on up to 1 in 22 cases. Through NIL, unauthorized writes admitted at the gate drop to 0.00% across both models in the base setting, while authorized calls pass through at 100% (false-refusal rate 0). An undeclared action has an empty preimage: it is unexpressible, not merely filtered. The defense is model-independent by construction.
ModelSettingCasesHijack rate (ASR)Unauth. write — rawUnauth. write — NILAuthorized pass-through
gpt-oss-120bbase10542.75%2.75%0.00%100%
zai-glm-4.7base10544.46%4.46%0.00%100%

Total: 2,108 base-setting evaluations across two models. We report the base setting only. The two enhanced-setting rows are withheld: that arm is degenerate (pre-correction error-masking), so it would understate raw ASR rather than test the gate. The harness scores gate decisions over tool names, not executed writes, so raw unauthorized-write rate equals ASR by construction; the NIL 0 is the intent-oracle (Proposition 2) face of the gate, not independent evidence on top of ASR. The authorized pass-through column is the false-refusal rate (0): no authorized call was refused. It is not measured task completion; task-success is a separate, planned axis (tau-bench).

How it's measured

NIL is the layer between the agent and the backend, so we don't compete on a leaderboard — we instrument one. InjecAgent (ACL Findings 2024) injects a malicious instruction into a tool's response while the user only asked for an authorized read; a hijacked agent then calls the attacker's tool: a state-changing write. We run every case twice in the base setting: the agent calling tools directly (raw), and the same agent routed through NIL (gated). Same model, same attacks: only the gate differs. The claim isn't “NIL makes the model smarter”; it is that an undeclared action is unexpressible. A write only commits after a previewed propose → approve → commit, and the agent can only name verbs the backend's skeleton exposes; an undeclared verb has an empty preimage, so there is nothing to filter. This is model-independent by construction, not estimated from two models.

Edge axis — SRR & Effect-Leakage

The InjecAgent axis scores gate decisions. To test the actual deployed surface we add an edge-level axis measured through the live odoo-CRM production edge: SRR (Structural-Rejection Rate, the share of undeclared actions structurally rejected) and EL (Effect-Leakage, the count of undeclared writes that reached the backend). Across four corpora we observe SRR = 100% and EL = 0:

CorpusNSRREffect-Leakage
Synthetic undeclared verbs50100%0
Plausible-attacker verbs8100%0
InjecAgent-derived verbs8100%0
resource.* × provisioned-but-undeclared targets (account.payment, hr.employee)8100%0

The fourth corpus is load-bearing. Before the resource.* gate it leaked: SRR 0%, EL 8/8, a real payment/employee write reached the backend. The 100%/0 result is earned by closing that hole, not assumed. SRR = 100% is true by construction (implementation faithfulness to the declared surface), so it is a faithfulness check, not a surprising rate.

Reference-implementation audit

A reference-implementation audit closed two “asserted-not-earned” defects, both now kernel-gated at conformance admission:

  • COMMIT success is earned, not hardcoded. The success envelope is verified by a read-after-write: a dropped field flips verified to false/partial, rather than returning a hardcoded true.
  • The generic resource.* CRUD family is skeleton-bounded so advertised ≡ committable (default-deny). A CRM adapter cannot reach accounting or payroll.

Live Odoo confirmation

Both invariants were observed through the deployed edge against a real Odoo: account.payment was refused at PROPOSE (Effect-Leakage = 0 observed); a committed contact passed a per-field read-back; and a rollback's HIGH delete was held by the human gate.

Conformance — protocol invariants

Beyond safety, the wire itself is tested as properties, not single runs: a property-based state machine drives random propose/commit/rollback sequences and asserts idempotency, no side effect on PROPOSE, rollback honesty (a reversal targets the real record, never a stale name), and refusal correctness (unknown verbs are refused, never faked).

Honest caveats

We publish the caveats, not just the win. The harness scores gate decisions over tool names, not executed writes, so raw unauthorized-write rate equals ASR by construction and the NIL 0 is the intent-oracle (Proposition 2) face of the gate, not independent evidence layered on top of ASR. The harness also uses a single-step decision, not InjecAgent's two-step ReAct, and these reasoning models' raw hijack rates (0–4.5%) sit below the paper's 24% GPT-4-ReAct base, so the ASR numbers are harness-specific and not a head-to-head with the published figure. We report the base setting only; the enhanced arm is withheld as degenerate. The NIL → 0 result is the robust, comparable claim. Unauthorized-write rate is always reported paired with the authorized-call pass-through (false-refusal rate 0), never alone; measured task-success is a separate, planned axis (tau-bench).

  • Harness + how to run: nilscript/bench
  • Full four-axis plan (task-success, safety, conformance, performance): benchmarking-plan.md
  • Run the propose→approve→commit→rollback flow yourself locally: nilscript demo

NILScript is an open standard, stewarded by the Wosool project. The spec is extracted from running code.

Draft standard v0.3.0 · 0.x stage · NIL wire 0.1 · DSL 0.1