shisa-ai/textguard

GitHub: shisa-ai/textguard

面向LLM系统的恶意文本防御库,专注于Unicode规范化、编码走私检测及多语言文本清洗。

Stars: 1 | Forks: 0

# textguard 面向 LLM 相关系统的恶意文本规范化、检查与清洗。 `textguard` 将可复用的文本防御工作从 [`shisad`](https://github.com/shisa-ai/shisad) 中提取出来,成为一个独立的 Python 包,可以扫描和清洗不受信任的文本输入——包括提示词、Markdown、技能文件和其他内容——而无需引入守护进程或框架依赖。 - 合法多语言 Unicode 文本是一等用例,因此我们**不会**默认将所有内容转换为 ASCII。 - 有损转换始终显式选择加入。 - 所有解码路径都有深度限制和扩展限制。 - 发现结果带有严重性级别(`info`、`warn`、`error`)——没有不透明的聚合风险评分。 - 该包不会静默下载模型或发起网络请求。 ## 安装 ``` pip install textguard # core only, zero dependencies pip install 'textguard[yara]' # + pattern-based detection pip install 'textguard[all]' # everything ``` 或使用 uv: ``` uv pip install textguard uv tool install textguard # CLI-only, isolated uvx textguard scan SKILL.md # one-shot, no install ``` ## CLI CLI 的行为类似于 UNIX 文本工具:通过管道传递文本,在 Shell 脚本中使用,或指向文件。默认用法与 `cat` 或 `sed` 相当:从 stdin 或文件读取,将清洗后的输出写入 stdout。 CLI 和 [Python API](#python-api) 均专为代理工作流设计。在不受信任的输入到达模型之前对其进行扫描,或将其作为流水线的一部分进行内联清洗。 ``` # 扫描:只读,报告发现 textguard scan SKILL.md textguard scan SKILL.md --json textguard scan docs/*.md --json > report.json # 清理:输出清理后的文本 textguard clean SKILL.md # cleaned text to stdout textguard clean SKILL.md -i # overwrite in place textguard clean SKILL.md -o out.md # write to file textguard clean SKILL.md -i --report # overwrite, human-readable report to stderr cat untrusted.txt | textguard clean - # pipe from stdin # 预设 textguard clean SKILL.md --preset strict textguard clean SKILL.md --preset ascii # 可选后端 textguard scan --yara-rules ./rules/ SKILL.md textguard scan --no-yara-bundled SKILL.md textguard scan --split-tokens SKILL.md textguard scan --promptguard ~/.local/share/textguard/models/promptguard2/ SKILL.md ``` ### 预设 预设控制清洗的激进程度: | 预设 | 规范化 | 剥离 | 解码 | 用例 | |--------|--------------|--------|---------|----------| | **default** | NFC | 标签字符、软连字符、空白折叠、组合标记上限 | 否 | 对包括中日韩(CJK)在内的所有多语言文本均安全 | | **strict** | NFKC | 所有不可见字符、双向控制字符、变体选择器、标签字符、软连字符 | 全部七层 | 技能文件、提示词、隐藏内容可疑的上下文 | | **ascii** | NFKC + ASCII 音译 | 所有非 ASCII 字符 | 全部七层 | 当您明确想要仅 ASCII 输出时 | 默认预设保留了合法的多语言文本。NFKC 不是默认选项,因为它会破坏日语和其他文字中的语义内容。Strict 和 ascii 预设选择加入 progressively 更激进的清洗。 扫描时的分析有意比重写时的清洗更激进。`scan()` 始终剥离恶意格式并展开有界编码进行分析;预设控制 `clean()` 将哪些内容重写为返回的输出。 分词(split-token)走私检测是可选的。通过 `TextGuard(split_tokens=True)`、`TEXTGUARD_SPLIT_TOKENS=1`、配置文件 `split_tokens = true` 或 CLI `--split-tokens` 启用它。 `scan` 的退出代码反映结果中的最强信号:结构发现映射为 `0` 无、`1` 信息、`2` 警告、`3` 错误;语义层级映射为 `0` 无、`1` 中、`2` 高、`3` 严重。跨子命令的运行时故障返回 `4`。 ## 防护层级 textguard 组织为三个层级。每一层都在前一层的基础上增加检测能力。 | 层级 | 安装 | 检测内容 | 占用 | |------|---------|----------------|-----------| | **Core** | `textguard` | 不可见字符、双向控制滥用、标签字符、软连字符、变体选择器、Zalgo、同形异义字/混合脚本、编码层滥用(URL、HTML 实体、ROT13、base64、Unicode 转义、十六进制转义、Punycode) | 仅 stdlib,体积小 | | **YARA** | `textguard[yara]` | 基于模式的检测:提示词注入短语、工具欺骗标签、自定义签名。对原始文本和解码后的文本均运行。 | +~6 MB (`yara-python`) | | **PromptGuard** | `textguard[promptguard]` | 通过 ONNX 模型进行语义提示词注入/越狱分类。 | +~27 MB wheels (`onnxruntime`, `transformers`) + 首次获取时约 295 MB 模型 | Core 没有运行时依赖。重型后端始终是可选的额外项。 ## 模型管理 PromptGuard 需要约 295 MB 的 ONNX 模型包 ([shisa-ai/promptguard2-onnx](https://huggingface.co/shisa-ai/promptguard2-onnx))。textguard 绝不会静默下载模型。 ``` # 获取、验证并安装到 XDG data dir textguard models fetch promptguard2 # 将 textguard 指向它 export TEXTGUARD_PROMPTGUARD_MODEL=~/.local/share/textguard/models/promptguard2 # 或直接传递 textguard scan --promptguard ~/.local/share/textguard/models/promptguard2 SKILL.md ``` `textguard models fetch promptguard2` 通过 stdlib HTTP 从 Hugging Face 下载,使用捆绑的公钥验证 SSH ed25519 签名,并在根据清单检查 SHA-256 文件哈希后,将其安装在 `~/.local/share/textguard/models/promptguard2/` 下(如果设置了 `XDG_DATA_HOME`,则为该路径)。 ## Python API 两个主要调用是 `scan()` 和 `clean()`——它们的作用正如您所料。`scan()` 检查文本并返回发现结果;`clean()` 重写文本并移除恶意内容。 ``` from textguard import scan, clean, TextGuard # 快速函数式 API — 使用默认值,零配置 result = scan(text) # ScanResult cleaned = clean(text) # CleanResult # 配置好的实例 — 可复用,携带后端状态 guard = TextGuard( preset="strict", split_tokens=True, yara_rules_dir="./rules/", promptguard_model_path="~/.local/share/textguard/models/promptguard2/", ) result = guard.scan(text) # ScanResult cleaned = guard.clean(text) # CleanResult semantic = guard.score_semantic(text) # SemanticResult ``` 顶层的 `scan()` 和 `clean()` 是使用默认设置的 `TextGuard` 的薄包装器。对于重复调用或启用后端的扫描,请创建 `TextGuard` 实例。 ### 结果 `scan()` 返回 `ScanResult`——发现结果、解码元数据和可选的语义分类: ``` result = scan(text) for f in result.findings: print(f"{f.severity}: {f.kind} at offset {f.offset} — {f.detail}") ``` `clean()` 返回 `CleanResult`——清洗后的文本以及变更报告: ``` cleaned = clean(text) print(cleaned.text) # the safe output for c in cleaned.changes: print(f" {c.kind}: {c.detail}") ``` ## 依赖与供应链 - **Core runtime**:核心仅依赖 stdlib,且**没有运行时依赖**。 - **Unicode 数据**:用于脚本范围和混淆字符的 vendored Unicode 数据通过手动脚本运行生成。 - **可选 YARA**:`yara-python>=4.5.4` - **可选 PromptGuard**:`onnxruntime>=1.24.4`,`transformers>=5.5.3` - 通过 `pyproject.toml` 中的最低版本进行固定。通过提交的带有哈希的 `uv.lock` 进行精确解析。 [pypi 包](https://pypi.org/project/textguard) 通过带有 OIDC 和 SBOM 的 Github CI 发布。 ## 相关项目 我们的工作主要依赖于这些公开贡献: - [Unicode 17.0 Scripts](https://www.unicode.org/Public/17.0.0/ucd/Scripts.txt) - [Unicode 17.0 Confusables](https://www.unicode.org/Public/security/17.0.0/confusables.txt) - [YARA](https://virustotal.github.io/yara/) / [yara-python](https://github.com/VirusTotal/yara-python) - [Llama Prompt Guard 2](https://github.com/meta-llama/PurpleLlama/tree/main/Llama-Prompt-Guard-2) 虽然 textguard 填补了一个独特的利基市场(面向 LLM 输入的恶意 Unicode 和编码走私),但也有一些基础和相关项目: - Unicode 安全参考: - https://www.unicode.org/reports/tr36/ — 关于 Unicode 攻击面的基础文档 - https://www.unicode.org/reports/tr39/ — 正式规定混淆字符和混合脚本检测的地方 - Unicode / 文本规范化: - https://github.com/rspeer/python-ftfy — 修复 Mojibake 和编码问题 - https://github.com/vhf/confusable_homoglyphs — 基于相同 Unicode 混淆字符数据构建的 Python 库 - https://github.com/avian2/unidecode — ASCII 音译
标签:Agent工作流, AI基础设施, API密钥检测, CNCF毕业项目, DLL 劫持, DNS信息、DNS暴力破解, DNS枚举, Naabu, Unicode处理, YARA规则, 内容安全, 大语言模型, 对抗性文本, 恶意文本检测, 提示词注入防御, 数据预处理, 文本归一化, 文本清洗, 无依赖, 模式匹配, 系统调用监控, 网络安全工具, 自动化资产收集, 输入验证, 逆向工具