
Issue with AWS SAM CLI (CVE-2025-3047, CVE-2025-3048)
В этом README представлен подробный анализ двух уязвимостей безопасности, обнаруженных в AWS Serverless Application Model CLI (AWS SAM CLI) – CVE-2025-3047 и CVE-2025-3048 – а также проблемы и исправления на уровне кода. Обе уязвимости связаны с некорректной обработкой символических ссылок (symlinks) во время процесса сборки с использованием контейнеров Docker. Каждый раздел ниже описывает один CVE с кратким обзором, затронутым кодом (со ссылками на исходный код SAM CLI), исправлением и тем, как оно решает проблему, а также рекомендациями по устранению.
Эти недостатки связаны с некорректной обработкой символических ссылок во время sam build --use-container. Обе проблемы затрагивают локальные среды разработки (они не влияют на развернутые сервисы или ресурсы AWS), но могут позволить несанкционированный доступ к файлам на хост-машине путем злоупотребления тем, как AWS SAM CLI обрабатывает символические ссылки. Настоятельно рекомендуется обновить AWS SAM CLI до исправленных версий (1.133.0+ для CVE-2025-3047 и 1.134.0+ для CVE-2025-3048).
GHSA-px37-jpqx-97q9 – это уязвимость обхода пути в AWS SAM CLI <= v1.132.0, которая позволяла несанкционированный доступ к файлам на хост-машине во время sam build --use-container. При сборке серверного приложения внутри контейнера Docker SAM CLI по умолчанию следовал символическим ссылкам в проекте. Злоумышленник, разместивший вредоносную символическую ссылку в проекте (указывающую на конфиденциальный файл хоста), мог воспользоваться повышенными привилегиями контейнера Docker, чтобы смонтировать этот файл в контейнер и скопировать его в доступное внутри контейнера место. По сути, это означало, что привилегированные файлы хоста (вне каталога проекта) могли быть прочитаны и выкрадены через сборочный контейнер. Проблема была исправлена в v1.133.0. (Для сохранения обратной совместимости в легитимных случаях SAM CLI v1.133.0 ввел опциональный флаг --mount-symlinks для повторного включения старого поведения при необходимости.)
Основная причина и затронутый компонент: Основная проблема заключается в том, как AWS SAM CLI монтирует каталоги проекта и их символические ссылки в контейнер Docker, используемый для сборки. В коде AWS SAM CLI (модуль samcli.local.docker.container) до исправления все символические ссылки верхнего уровня в каталоге проекта автоматически разрешались и монтировались в контейнер с теми же повышенными привилегиями, что и процесс контейнера. Контейнер по умолчанию работает от имени root, поэтому разрешение и монтирование символической ссылки, указывающей на конфиденциальный путь хоста, давало контейнеру доступ к этому файлу, который непривилегированный пользователь хоста обычно не имел. Уязвимый код недостаточно ограничивал, за какими символическими ссылками следовать/какие монтировать.
В частности, в функции, создающей тома Docker для сборки, SAM CLI безусловно обрабатывал символические ссылки как фактические файлы/каталоги для монтирования. Уязвимость находилась в логике оркестрации контейнеров SAM CLI, а именно в методе Container.create файла samcli/local/docker/container.py. В уязвимых версиях этот метод всегда пытался разрешить и смонтировать цели символических ссылок из проекта в контейнер Docker, независимо от контекста. Проблемный код показан ниже, из SAM CLI v1.132.0:
# 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)
Недостаток здесь в том, что во время sam build --use-container SAM CLI рассматривает символические ссылки как файлы для монтирования в контейнер. Если символическая ссылка указывала, скажем, на /etc/shadow на хосте, контейнер Docker (который может работать с повышенными привилегиями) смонтировал бы этот файл. Это классический обход пути на основе символических ссылок, приводящий к повышению привилегий – файлы хоста, к которым у пользователя обычно нет доступа, могли быть прочитаны контейнером и затем оказаться в выводе сборки.
Исправление (исправленный код в v1.133.0): Исправление вводит понятие контекста сборки и отключает разрешение символических ссылок во время сборки в контейнере. В исправленной версии Container.create принимает дополнительный параметр, указывающий контекст (BUILD или INVOKE), и будет разрешать символические ссылки только если контекст – вызов (при локальном запуске функций), а не во время сборки. Ниже приведен исправленный код из исправленной версии:
# 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, # Монтировать символические ссылки только если это явно разрешено контекстом (не при сборке)
}
В исправленном коде _create_mapped_symlink_files() обернута проверкой контекста. Новое перечисление ContainerContext определяет контексты BUILD и INVOKE, и _resolve_symlinks(context) возвращает False для контекста сборки. Таким образом, mapped_symlinks будет пустым словарем во время сборки, что означает по умолчанию никакие символические ссылки не монтируются в контейнер.
Ссылка на изменение кода: Исправление было реализовано в Pull Request#7865 («fix: Resolve symlinks on local invoke only») и выпущено в составе v1.133.0. Различие на GitHub показывает введение ContainerContext и условную логику монтирования. Отказ от монтирования целей символических ссылок во время сборки означает, что контейнер больше не получает доступа к файлам за пределами каталога проекта. (Если пользователь все же хочет разрешить символические ссылки на пути хоста, теперь он должен явно указать флаг --mount-symlinks, который был добавлен после этого исправления.)
Как исправление решает проблему: После исправления любые символические ссылки в проекте больше не будут обрабатываться во время фазы сборки. Они останутся символическими ссылками в контейнере (указывающими на пути, которые не будут смонтированы) или будут проигнорированы, вместо того чтобы быть замененными содержимым их целей. Это закрывает лазейку, через которую злоумышленник мог обманом заставить процесс сборки скопировать конфиденциальные файлы хоста. Короче говоря, обзор сборочного контейнера теперь ограничен самим каталогом проекта (плюс явно разрешенные тома), что устраняет непреднамеренное повышение привилегий.
Устранение: Всем пользователям следует обновиться до AWS SAM CLI v1.133.0 или новее, чтобы получить это исправление. После обновления поведение по умолчанию безопасно. Только если вы явно доверяете своему проекту и нуждаетесь в старом поведении, следует использовать sam build --use-container --mount-symlinks. Для большинства разработчиков рекомендуется оставить этот флаг отключенным (по умолчанию), чтобы гарантировать, что символические ссылки не смогут выйти за пределы рабочей области. Также полезно проверить любые символические ссылки в ваших проектах на предмет того, не указывают ли они на конфиденциальные места.
GHSA-pp64-wj43-xqcr – это связанная уязвимость, затрагивающая AWS SAM CLI <= v1.133.0 (исправлена в v1.134.0). Уязвимость в кэшировании артефактов сборки AWS SAM CLI могла привести к утечке конфиденциальных файлов из контейнера обратно в рабочее пространство хоста после сборки. Если проект содержал символические ссылки, после выполнения sam build --use-container содержимое целей символических ссылок копировалось в локальный каталог кэша сборки как обычные файлы или папки. По сути, разработчик без доступа к определенным файлам хоста мог получить к ним доступ, поскольку содержимое этих файлов оказывалось в выводе сборки .aws-sam на хосте. Например, символическая ссылка в проекте, указывающая на /secret/config, могла привести к тому, что фактическое содержимое /secret/config появлялось в папке .aws-sam/build проекта после сборки в контейнере, даже если пользователь не мог напрямую прочитать /secret/config.
Основная причина и затронутый компонент: Суть проблемы заключалась в том, как SAM CLI копировал файлы из контейнера (или из процесса сборки) в локальный каталог артефактов сборки проекта. Функция, отвечающая за копирование файлов, находится в samcli/lib/utils/osutils.py, а именно пользовательская утилита copytree. В уязвимых версиях эта функция использовала Python shutil.copy2 без указания follow_symlinks=False, что по умолчанию следует символическим ссылкам и копирует содержимое файлов. Фрагмент ниже (из v1.133.0) показывает проблемную логику:
# 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
Здесь, если new_source является символической ссылкой, shutil.copy2 разрешит символическую ссылку и скопирует целевой файл в new_destination. Не было флага, указывающего сохранить символическую ссылку. Таким образом, символическая ссылка на конфиденциальный файл приводила к тому, что содержимое этого файла появлялось в каталоге назначения. (см. aws/aws-sam-cli#7890)
Практически это означает: представьте, что процесс сборки создал символическую ссылку config -> /etc/secret-config (возможно, как часть наслоения зависимостей или оставшуюся после сценария CVE-2025-3047). Приведенный выше код скопировал бы содержимое /etc/secret-config в локальный вывод сборки как config. Локальный пользователь, не имеющий прямого доступа к /etc/secret-config, мог бы теперь просто открыть файл в .aws-sam/build/.../config и увидеть его содержимое.
Исправление (исправленный код в v1.134.0): Исправление было простым – сохранять символические ссылки вместо их разрешения при копировании. В Python shutil это делается путем передачи follow_symlinks=False. Исправленный код (v1.134.0) изменяет вызов copy следующим образом:
# 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
С follow_symlinks=False, если new_source является символической ссылкой, функция скопирует саму символическую ссылку а не файл, на который она указывает. Другими словами, вывод сборки будет содержать символическую ссылку с той же целью, а не реальный файл с содержимым цели.
Ссылка на изменение кода: Изменение было сделано в Pull Request#7890 («fix: Keep symlinks when copying files after build») и выпущено в v1.134.0. Различие на GitHub для этого PR подтверждает добавление параметра follow_symlinks=False в shutil.copy2, а также обновленные модульные тесты, гарантирующие сохранение символических ссылок. В описании PR явно указано: «Символические ссылки перестанут преобразовываться в копии файлов и сохранят свой статус символической ссылки.» Это означает, что артефакты сборки будут содержать символические ссылки (которые ссылаются на исходные пути файлов) вместо несанкционированных копий данных файлов.
Как исправление решает проблему: После этого исправления копирование файлов после сборки SAM CLI больше не приводит к утечке содержимого файлов. Если во время сборки была создана символическая ссылка, она останется символической ссылкой в выводе. Локальный пользователь не получит магического доступа на чтение содержимого цели – он увидит только символическую ссылку, которая по-прежнему указывает на исходный путь. Если у пользователя нет разрешения на чтение целевого файла, символическая ссылка в выводе безвредна (она выдаст ошибку при попытке разыменования без соответствующих прав). По сути, воздействие на конфиденциальность смягчено: конфиденциальные файлы непреднамеренно не материализуются в рабочем пространстве пользователя. Это исправление дополняет исправление CVE-2025-3047: оно остановило контейнер от захвата файлов хоста через символические ссылки; исправление CVE-2025-3048 не позволяет тем, которые всё же прошли (или существовали легитимно), быть сохраненными как обычные файлы в выводе.
Устранение: Пользователям следует обновиться до AWS SAM CLI v1.134.0 или новее, чтобы получить это исправление. После перехода на v1.134.0+ процесс сборки будет по умолчанию сохранять символические ссылки, устраняя эту уязвимость. После обновления рекомендуется очистить и пересобрать любые SAM-приложения, чтобы гарантировать, что любые кэшированные артефакты сборки будут регенерированы в соответствии с новым более безопасным поведением (бюллетень безопасности AWS советует после обновления выполнить новую sam build --use-container). Для старых версий обходных путей решения этой проблемы не существует, кроме ручного удаления конфиденциальных символических ссылок или отказа от сборок в контейнерах, поэтому обновление является единственным надежным решением. В целом, относитесь к локальной папке сборки SAM CLI как к конфиденциальному выводу – с исправлением она больше не должна содержать неожиданных секретов, но полезно следить за тем, что оказывается в ваших артефактах сборки.
Обе уязвимости CVE-2025-3047 и CVE-2025-3048 связаны с недостатками обработки символических ссылок, которые могут привести к раскрытию конфиденциальных файлов во время локальных сборок. CVE-2025-3047 могла позволить чтение файлов внутри контейнера Docker (и, возможно, их копирование наружу), в то время как CVE-2025-3048 могла привести к тому, что эти файлы оказывались в локальном выводе, где пользователь или злоумышленник могли прочитать их позже. Эти уязвимости были оценены как умеренные по серьезности, поскольку они требуют некоторого взаимодействия с пользователем (выполнение сборки на вредоносном проекте), но могут привести к высокому влиянию на конфиденциальность. Согласованные исправления гарантируют, что по умолчанию SAM CLI не будет следовать символическим ссылкам во время сборок в контейнерах и не будет копировать цели символических ссылок в вывод.
Разработчики и специалисты DevSecOps, использующие SAM CLI, должны убедиться, что их CLI обновлен (v1.134.0 или новее), и сохранять осторожность в отношении проектов, содержащих неожиданные символические ссылки. Если вы поддерживаете форкнутые или измененные версии SAM CLI, вы должны включить в них те же исправления. Понимая эти изменения кода, можно оценить, как небольшая корректировка логики – например, добавление условия или параметра функции – может закрыть серьезную брешь в безопасности. Всегда учитывайте безопасность обработки файлов, особенно когда речь идет о символических ссылках и взаимодействии с контейнерами, чтобы предотвратить подобные проблемы обхода пути в ваших собственных проектах.
Ссылки:
container.py и osutils.py, демонстрирующие исправления