Skip to content

[Bug]: Gateway labels denylist scan-clean as ALLOW_VERIFIED / "passed deterministic verification" — false verification claim in the decision vocabulary #43

Description

Summary

The governance gateway's decision vocabulary makes a false verification claim: when the code-engine's denylist scan finds nothing, the decision is status: "ALLOW_VERIFIED" with message "Python execution request passed deterministic verification." No deterministic verification occurred — a static token scan returned zero matches. This is the semantic half of #24 (which tracks the bypass vectors; executed evidence posted there); filing separately because relabeling and vector-closing are different fixes that must land together to mean anything.

Found in the 2026-08-23 adversarial audit of v0.2.1 @ 518192b.

Location

  • src/qwed_mcp/security/risk_gateway.py:142-149"status": "ALLOW_VERIFIED", "message": "Python execution request passed deterministic verification." on verify_code_safety(...)["verified"] == True, which means only "zero denylist issues found" (engines/code_engine.py:107-111)
  • src/qwed_mcp/security/risk_gateway.py:135-138 — even the refusal path uses the word: "Python execution was verified, but server policy keeps code execution disabled"

Evidence (CONFIRMED BY EXECUTION)

All ten bypass classes in the #24 comment (pathlib file read, io.open, builtins.eval, from os import remove, socket, urllib, ctypes, shutil, getattr chains) return ALLOW_VERIFIED. An end-to-end run executed an actual file read through the full pipeline. The label is not just cosmetic — any downstream consumer, auditor, or dashboard keying on ALLOW_VERIFIED / "verified" is being told a deterministic QWED verification occurred for code that merely avoided six denylist entries.

Why this matters beyond wording

QWED's ecosystem-wide contract distinguishes deterministic proof from heuristic signal (qwed-a2a's heuristic_pass status is the precedent; the a2a audit explicitly validated that honest labeling is what keeps heuristic results from being admitted as verified). This gateway inverts that: heuristic-clean → claimed-verified → admitted-executed. Same token ("VERIFIED"), two meanings across the ecosystem — the exact vocabulary fracture the Verification Context spec exists to prevent.

Remediation

  1. Rename the status honestly: SCAN_CLEAN or HEURISTIC_PASS — never "VERIFIED" for a denylist miss.
  2. Fix both messages ("passed deterministic verification", "was verified, but server policy...").
  3. Update the tool description to match the honest status.
  4. Result-poisoning note (same surface, fold in): executed code's stdout is returned verbatim into the LLM conversation as "Result:" text — content produced by executed (untrusted) code should be documented as untrusted, since it can carry instructions aimed at the hosting model.

Architecture change required: NO — strings and status constants.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions