PEP 723 与 uv:内联元数据的安全隐患

目录

PEP 723 带有一个令人兴奋的功能——单文件 Python 脚本,你可以在脚本中直接声明依赖项,无需搭建完整的 Python 项目环境(通常还需要配置依赖项)。

让我们看一个使用 PEP 723 特性的脚本——

python
# /// script # requires-python = ">=3.11" # dependencies = [ # "requests<3", # "rich", # "stripe-client", # malicious package # ] # /// import requests from rich.table import Table from rich.console import Console console = Console() table = Table(title="User Subscriptions") # Simulate fetching user subscription data from a mock billing service resp = requests.get("https://billing.example.com/api/v1/subscriptions") if not resp.ok: console.print("[red]Failed to fetch subscriptions.[/red]") exit(1) data = resp.json() table.add_column("User ID", style="cyan") table.add_column("Plan", style="magenta") table.add_column("Status", style="green") for sub in data.get("subscriptions", []): table.add_row(sub["user_id"], sub["plan_name"], sub["status"]) console.print(table)

乍一看,这个脚本看起来简洁无害。为了安全起见,你甚至使用了 SCA 工具进行扫描,结果没有报告任何可疑内容。

理所当然,你会认为它是安全的。

但真正的陷阱在于:​你的 SCA 工具没有发现任何问题,因为它根本没有检查那里。​

为什么?

该脚本使用了 PEP 723 特性,而大多数 SCA 工具目前还不支持,因此扫描会跳过它。这正是恶意包能够悄然通过检测的方式。

什么是 PEP 723

PEP 723 引入了一种元数据格式,允许 Python 脚本直接在脚本中声明依赖项,使用特殊的注释块。

uv 这样的工具可以解析这些代码块,并在运行脚本时自动安装依赖项,使脚本的共享和使用变得更加便捷。

问题

恶意依赖项可以被注入到脚本中,能够躲过审计,不仅因为它隐藏得很好,还因为它看起来非常普通,大多数用户可能会认为它是合法的依赖项。

这些脚本具有以下特点:

  • 易于分享
  • 很少被详细审查
  • 使用 uv 等工具运行时会自动安装未经审核的包

如何保护自己?

在 SCA 工具完全支持 PEP 723 格式之前,最安全的做法是:

  • 在运行脚本之前手动审查脚本中的依赖项,尤其是使用 # /// 块的脚本。

  • 避免盲目运行使用 uv 等工具的脚本,除非你信任来源。

  • 使用 vet 等工具在运行前分析脚本包中的恶意或可疑行为。

  • 关注 pmg,我们将很快添加对 uv 的支持,该功能将允许分析内联脚本依赖项。

  • python

  • pep-723

  • security

  • uv

  • dependency-management

  • supply-chain

SafeDep 博客最新动态

关注开源安全与工程领域的最新更新和见解