Skip to content

Releases: nkratk/llm-trust-guard-python

v0.21.6

Choose a tag to compare

@nkratk nkratk released this 24 Jul 02:54

Adversarial Benchmark Results — v0.21.6

False-positive/false-negative fix, no new adversarial-corpus run. This release fixes OutputFilter's ip_address PII pattern false-positiving on version strings (issue #10, parity gap) and ExternalDataGuard's role_override false-positive on ordinary business language (issue #7 sub-bug, parity gap) — no other guard's detection logic changed. Recall against the 1,182-group corpus is unchanged; see RESULTS-v0.21.5.md for those numbers, which remain the current basis for detection-rate claims.

Run date: 2026-07-23
Pytest: 1001 tests, all pass (up from 998 in v0.21.5)


Changes in v0.21.6

Full detail in CHANGELOG.md [0.21.6]. Summary — mirrors npm v4.32.7 exactly:

  • OutputFilter's ip_address false positive on version strings (#10), fixed properly across two independent-review rounds:
    • Base fix: octet-bounding (0-255) plus a post-match context check (_is_version_context) suppressing the match when a version-indicating keyword qualifies the number within the same clause — implemented as code rather than an embedded regex lookbehind, since Python's re module only supports fixed-width lookbehind.
    • Round 1 review caught two regressions: a context window with no clause-boundary awareness (a real IP silently left unmasked when an unrelated keyword sat nearby), and an obfuscation-scan-variant bypass (the reversed-text variant scrambles the keyword while preserving the IP shape) — my own first fix attempt for the latter reproduced the identical bug via a different path before being corrected.
    • Round 2 review (a second, deliberate re-probe of the already-twice-fixed logic before merge) caught two more regressions, and found a code comment's claim of "parity with npm" was itself factually wrong when checked against npm's actual source: the clause-break denylist (:;.,) still missed every other punctuation mark and digit/newline gaps, and "skip for every scan variant" was scoped too broadly, itself disabling real-IP detection in base64/hex-obfuscated output.
    • Final design: an allowlist (letters + horizontal whitespace only) for the clause gap, matching npm's actual lookbehind exactly, and a narrowly-scoped skip for only the specific reversed scan variant. Verified exhaustively: every ASCII punctuation character correctly preserves detection; every non-reversal obfuscation variant (base64, hex) still catches a real IP.
  • ExternalDataGuard's role_override false positive on ordinary business language, ported from npm (this repo had never received the fix — a real, unattempted parity gap). A pre-existing, intentional gap in this same pattern ("act as a system administrator" isn't caught — the same tradeoff npm already shipped) is now documented with an explicit test, parity with an equivalent npm test.
  • Issue #7's fetch_url/markdown_image_exfil sub-bugs and #5 (npm-tracked, no Python-specific issues filed) were investigated with genuinely different angles, not changed — all three independently reconfirmed the original 2026-07-16 conclusion that any pattern-based carve-out here either reopens a real bypass or is trivially gameable.

Note on review process

This release went through two full rounds of independent adversarial review, both of which found real, previously-unnoticed regressions in the immediately-preceding fix — including one case where a code comment's explicit claim of matching the npm sibling's design was checked against npm's actual source and found to be wrong. Documenting this explicitly: a security-relevant regex/logic fix that looks complete after one round of scrutiny has, more than once now, still had real gaps a second round found. The final design in this release (allowlist over denylist, narrowly-scoped exclusions verified exhaustively rather than against a handful of examples, verified npm parity claims against npm's actual code rather than trusting a comment) is intended to close the class of bug, not just the specific reproductions found so far.

v0.21.5

Choose a tag to compare

@nkratk nkratk released this 23 Jul 02:33

Adversarial Benchmark Results — v0.21.5

Safety-net + review-driven fix release. No new adversarial-corpus run — this release adds permanent, automated regression tests (ReDoS-safety, config-consistency) and fixes real bugs those tests (and two rounds of independent adversarial review) found, but does not change any guard's steady-state detection logic relative to v0.21.4's measured corpus results, with one exception noted below. Recall against the 1,182-group corpus is unchanged; see RESULTS-v0.21.4.md for those numbers, which remain the current basis for detection-rate claims.

Run date: 2026-07-23
Pytest: 988 tests, all pass (up from 982 in v0.21.4 — new tests/test_redos_safety.py (2 tests), tests/test_heuristic_analyzer.py (4 tests), plus 2 new cases each in tests/test_decode_variants.py and tests/test_encoding_detector.py)
G5 recall ratchet (recall-baseline.json): unchanged, passed.


Changes in v0.21.5

Full detail in CHANGELOG.md [0.21.5]. Summary:

  • Permanent ReDoS-safety regression test (tests/test_redos_safety.py): extracts regex patterns via re.<func>(...) calls and pattern= keyword-argument dataclass fields, and stress-tests each with a scaling-ratio check. Found and fixed three real catastrophic-backtracking regexes: heuristic_analyzer.py's _QA_PATTERN, encoding_detector.py's template_injection (neither had ever shipped in a released version — found and fixed within the same unreleased branch), and output_filter.py's email PII pattern — this one was live in v0.21.4 and every prior release. It's a parity gap: the exact same bug shape was already found and fixed in ExternalDataGuard and in the npm sibling's output-filter.ts, but this file's own copy never got the parity fix, and was entirely invisible to the ReDoS-safety test until its extractor was broadened (per independent review) to cover dataclass-field patterns, not just re.compile() call arguments.
  • Content-length consistency regression test (tests/test_decode_variants.py).
  • .githooks/pre-push now fetches origin's tags before running scripts/verify.sh.
  • Review-driven fix: the first fix for _QA_PATTERN (bounding its unbounded gap to 1000 chars) closed the ReDoS but silently created a many-shot-jailbreak detection bypass — any turn whose Q→A gap exceeds 1000 chars stopped being counted. Independent adversarial review of the npm sibling's identical fix caught this and confirmed it here too (verified 5/5 → 0/5 on a long-turn payload). Replaced with a linear marker-position scan (_count_qa_pairs) with no length cap at all — detection fully restored, still ReDoS-safe. Net effect on the many-shot heuristic: neutral relative to v0.21.4 (this bug was found and fixed within the same unreleased branch, never shipped in a tagged release).
  • Review-driven fix: a portability bug in the ReDoS test itself (signal.alarm called unconditionally on a code path that should have degraded gracefully without SIGALRM) — test-infrastructure only, no production code affected.

Security-relevant note on the output_filter.py email fix

Unlike the other fixes in this release, the output_filter.py email-pattern fix changes behavior that was live in v0.21.4 and prior releases: an attacker-reachable input (any text passed through OutputFilter with PII detection enabled and containing a long run of .-adjacent characters near an @) could trigger multi-second-plus backtracking, a real, if narrow, denial-of-service surface on LLM output filtering. The fix bounds the pattern's quantifiers ({1,64}@(?:...){1,8}[A-Za-z]{2,24}, identical to the already-fixed ExternalDataGuard/npm versions) with no change to which strings are detected as emails on realistic input (verified against the existing test_should_detect_email_addresses test and several representative email formats).

v0.21.4

Choose a tag to compare

@nkratk nkratk released this 23 Jul 00:13

Regression fix + coverage-gap fix + security hardening. Companion release to npm v4.32.5. Parity fixes for issues #7 (closed), #9 (closed), #10/#11 (left open, partial — documented residual gap), plus 25 ReDoS fixes and one Python-specific bug (a decode step silently dropping a variant on invalid UTF-8) found during independent review.

Adversarial Benchmark Results — v0.21.4

Run date: 2026-07-22
Companion release to npm v4.32.5 — same methodology, independently re-verified against this repo's own guards rather than assumed identical to npm (see notes below on where the two diverge).
Suite: 979 tests, all pass (up from 964 in v0.21.3 — new tests/test_decode_variants.py, 15 tests)


Changes in v0.21.4

Full detail in CHANGELOG.md 0.21.4. Summary:

  • InputSanitizer's dan_jailbreak pattern fixed (#7, closed).
  • New shared src/llm_trust_guard/decode_variants.py: InputSanitizer, ExternalDataGuard, MultiModalGuard now re-scan de-obfuscated content variants before deciding allow/block.
  • ExternalDataGuard (#9, closed): 33/34 previously-undetected threats now caught.
  • MultiModalGuard (#10, left open — partial): 20/30 now caught via decode; 10 remain a genuine signature gap.
  • InputSanitizer (#11, left open — partial): parity with npm's decode-gap subset.
  • 25 ReDoS fixes across 8 guard files, found via the same empirical stress-test sweep as npm, run independently against this repo's own patterns (814 patterns, 28 adversarial seeds) — 19 direct timeouts + 6 slow patterns found and fixed, not assumed identical to npm's findings.
  • One Python-specific bug, not present in the npm original: decode_variants.py used errors="strict" on hex/base64 decode, silently dropping a variant on any single non-UTF-8 byte (npm's Buffer.toString('utf-8') never throws). Fixed by switching to errors="replace" — found by independent adversarial review of the port, not by mechanically copying npm's implementation.
  • A final pre-merge review round caught the same maxContentLength/decode-cap bypass npm had (the input cap sat below ExternalDataGuard's own 50,000-char default). Raised to 65,000 here — deliberately lower than npm's 100,000, since InputSanitizer's 170+ patterns cost ~770ms worst-case at npm's value on CPython's slower regex engine vs. npm's ~30ms; 65,000 keeps worst-case latency ~300ms while still closing the same bypass.

Pipeline re-verified against the actual threat corpus after these fixes: of the 133 Python threat groups that showed zero detection before this release, 70 now detect (43 fully, 27 partially) — consistent with npm's 70/137.

Process note: this release's port went through independent adversarial review of the Python-specific implementation, not just parity-checking against npm — this is what caught the errors="strict" bug above, which has no npm equivalent (JS's Buffer.toString semantics differ from Python's str.decode). A second, final holistic review after CI went green caught the maxContentLength/decode-cap bypass before merge, same as npm.


WildChat FPR gate

No local WildChat fixture / FPR gate exists in this repo (npm-only infrastructure) — not applicable here, same as prior releases.


Full guard recall summary

Inherited from RESULTS-v0.21.3.md for the general 1,182-group corpus — this release's testing focus was the 133 specifically-bisected previously-failing threat groups (documented above), not a full corpus re-run. See specs/001-guard-adversarial-hardening/tasks.md for the full bisection methodology.

v0.21.3

Choose a tag to compare

@nkratk nkratk released this 19 Jul 21:04

Fixes issue #4: CodeExecutionGuard's AST gadget-chain proximity detector false-positived on a single standalone dunder attribute access. Companion release to npm v4.32.4. See CHANGELOG.md and tests/adversarial/RESULTS-v0.21.3.md for full detail. Closes #4.

v0.21.2

Choose a tag to compare

@nkratk nkratk released this 16 Jul 02:08

0.21.2 (2026-07-15)

Fixed

  • rag_guard.py: decode URL-encoded document content — including double-encoding, up to 3 levels — and re-scan each decoded variant before running injection-detection patterns, mirroring the npm v4.32.3 fix. Previously a URL-encoded payload bypassed detection entirely. (#1, companion to nkratk/llm-trust-guard#1)
  • agent_skill_guard.py: loosened the "fake-compliance data exfiltration" and "response appending directive" SCH patterns — they previously required a specific word order/literal word and missed reordered or reworded variants ("X mandates: route ...", "include in all outputs: ..."). The broadened "fake-compliance" pattern also now requires an explicit "all responses/data/output(s)" object AND an actual destination (to/at <address>) after the action verb — two earlier drafts were progressively found, in review, to false-positive on benign compliance/audit prose (first on qualifier+verb alone, then on verb+destination with no bulk object). Both caught before merge. Same regex source and fix as npm v4.32.3. (#2, companion to nkratk/llm-trust-guard#2)

Note: code_execution_guard.py was not changed in this release. Its native AST-based _ast_escape_findings() correctly blocks real Python object-introspection gadget chains (__subclasses__, __globals__, __mro__, etc.) and served as the reference for fixing the npm port's true-negative gap (npm #3). However, it has its own, separate over-blocking bug — a single standalone dunder attribute access (e.g. bare cls.__subclasses__()) is flagged as if it were a chain, with no proximity/co-occurrence check at all. Filed as #4; not fixed in this release.

v0.21.1 — README: new threat classes in feature list

Choose a tag to compare

@nkratk nkratk released this 09 Jul 02:04

Docs-only patch. No guard code changes.

Added to "What it catches well" section:

  • Semantic Compliance Hijacking (SCH) — AgentSkillGuard
  • Plant-Persist-Trigger (PPT) — MemoryGuard
  • LLM-to-LLM string-payload injection — AgentCommunicationGuard
  • Markdown image alt / HTML event injection — RAGGuard

v0.21.0 — 2026 literature gap-fill: SCH, PPT, string-payload, HTML/image patterns (mirror of TS v4.32.0)

Choose a tag to compare

@nkratk nkratk released this 07 Jul 17:42

What's new

Python mirror of npm v4.32.0. Pattern-only release adding 2026 threat-research coverage to 4 guards. No API changes. Zero new dependencies.

agent_skill_guard.py — 4 Semantic Compliance Hijacking (SCH) patterns

agent_communication_guard.py — 7 string-payload patterns + isinstance branch in _validate_payload()

memory_guard.py — 4 Plant-Persist-Trigger patterns

rag_guard.py — markdown_img_alt_injection + html_event_injection

Metrics

  • Adversarial recall: 82.1% (1,182 groups / 5,883 payloads — from npm corpus)
  • WildChat FPR gate: 494 / 10,000 = 4.94% (unchanged)
  • Suite: 949 / 949 pass
  • Parity vectors: 46 (Python-handled guards)

Full results: RESULTS-v0.21.0.md

npm counterpart: llm-trust-guard v4.32.0

v0.20.0

Choose a tag to compare

@nkratk nkratk released this 04 Jul 21:15

Python parity for v4.31.0: MultiModalGuard FPR fix, ConversationGuard 9 new patterns, InputSanitizer preprocessing, full parity gate (32 vectors, 12 guards). 935 tests pass.

v0.19.0 — MemoryGuard, OutputFilter, ToolResultGuard: obfuscation preprocessing (mirror of TS v4.30.0)

Choose a tag to compare

@nkratk nkratk released this 04 Jul 19:35

Mirror of llm-trust-guard v4.30.0.

Changes

MemoryGuard (11% → 96.06% recall): 14 new MEMORY_INJECTION_PATTERNS + _preprocess_content() pipeline wired into check_write().

OutputFilter (30% → 58.64% recall): judge_stealth_marker + echogram_marker secret patterns; _build_scan_variants() applied to PII and secret scans.

ToolResultGuard (6% → 63.64% recall): embedded_tool_call extended to <invoke name=/<function_call; _build_scan_variants() in scan_for_injection() and _detect_state_change_claims().

Test suite

903 pytest tests pass. All verification gates green (G1–G11). Patch coverage 86%.

v0.18.0 — MCPSecurityGuard: obfuscation preprocessing + 20 new patterns (mirror of TS v4.29.0)

Choose a tag to compare

@nkratk nkratk released this 03 Jul 22:28

What's new

MCPSecurityGuard — mirror of TS v4.29.0

_preprocess_content(): ZWSP strip, URL/hex/base64 decode, reverse, Cyrillic homoglyph normalisation.

New patterns: sd_retry_forever, embedded_abs_path, cursor_mcp_inject, dangerous_scheme, mcp_endpoint_override; extended git_injection, env_injection; 8 new _LINE_JUMPING_PATTERNS (authority_directive, exfil_routing, schema_mutation_str, mcp_tool_shadow, mcp_impersonation, rug_pull_descriptor, html_comment_injection, homoglyph_cyrillic).

Corpus result: 84/440 (19.09%) → 430/440 (97.73%). 55 fully-blind threat groups → 0.

885 tests pass. All verify gates green.

Install

pip install llm-trust-guard==0.18.0