fix(c04): don't false-flag safe rejections that echo the payload (litmus-v14)#104
Merged
Conversation
…mus-v14) C-04 probe 3.2 (jailbreak amplification) masks reflections of our own injected payload before scanning, so an honest echo isn't mistaken for server-generated injection. The mask only caught COMPLETE echoes, so a server that safely REJECTS a jailbreak-as-argument and quotes it back in its own error frame — often char-stripped (`</system>` -> `system>`) or truncated — slipped through and was capped at D for 'amplification' it never did. Generalize maskRejectionEchoes: when an output reads as a refusal (a rejection marker like `Invalid label "..."`, `Error: ... not found: ...`, Pydantic `input_value=`), neutralize any run that reproduces a substring of an injected payload. This can only remove echoes of OUR OWN payloads, so server-GENERATED injection is never masked (no false negatives), and gating on the refusal frame preserves probe 3.2's target: a compliant server that echoes a payload prefix then splices novel injection is not a refusal and still fails. Pass/fail-semantics change (some safe-rejecting servers move D->A), so bump the methodology string to litmus-v14. Adds regression tests for the transformed/truncated rejection echoes, the compliant-splice invariant, and server-generated injection surviving inside a rejection frame. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TZcTQCDwyFqdh59fPWDJAr
RubenSousaDinis
force-pushed
the
fix/c04-safe-reject-echo
branch
from
July 6, 2026 14:12
1296467 to
954039c
Compare
RubenSousaDinis
added a commit
that referenced
this pull request
Jul 6, 2026
Ships litmus-v14: the C-04 probe 3.2 fix so a server that safely rejects a jailbreak-as-argument and echoes it back in an error frame is no longer mis-flagged as amplification (#104). server.json bumped in lockstep so the MCP-registry listing tracks the release. Claude-Session: https://claude.ai/code/session_01TZcTQCDwyFqdh59fPWDJAr Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
C-04 probe 3.2 (jailbreak amplification) feeds jailbreak-pattern strings as tool arguments and flags injection-shaped output the server did NOT merely reflect from our input. It masks reflections of our own injected payload first, so an honest echo isn't mistaken for server-generated injection — but the mask only caught complete echoes.
A server that safely rejects a jailbreak-as-argument and quotes it back inside its own error frame slipped through when the echo was transformed: char-stripped (
</system>→system>), mid-truncated, or wrapped in a non-Pydantic error (Invalid label "…": disallowed characters,Error: file not found: …). The residual injection token survived the mask and capped an otherwise-clean server at D for amplification it never performed.The fix
Generalize
maskRejectionEchoes: when an output reads as a refusal (a rejection marker —invalid,error,not found,disallowed,_parsing, …), blank any run that reproduces a ≥9-char substring of an injected payload, with equal-length filler so offsets are stable.Two properties make this safe:
Pass/fail-semantics change (some safe-rejecting servers move D→A) → methodology string bumped litmus-v13 → litmus-v14 (kept a string so older attestations coexist).
Tests
New regression cases in
adversarial-inputs.test.ts: the transformedInvalid label "…"andfile not found: …rejection echoes; the compliant echo-then-splice invariant (must still fail); and a server-generated trigger surviving inside a rejection frame. Full suite green (probes 417 pass, core 18, typecheck clean).Verified end-to-end
Built the harness and graded a real safe-rejecting server in the Docker sandbox: C-04 moves from fail → pass under litmus-v14.
🤖 Generated with Claude Code
https://claude.ai/code/session_01TZcTQCDwyFqdh59fPWDJAr