exfil-scan
CLI that scans LLM outputs for data exfiltration signals — hidden text, encoded data, suspicious URLs, metadata leaks
exfil-scan
Scans LLM outputs and AI-generated content for signs of data exfiltration.
Why
The EchoLeak vulnerability (CVE-2025-32711, CVSS 9.3) showed that zero-click prompt injection in Microsoft 365 Copilot could exfiltrate data via hidden text in documents. As LLMs handle increasingly sensitive information, the outputs themselves become a new attack vector — attackers can embed stolen data in seemingly innocent responses using hidden characters, encoded blocks, or suspicious URLs.
Traditional security tools don’t monitor what AI systems output. exfil-scan fills that gap — it’s a “virus scanner” for LLM responses.
What It Detects
Six categories of exfiltration signals, each independently configurable:
- Hidden Text (HIGH) — Zero-width characters (U+200B, U+200C, U+200D, U+FEFF, etc.) and consecutive invisible sequences used to encode data invisibly — the same technique used in EchoLeak.
- Encoded Data (HIGH) — Base64 blocks, hex strings, octal escape sequences, and unicode escape sequences embedded in responses that may contain exfiltrated data.
- Data-in-URL (MEDIUM) — URLs with suspiciously long query parameters, base64/hex in query strings, or URL-encoded data payloads indicating callback-based exfiltration.
- Metadata Leaks (HIGH) — JSON/XML keys matching credential patterns (
api_key,secret_key,password,token, etc.), values matching known token formats (OpenAI, Stripe, GitHub personal access tokens, Slack tokens). - Unicode Steganography (MEDIUM) — Bidirectional text controls (RTL/LTR overrides), mixed Unicode scripts (Cyrillic + Latin homoglyphs) used for hidden messaging.
- Structural Anomalies (LOW) — Excessive consecutive newlines, unusual tab runs, or replacement characters indicating binary data incorrectly decoded as text.
Installation
From pip (recommended)
pip install exfil-scan
From source
git clone https://github.com/vikasudasi/exfil-scan.git
cd exfil-scan
pip install -e .
Developer install
pip install -e ".[dev]"
Usage
Scan from stdin
echo "LLM response here" | exfil-scan
Scan a file
exfil-scan response.json
Scan a directory
exfil-scan /path/to/responses/
Output formats
# Plain text (default, human-readable)
exfil-scan --format text responses.json
# JSON (machine-readable, CI integration)
exfil-scan --format json responses.json -o report.json
# HTML (browser-friendly report)
exfil-scan --format html responses.json -o report.html
# Markdown (documentation friendly)
exfil-scan --format markdown responses.json
Example output
Scanning a file containing an embedded API key:
exfil-scan report.json
exfil-scan report
=================
Scanned targets: 1
Total findings: 3
[!!!] KNOWN_TOKEN_FORMAT
Severity: high
Location: report.json:1:14
Description: Matched known credential/token format (openai_key).
Snippet: {"api_key": "sk-1234567890abcdefghijklmnopqrstuvwxyz"...
Configuration
Create a YAML config file to customize detection:
exfil-scan --dump-config > config.yaml
sensitivity: medium # low, medium, high
rules:
hidden_text:
enabled: true
severity: high
encoded_data:
enabled: true
severity: high
# ... more rules
custom_patterns:
- name: my_secret_pattern
pattern: "MY_SECRET[=_]\\s*[A-Za-z0-9]{20,}"
severity: high
CLI Options Reference
| Option | Type | Default | Description |
|---|---|---|---|
INPUT | argument | stdin | Path to an input file to scan. Omitted to read from stdin. |
-d DIRECTORY | argument | none | Path to a directory of files to scan. |
-r | flag | false | Recursively scan nested files when –directory is used. |
-c CONFIG | path | default | YAML configuration file path. |
-s LEVEL | enum | medium | Sensitivity profile: low, medium, or high. |
-f FORMAT | enum | text | Output format: text, json, html, or markdown. |
-o OUTPUT | path | stdout | Write report to this file instead of stdout. |
--dump-config | flag | false | Print default configuration to stdout and exit. |
--help | flag | n/a | Shows help message and exits. |
--version | flag | n/a | Shows version and exits. |
Configuration
Sensitivity Levels
| Level | Effect | Best For |
|---|---|---|
low | Higher thresholds, fewer false positives | Production CI pipelines |
medium | Balanced detection | General use, development |
high | Lower thresholds, catches more | Security auditing, red teaming |
Custom Patterns
Add custom regex patterns to the YAML config under custom_patterns. Each pattern needs a name, pattern (regex), and severity. Invalid regex patterns are reported as findings rather than crashing.
Architecture
cli.py argparse CLI: input selection, output formatting, config loading
config.py Default config, sensitivity adjustments, pattern definitions
scanner.py Core detection engine: 6 rule categories, severity classification
Execution flow:
- CLI parses arguments and loads YAML config
- Reads input text from file, directory, or stdin
- Scanner runs all enabled rule categories against the text
- Findings are classified by severity and sorted (HIGH → LOW)
- Formatter renders results in requested output format
Exit Codes
| Code | Meaning |
|---|---|
0 | No exfiltration signals detected (clean) |
1 | Exfiltration signals detected (findings found) |
2 | Error: invalid arguments, file not found, config error |
Testing
Run tests with:
pytest
Tests cover all six detection categories and all output formats.
License
MIT License. See LICENSE for details.