### <b>AWS SAM CLI 漏洞(CVE-2025-3047 和 CVE-2025-3048)</b>
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
本自述文件详细分析了 AWS Serverless Application Model CLI(AWS SAM CLI)中发现的两个安全漏洞——[`CVE-2025-3047`](https://www.cve.org/CVERecord?id=CVE-2025-3047) 和 [`CVE-2025-3048`](https://www.cve.org/CVERecord?id=CVE-2025-3048),以及相关的代码级问题和修复。这两个漏洞都涉及在使用 Docker 容器进行构建过程中对符号链接的不正确处理。以下每一节涵盖一个 CVE,包括摘要、受影响代码(引用 SAM CLI 源代码)、补丁及其解决问题的方式,以及补救指南。
这些缺陷涉及 `sam build --use-container` 过程中对符号链接的不当处理。这两个问题都影响本地开发环境(它们不会影响已部署的 AWS 服务或资源),但可能通过滥用 AWS SAM CLI 处理符号链接的方式,允许未经授权访问主机上的文件。强烈建议将 AWS SAM CLI 升级到已修补的版本(<b>1.133.0+</b> 用于 CVE-2025-3047,<b>1.134.0+</b> 用于 CVE-2025-3048)。
#### CVE-2025-3047 – 容器构建中的符号链接路径遍历
[GHSA-px37-jpqx-97q9](https://github.com/advisories/GHSA-px37-jpqx-97q9) 是 AWS SAM CLI <b><= v1.132.0</b> 中的一个路径遍历漏洞,允许在 `sam build --use-container` 期间未经授权访问主机上的文件。在 Docker 容器内构建无服务器应用程序时,SAM CLI 默认会<b>跟随项目中的符号链接</b>。能够在项目中植入恶意符号链接(指向敏感主机文件)的攻击者,可以利用 Docker 容器的提升权限将该文件挂载到容器中,并复制到容器内可访问的位置。实际上,这意味着特权主机文件(项目目录之外)可以通过构建容器被读取和泄露。该问题已在 <b>v1.133.0</b> 中修复。(为了保持对合法情况的向后兼容性,SAM CLI v1.133.0 引入了一个可选标志 [`--mount-symlinks`](https://aws.amazon.com/security/security-bulletins/AWS-2025-008/#:~:text=to%20access%20restricted%20files%20via,symlinks%27%20parameter),以便在需要时重新启用旧行为。)
<b>根本原因与受影响的组件:</b> 核心问题在于 AWS SAM CLI 如何将项目目录及其符号链接挂载到用于构建的 Docker 容器中。在 AWS SAM CLI 代码(模块 `samcli.local.docker.container`)中,在修复之前,<b>项目目录中的所有顶级符号链接都会被自动解析并以与容器进程相同的提升权限绑定挂载到容器中</b>。容器默认以 `root` 身份运行,因此解析并挂载指向敏感主机路径的符号链接会使容器能够访问该文件,而普通非特权主机用户通常无法访问该文件。有漏洞的代码没有充分限制要跟随/挂载哪些符号链接。
具体来说,在创建 Docker 构建卷挂载的函数中,SAM CLI 会<b>无条件地将符号链接视为要挂载的实际文件/目录</b>。该漏洞存在于 SAM CLI 的容器编排逻辑中,特别是 `samcli/local/docker/container.py` 的 `Container.create` 方法中。在受影响版本中,此方法始终尝试从项目解析符号链接目标并将其挂载到 Docker 容器中,而不考虑上下文。以下是来自 SAM CLI v1.132.0 的有漏洞代码:
```python
# samcli/local/docker/container.py (v1.132.0 - 有漏洞片段)
if self._host_dir:
mount_mode = "rw,delegated" if self._mount_with_write else "ro,delegated"
LOG.info("Mounting %s as %s:%s, inside runtime container", self._host_dir, self._working_dir, mount_mode)
_volumes = {
self._host_dir: {
"bind": self._working_dir,
"mode": mount_mode,
},
**self._create_mapped_symlink_files(), # 始终解析并挂载符号链接(有漏洞)
}
```
在上面的代码中,`_create_mapped_symlink_files()` 扫描项目目录下的符号链接并准备挂载它们。由于它被无条件包含,所有符号链接(包括指向项目外部的符号链接)都会被挂载到容器中。(参见 [aws/aws-sam-cli#7865](https://github.com/aws/aws-sam-cli/pull/7865/commits/6c8b7c41015daaed450e9a12a7166a5bc483c1f3#diff-89004c015f06af81ec7bf99d97b6827403738d2df8a288d05459b37706edfcca#:~:text=_volumes%20%3D%20,mapped_symlinks%2C))
这里的缺陷在于,在 `sam build --use-container` 期间,SAM CLI 将符号链接视为要挂载到容器中的文件。如果一个符号链接指向主机上的 `/etc/shadow`,Docker 容器(可能以提升的权限运行)将绑定挂载该文件。这是一个经典的<i>基于符号链接的路径遍历</i>,导致<b>权限提升</b>——用户通常无法访问的主机文件可以被容器读取,然后出现在构建输出中。
<b>补丁(v1.133.0 中的修复代码):</b> 修复引入了构建上下文的概念,并在容器构建期间禁用符号链接解析。在修补版本中,`Container.create` 接受一个额外的参数来指示上下文(`BUILD` vs `INVOKE`),并且只有在上下文是调用(运行本地函数时)时才解析符号链接,而不是在构建期间。以下是修补版本中的修正代码:
```python
# samcli/local/docker/container.py (v1.133.0+ - 已修补片段)
if self._host_dir:
mount_mode = "rw,delegated" if self._mount_with_write else "ro,delegated"
LOG.info("Mounting %s as %s:%s, inside runtime container", self._host_dir, self._working_dir, mount_mode)
mapped_symlinks = self._create_mapped_symlink_files() if self._resolve_symlinks(context) else {}
_volumes = {
self._host_dir: {
"bind": self._working_dir,
"mode": mount_mode,
},
**mapped_symlinks, # 仅在上下文明确允许(非构建上下文)时挂载符号链接
}
```
<i>在修补代码中,`_create_mapped_symlink_files()` 被包裹在上下文检查之后。新的 `ContainerContext` 枚举定义了 `BUILD` 和 `INVOKE` 等上下文,而 `_resolve_symlinks(context)` 对于构建上下文返回 False。因此,在构建期间 `mapped_symlinks` 将是一个空字典,意味着<b>默认情况下没有符号链接被挂载到容器中</b>。</i>
<b>代码变更参考:</b> 修复在 [Pull Request#7865](https://github.com/aws/aws-sam-cli/pull/7865)(<b>“fix: Resolve symlinks on local invoke only”</b>)中实现,并作为 v1.133.0 的一部分发布。GitHub diff 显示了 `ContainerContext` 的引入和条件挂载逻辑。通过在构建期间不挂载符号链接目标,容器不再能够访问项目目录之外的文件。(如果用户确实希望允许符号链接指向主机路径,现在必须通过 `--mount-symlinks` 标志选择加入,该标志是在此修复之后添加的。)
<b>补丁如何解决问题:</b> 打补丁后,项目中的任何符号链接在<b>构建阶段将不再被跟随</b>。它们将保留为容器中的符号链接(指向不会被挂载的路径)或被忽略,而不是被其目标的内容替换。这堵住了攻击者可能诱使构建过程复制敏感主机文件的漏洞。简而言之,构建容器的视图现在仅限于项目目录本身(加上明确允许的卷),消除了意外的权限提升。
<b>补救措施:</b> 所有用户应升级到 <b>AWS SAM CLI v1.133.0</b> 或更高版本以获取此修复。升级后,默认行为是安全的。仅当您明确信任您的项目并需要旧行为时,才应使用 `sam build --use-container --mount-symlinks`。对于大多数开发者,建议保持此标志关闭(默认值),以确保符号链接无法遍历到工作区之外。同时,良好的做法是审查项目中的任何符号链接,确保它们不指向敏感位置。
#### CVE-2025-3048 – 构建工件缓存中的符号链接内容泄露
[GHSA-pp64-wj43-xqcr](https://github.com/advisories/GHSA-pp64-wj43-xqcr) 是一个相关的漏洞,影响 AWS SAM CLI <b><= v1.133.0</b>(在 v1.134.0 中修复)。AWS SAM CLI 的<b>构建工件缓存</b>中的一个漏洞可能导致敏感文件在构建后从容器泄露到主机工作区。如果项目包含符号链接,在运行 `sam build --use-container` 后,<b>符号链接目标的内容将被复制到本地构建缓存目录</b>,作为常规文件或文件夹。实际上,没有权限访问某些主机文件的开发者可能获得访问权限,因为这些文件的内容最终出现在主机上的 `.aws-sam` 构建输出中。例如,项目中指向 `/secret/config` 的符号链接可能导致 `/secret/config` 的实际内容出现在项目的 `.aws-sam/build` 文件夹中,即使开发人员不能直接读取 `/secret/config`。
<b>根本原因与受影响的组件:</b> 这个问题的核心在于 SAM CLI 如何将文件从容器(或构建过程)复制到本地项目的构建工件目录。负责文件复制的函数位于 `samcli/lib/utils/osutils.py` 中,即自定义的 `copytree` 工具。在受影响版本中,此函数使用了 Python 的 `shutil.copy2`,但没有指定 `follow_symlinks=False`,默认情况下它<b>会跟随符号链接</b>并复制文件内容。以下片段(来自 v1.133.0)显示了有问题的逻辑:
```python
# samcli/lib/utils/osutils.py (v1.133.0 - 有漏洞片段)
# ... 在 osutils.copytree 内部 ...
else:
try:
shutil.copy2(new_source, new_destination) # follow_symlinks 默认是 True(有漏洞)
except OSError as e:
if e.errno != errno.EINVAL:
raise e
```
<i>这里,如果 `new_source` 是一个符号链接,`shutil.copy2` 将解析该符号链接并将目标文件复制到 `new_destination`。没有标志告诉它保留符号链接。因此,指向敏感文件的符号链接会导致该文件的<b>内容</b>出现在目标目录中。</i>(参见 aws/aws-sam-cli#7890)
在实际情况下,假设构建过程创建了符号链接 `config -> /etc/secret-config`(可能是作为依赖分层的一部分,或作为 CVE-2025-3047 场景的遗留物)。上述代码会将 `/etc/secret-config` 的内容复制到本地构建输出中,作为 `config`。一个无法直接读取 `/etc/secret-config` 的本地用户现在可以简单地打开 `.aws-sam/build/.../config` 下的文件并查看其内容。
<b>补丁(v1.134.0 中的修复代码):</b> 修复很简单——在复制时保留符号链接而不是跟随它们。在 Python 的 shutil 中,这是通过传递 `follow_symlinks=False` 来实现的。修补代码(v1.134.0)更改了复制调用,如下所示:
```python
# samcli/lib/utils/osutils.py (v1.134.0 - 已修补片段)
else:
try:
shutil.copy2(new_source, new_destination, follow_symlinks=False) # 不跟随符号链接(已修复)
except OSError as e:
if e.errno != errno.EINVAL:
raise e
```
<i>使用 `follow_symlinks=False` 时,如果 `new_source` 是一个符号链接,该函数将复制符号链接本身,而不是它所指向的文件。换句话说,构建输出将包含一个指向相同目标的符号链接,而不是包含目标内容的实际文件。</i>
<b>代码变更参考:</b> 此更改在 [Pull Request#7890](https://github.com/aws/aws-sam-cli/pull/7980)(<b>“fix: Keep symlinks when copying files after build”</b>)中完成,并作为 v1.134.0 的一部分发布。此 PR 的 GitHub diff 确认了将 `follow_symlinks=False` 参数添加到 `shutil.copy2`,并更新了单元测试以确保保留符号链接。PR 描述明确指出:<i>“符号链接将不再被转换为文件的副本,而是保持其符号链接状态。”</i> 这意味着构建工件将包含符号链接(引用原始文件路径),而不是未经授权的文件数据副本。
<b>补丁如何解决问题:</b> 修复后,SAM CLI 的构建后文件复制不再泄露文件内容。如果构建期间创建了符号链接,它将在输出中保持为符号链接。本地用户不会神奇地获得对目标内容的读取权限——他们只会看到一个仍然指向原始路径的符号链接。除非用户已有权限读取目标文件,否则输出中的符号链接是无害的(如果尝试在没有适当权限的情况下解引用,将会出错)。本质上,<b>机密性影响得到缓解</b>:敏感文件不会意外地具体化到用户的工作区。此修复补充了 CVE-2025-3047 的补丁:它阻止了容器通过符号链接获取主机文件;而 CVE-2025-3048 的修复阻止了任何已通过(或合法存在)的符号链接被持久化为输出中的普通文件。
<b>补救措施:</b> 用户应升级到 <b>AWS SAM CLI v1.134.0</b> 或更高版本以获取此补丁。一旦升级到 v1.134.0+,构建过程将默认保留符号链接,从而修复此漏洞。升级后,建议清理并重新构建任何 SAM 应用程序,以确保任何缓存的构建工件在新的更安全行为下重新生成(AWS 安全公告建议在升级后运行一次全新的 `sam build --use-container`)。对于较旧的版本,除了手动删除敏感的符号链接或不使用容器构建外,没有其他变通方法,因此升级是唯一可靠的解决方案。一般来说,将本地 SAM CLI 构建文件夹视为敏感输出——打补丁后,它不应再包含意外的秘密,但保持良好的实践,留意构建工件中最终出现的内容。
#### 安全影响与结论
[`CVE-2025-3047`](https://github.com/aws/aws-sam-cli/security/advisories/GHSA-px37-jpqx-97q9) 和 [`CVE-2025-3048`](https://github.com/aws/aws-sam-cli/security/advisories/GHSA-pp64-wj43-xqcr) 都涉及符号链接处理缺陷,可能导致在本地构建期间泄露机密文件。CVE-2025-3047 可能允许文件在<b>Docker 容器内部</b>被读取(并可能被复制出来),而 CVE-2025-3048 可能允许这些文件最终出现在<b>本地输出</b>中,用户或攻击者可以在之后读取它们。这些漏洞被评为中等严重性,因为它们需要一些用户交互(在恶意项目上运行构建),但可能导致高机密性影响。协调的补丁确保默认情况下,SAM CLI 在容器化构建期间既不会跟随符号链接,也不会将符号链接目标复制到输出中。
使用 SAM CLI 的开发者和 DevSecOps 专业人员应确保其 CLI 是最新的(v1.134.0 或更高版本),并对包含意外符号链接的项目保持警惕。如果您维护 SAM CLI 的分支或自定义版本,则必须合并这些相同的修复。通过理解这些代码更改,可以领会一个小小的逻辑调整——例如添加一个条件或一个函数参数——如何堵住一个严重的安全漏洞。始终考虑文件处理的安全性,尤其是在符号链接和容器交互方面,以防止在您自己的项目中出现类似的路径遍历问题。
<b>参考文献:</b>
- [AWS 安全公告 AWS-2025-008](https://aws.amazon.com/security/security-bulletins/AWS-2025-008/) – <i>AWS SAM CLI 问题(CVE-2025-3047、CVE-2025-3048)</i>
- [CVE-2025-3047 的 GitHub 咨询数据库条目](https://github.com/advisories/GHSA-px37-jpqx-97q9)
- [CVE-2025-3048 的 GitHub 咨询数据库条目](https://github.com/advisories/GHSA-pp64-wj43-xqcr)
- [aws/aws-sam-cli](https://github.com/aws/aws-sam-cli) – 来自 [`container.py`](https://github.com/valerena/aws-sam-cli/blob/6c8b7c41015daaed450e9a12a7166a5bc483c1f3/samcli/local/docker/container.py#:~:text=mapped_symlinks%20%3D%20self,else) 和 [`osutils.py`](https://github.com/aws/aws-sam-cli/pull/7890/commits/af13758eb74a72bc0702229d6cfc7e5744520d99#:~:text=Original%20file%20line%20number%20Diff,except%20OSError%20as%20e) 的相关摘录,展示了修复方法。