目录
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 博客最新动态
关注开源安全与工程领域的最新更新和见解