
AWS SAM CLI 관련 이슈 (CVE-2025-3047, CVE-2025-3048)
이 README는 AWS Serverless Application Model CLI(AWS SAM CLI)에서 발견된 두 가지 보안 취약점인 CVE-2025-3047 및 CVE-2025-3048과 코드 수준의 문제 및 수정 사항에 대한 상세 분석을 제공합니다. 두 취약점 모두 Docker 컨테이너를 사용한 빌드 프로세스 중 심볼릭 링크(심링크)를 부적절하게 처리하는 것과 관련됩니다. 아래의 각 섹션은 하나의 CVE를 요약, 영향을 받는 코드(SAM CLI 소스 참조 포함), 패치와 문제 해결 방식, 그리고 해결 방법 안내로 다룹니다.
이 결함들은 sam build --use-container 프로세스 중 심볼릭 링크(심링크)를 부적절하게 처리하는 것과 관련됩니다. 두 문제 모두 로컬 개발 환경에 영향을 미치며(배포된 AWS 서비스나 리소스에는 영향을 주지 않음), AWS SAM CLI가 심링크를 처리하는 방식을 악용하여 호스트 머신의 파일에 대한 무단 접근을 허용할 수 있습니다. 패치된 버전(1.133.0+은 CVE-2025-3047용, 1.134.0+은 CVE-2025-3048용)으로 AWS SAM CLI를 업그레이드하는 것이 강력히 권장됩니다.
GHSA-px37-jpqx-97q9은 sam build --use-container 중 호스트 머신에서 허가되지 않은 파일 접근을 허용한 AWS SAM CLI <= v1.132.0의 경로 탐색 취약점입니다. 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의 컨테이너 오케스트레이션 로직, 특히 samcli/local/docker/container.py의 Container.create 메서드에 있었습니다. 취약한 버전에서 이 메서드는 컨텍스트와 관계없이 항상 프로젝트의 심링크 대상을 확인하고 Docker 컨테이너에 마운트하려고 시도했습니다. 문제가 있는 코드는 아래와 같습니다(SAM CLI v1.132.0).
# samcli/local/docker/container.py (v1.132.0 - vulnerable snippet)
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(), # Always resolve and mount symlinks (vulnerable)
}
위 코드에서 _create_mapped_symlink_files()는 프로젝트 디렉터리 아래의 심링크를 검색하여 마운트할 준비를 합니다. 이것이 조건 없이 포함되었기 때문에 모든 심링크(프로젝트 외부를 가리키는 심링크 포함)가 컨테이너에 마운트되었습니다. (aws/aws-sam-cli#7865 참조)
여기서의 결함은 sam build --use-container 중 SAM CLI가 심링크를 컨테이너에 마운트할 파일로 취급한다는 것입니다. 심링크가 예를 들어 호스트의 /etc/shadow를 가리킨다면, (상승된 권한으로 실행될 수 있는) Docker 컨테이너가 해당 파일을 바인드 마운트하게 됩니다. 이는 전형적인 심링크 기반 경로 탐색으로, 권한 상승으로 이어집니다. 사용자가 일반적으로 접근할 수 없는 호스트 파일을 컨테이너가 읽은 다음 빌드 출력에 남길 수 있습니다.
패치(v1.133.0의 수정 코드): 수정은 빌드 컨텍스트 개념을 도입하고 컨테이너 빌드 중 심링크 확인을 비활성화합니다. 패치된 버전에서 Container.create는 컨텍스트(BUILD vs INVOKE)를 나타내는 추가 매개변수를 받으며, 로컬에서 함수를 실행하는 호출(invocation) 컨텍스트에서만 심링크를 확인하고 빌드 중에는 확인하지 않습니다. 아래는 패치된 버전의 수정 코드입니다.
# samcli/local/docker/container.py (v1.133.0+ - patched snippet)
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, # Only mount symlinks if explicitly allowed by context (not in build)
}
패치된 코드에서 _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 diff는 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 유틸리티입니다. 취약한 버전에서 이 함수는 follow_symlinks=False를 지정하지 않고 Python의 shutil.copy2를 사용했으며, 기본적으로 심링크를 따라가 파일 내용을 복사했습니다. 아래 스니펫(v1.133.0)은 문제가 있는 로직을 보여줍니다.
# samcli/lib/utils/osutils.py (v1.133.0 - vulnerable snippet)
# ... inside osutils.copytree ...
else:
try:
shutil.copy2(new_source, new_destination) # follow_symlinks is True by default (vulnerable)
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)는 복사 호출을 다음과 같이 변경합니다.
# samcli/lib/utils/osutils.py (v1.134.0 - patched snippet)
else:
try:
shutil.copy2(new_source, new_destination, follow_symlinks=False) # Do not follow symlinks (fixed)
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에서 릴리스되었습니다. 이 PR의 GitHub diff는 shutil.copy2에 follow_symlinks=False 매개변수가 추가된 것을 확인시켜 주며, 심링크가 유지되도록 업데이트된 단위 테스트와 함께 제공됩니다. PR 설명에는 “심링크는 더 이상 파일의 복사본으로 변환되지 않고 심링크 상태를 유지합니다.”라고 명시되어 있습니다. 이는 빌드 아티팩트에 파일 데이터의 무단 복사본 대신 (원본 파일 경로를 참조하는) 심링크가 포함된다는 것을 의미합니다.
패치가 문제를 해결하는 방식: 이 수정 후 SAM CLI의 빌드 후 파일 복사는 더 이상 파일 내용을 유출하지 않습니다. 빌드 중에 생성된 심링크는 출력에서 계속 심링크로 남습니다. 로컬 사용자는 대상 콘텐츠에 대한 읽기 권한을 마술처럼 얻지 못하며, 원래 경로를 계속 가리키는 심링크를 보게 될 뿐입니다. 사용자에게 대상 파일을 읽을 권한이 이미 없는 한, 출력의 심링크는 무해합니다(적절한 권한 없이 역참조하면 오류가 발생합니다). 본질적으로 기밀성 영향이 완화됩니다. 민감한 파일이 우연히 사용자의 작업 영역에 실재하는 파일로 생성되지 않습니다. 이 수정은 CVE-2025-3047 패치를 보완합니다. 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가 컨테이너화된 빌드 중에 심링크를 따라가지도 않고 심링크 대상을 출력으로 복사하지도 않도록 보장합니다.
SAM CLI를 사용하는 개발자와 DevSecOps 전문가는 CLI를 최신 상태(v1.134.0 이상)로 유지하고 예상치 못한 심링크가 포함된 프로젝트에 대해 주의를 기울여야 합니다. SAM CLI의 포크(fork) 또는 사용자 지정 버전을 유지 관리하는 경우에도 이러한 수정 사항을 동일하게 통합해야 합니다. 이러한 코드 변경을 이해하면 조건문이나 함수 매개변수 추가 같은 작은 로직 변경이 심각한 보안 허점을 어떻게 막을 수 있는지 알 수 있습니다. 파일 처리, 특히 심링크와 컨테이너 상호작용과 관련된 보안을 항상 고려하여 자신의 프로젝트에서도 유사한 경로 탐색 문제를 예방하십시오.
참조:
container.py 및 osutils.py의 관련 발췌문