feat(guard): active-content detector wired into the output gate (review MAJOR #1)
Close the EchoLeak wiring hole (CVE-2025-32711 class): markdown images/ links, reference definitions, autolinks, raw active HTML and data: URIs now surface as report-only findings (active:*, OWASP LLM05) in scan_output step 6, so screen_output and okf.import_bundle dispose of them instead of admitting them with findings=[]. - new active_content.py: canonical home of the shared pattern table + scan_active_content; neutralize refactored to import it (mutating API and behavior unchanged, all neutralize tests pass as-is) - images/links flagged only for absolute/protocol-relative URLs: relative in-bundle links are legitimate wiki/OKF mechanism (principle 5) - evidence carries defanged URLs only (hxxps://evil[.]example) - EchoLeak vectors planted in both showcases; detach proofs cover them - README export list + checklist step 6, CLAUDE.md context line updated Suite: 321 -> 341 passed. Core invariant intact (dependencies=[]).
This commit is contained in:
parent
31166d0af0
commit
4d53765c63
9 changed files with 454 additions and 101 deletions
|
|
@ -33,6 +33,11 @@ input-side scanners do not cover:
|
|||
report-only and never sanitized, so this is the persist-gate analogue of
|
||||
``sanitize``'s input-side stripping; disposition treats the labels as
|
||||
any-tier carriers. Unicode-tag / PUA stego is already surfaced by step 1.
|
||||
6. **Active content** (:func:`~llm_ingestion_guard.active_content.scan_active_content`,
|
||||
OWASP LLM05 — Improper Output Handling) — markdown images/links, reference
|
||||
definitions, autolinks, raw active HTML and ``data:`` URIs with an external
|
||||
target: the zero-click EchoLeak exfil class (CVE-2025-32711). Report-only;
|
||||
``neutralize`` remains the separate, opt-in defanger of the same constructs.
|
||||
|
||||
**Security property (this module specifically).** A finding's ``evidence`` never
|
||||
contains the secret value it matched — only a human description and the match
|
||||
|
|
@ -49,6 +54,7 @@ import re
|
|||
from dataclasses import dataclass, replace
|
||||
from typing import Optional, Union
|
||||
|
||||
from .active_content import scan_active_content
|
||||
from .entropy import scan_entropy
|
||||
from .lexicon import MAX_SCAN_CHARS, scan_lexicon
|
||||
from .report import Finding, Report, Severity, Source
|
||||
|
|
@ -302,4 +308,9 @@ def scan_output(
|
|||
# unicode-tag case is already covered by the lexicon scan in step 1.
|
||||
report.extend(_scan_invisible_carriers(scan_text, source).findings)
|
||||
|
||||
# 6. Active-content constructs with an external target (the EchoLeak class,
|
||||
# OWASP LLM05) — reported here so disposition sees them; defanging stays
|
||||
# neutralize's separate, opt-in job.
|
||||
report.extend(scan_active_content(scan_text, source).findings)
|
||||
|
||||
return report
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue