FlawOpen

flawopen.com/Teardowns/cve-2026-87913-aws-security-agent-mcp-s3-bucket-ownership

● CVE-2026-87913 · CVSS 5.1 · 보통
보안 연구 · FlawOpen

CVE-2026-87913: AWS MCP S3 데이터 노출

예측 가능한 버킷에 비공개 스캔 아카이브가 다른 계정으로 업로드될 수 있었습니다. 0.2.0으로 업데이트하고 소유자를 확인하세요.[1], [2], [4]

💡 알기 쉬운 설명 (ELI5)

배달원이 주소에 건물이 있는지만 확인하고 소유자는 확인하지 않는다고 상상해 보세요. 다른 사람이 주소를 먼저 등록해 소포를 받을 수 있습니다. 수정 버전은 확인과 업로드 모두에서 S3가 예상 소유자를 검증하게 합니다.[2], [1]

핵심 개념 및 용어

MCP 서버
AI 어시스턴트에 도구 작업을 제공하는 로컬 서비스이며 서버 프로세스 권한으로 실행됩니다.[3]
S3 버킷
전역 이름을 가진 Amazon S3 컨테이너입니다. 이름만으로 AWS 소유 계정을 확인할 수 없습니다.[2], [3]
ExpectedBucketOwner
작업 전에 예상 소유자의 AWS 계정 ID를 S3가 확인하도록 하는 요청 매개변수입니다.[2], [8], [9]
CWE-283 및 CWE-341
소유권 미검증과 관찰 가능한 정보로 예측 가능한 값을 나타내는 MITRE 분류이며 권고문은 둘 다 연결합니다.[8], [9]

프레임워크 매핑

근본 원인 분석 (Root Cause)

AWS Security Agent MCP 서버는 고객 AWS 계정 ID와 리전으로 스캔 입력 버킷 이름 security-agent-scans-<account-id>-<region>을 만듭니다. AWS와 메인테이너 권고문에 따르면 취약 버전은 버킷이 존재하는지만 확인하고 고객 계정 소유 여부는 검증하지 않았습니다. S3 이름은 전역적으로 고유하고 계정 ID는 공개 정보입니다. 제3자가 예측 가능한 이름을 먼저 등록하면 서버가 올리는 비공개 소스 아카이브를 받을 수 있으며 소스, 자격 증명, 인프라 상태가 들어갈 수 있습니다. 이는 클라우드 리소스 소유권 검증과 예측 가능한 이름의 문제이지 AI 모델의 프롬프트 인젝션은 아닙니다. 0.1.0~0.1.5가 영향받고 0.2.0은 S3 작업에 ExpectedBucketOwner를 추가해 불일치 시 실패합니다. 업데이트해도 이미 등록된 이름은 해제되지 않습니다. 실제 소유자를 확인하고 제3자 소유면 스캔을 재개하지 마세요.

버킷 이름은 소유권을 증명하지 않습니다

경계문서화된 조건운영자 조치
영향받는 버전awslabs.security-agent-mcp-server 0.1.0~0.1.5가 영향을 받으며 0.2.0에서 소유자 검증이 추가됐습니다.0.2.0 이상으로 업그레이드하고 실행 중인 패키지 버전을 확인하세요.
예측 가능한 버킷 이름스캔 버킷 이름은 계정 ID와 리전으로 만들어지며 다른 AWS 계정이 먼저 등록할 수 있습니다.일치하는 이름은 주소로만 보고 소유권 증거로 간주하지 마세요.
계정 간 업로드취약한 서버는 소유자를 확인하지 않고 이름만으로 버킷을 받아들인 뒤 비공개 스캔 아카이브를 업로드할 수 있었습니다.스캔이나 업로드 전에 버킷이 예상 계정 소유인지 확인하세요.
수정된 소유권 경계ExpectedBucketOwner를 사용하면 S3가 소유권 확인과 업로드 모두에서 소유자를 비교합니다.업그레이드하고 실제 소유자를 확인하세요. 제3자가 소유한 이름이면 스캔을 중지하세요. 업그레이드가 버킷 소유권을 이전하지는 않습니다.

단계별 공격 실행 흐름

단계 1

스캔 요청이 소스를 받는다

AI 클라이언트가 스캔을 요청하면 로컬 서버는 작업공간을 묶고 설정된 AWS ID를 사용합니다.[3], [2]

단계 2

대상 이름은 예측 가능하다

버킷 이름은 계정 ID와 리전으로 만들어지며 ID는 비밀이 아니고 S3 이름은 전역 범위입니다.[1], [2]

단계 3

검사는 존재 여부만 본다

취약 서버는 이름으로 버킷을 받아들였지만 고객 계정 소유 여부를 확인하지 않았습니다.[2], [1]

단계 4

아카이브가 다른 계정에 도달할 수 있다

다른 계정이 이름을 먼저 등록했다면 민감 정보가 든 비공개 아카이브를 받을 수 있습니다.[2], [1]

소스 코드 비교: 취약한 구현 vs 보안 패치

아래 코드는 설명용 구조이며 실제 소스의 그대로 복사본은 아닙니다. 존재 여부만 확인해서는 부족합니다. S3가 확인과 쓰기 모두에서 예상 소유자를 비교해야 합니다. 인증된 AWS ID에서 기대값을 가져오고 불일치 시 중단하세요. 업데이트 후에도 기존 이름은 이전되거나 해제되지 않으므로 소유자를 별도로 확인하세요. AWS 문서에 따르면 HeadBucket과 PutObject 모두 ExpectedBucketOwner를 지원하며 소유자가 일치하지 않으면 요청이 403으로 실패합니다. fail-closed 보호로 사용하되, 버킷이 타인 소유라고 결론 내리기 전에 승인된 소유권 확인 경로로 액세스 거부 오류를 조사하세요.[2], [8], [9]

소스 코드 발췌: 권고문을 바탕으로 한 AWS SDK 예시이며, 소스 코드의 그대로인 diff는 아닙니다.

취약한 구현
# 단순화한 취약 형태: 이름은 확인하지만 소유자는 확인하지 않습니다.
s3.head_bucket(Bucket=bucket_name)
s3.put_object(
    Bucket=bucket_name,
    Key=object_key,
    Body=archive_bytes,
)
보안 강화 패치
# 각 작업을 버킷을 소유해야 하는 계정에 바인딩합니다.
expected_owner = sts.get_caller_identity()["Account"]
s3.head_bucket(
    Bucket=bucket_name,
    ExpectedBucketOwner=expected_owner,
)
s3.put_object(
    Bucket=bucket_name,
    Key=object_key,
    Body=archive_bytes,
    ExpectedBucketOwner=expected_owner,
)

엔지니어링 및 시스템 보안 강화 체크리스트

출처