FlawOpen

flawopen.com/Teardowns/cve-2026-97662-aws-security-agent-mcp-git-argument-injection

● CVE-2026-97662 · CVSS v4 6.9 · 보통
보안 연구 · FlawOpen

CVE-2026-97662: AWS 보안 에이전트 MCP의 Git 인자 인젝션

CVE-2026-97662는 AWS Security Agent MCP diff scan에서 호출자가 영향을 줄 수 있는 Git 참조를 명령 옵션으로 해석하게 해 workspace 제한을 우회하고 호스트 파일을 쓸 수 있게 했습니다. 0.2.0 이상으로 업데이트하세요.[1], [2]

CVSS 벡터CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:H/SC:N/SI:N/SA:N
💡 알기 쉬운 설명 (ELI5)

직원이 라벨로 폴더를 찾도록 지시받았지만 제어 지시로 시작하는 라벨도 받아들입니다. 보관 시스템은 폴더를 찾는 대신 지시를 실행합니다. 이 문제에서는 하이픈으로 시작하는 Git 참조가 옵션으로 해석될 수 있었습니다. Git을 실행하기 전에 빈 참조와 옵션처럼 보이는 참조를 거부하면 이 입력 경계가 닫힙니다. 이는 Git의 옵션 해석이며 임의의 셸 명령 실행이 아닙니다.[2]

핵심 개념 및 용어

MCP 서버
Model Context Protocol을 통해 AI 애플리케이션에 도구를 제공하는 로컬 프로세스입니다. 도구 인자는 신뢰할 수 없는 데이터로 서버에 전달됩니다.
인자 인젝션 (CWE-88)
명령줄 프로그램이 신뢰할 수 없는 입력을 옵션이나 구분자로 해석하는 문제입니다. 셸 문자열 대신 인자 배열을 사용해도 발생할 수 있습니다.[2], [4]
Git 참조
main 또는 HEAD~1처럼 커밋이나 트리를 가리키는 이름 또는 표현식입니다. -로 시작하는 값은 옵션으로 해석될 수 있습니다.[2], [3]
Workspace 격리
도구의 파일 작업을 선택한 프로젝트 디렉터리 안에 두는 경계입니다. 입력이 하위 프로세스 명령의 의미를 바꾸면 이 경계는 불완전합니다.[1], [3]

프레임워크 매핑

근본 원인 분석 (Root Cause)

AWS는 diff scan 작업의 조건부 인자 인젝션을 설명합니다. 스캔에 전달된 참조가 Git 리비전이 아니라 명령줄 옵션으로 해석될 수 있었습니다. 업스트림 PR은 start_diff_scan이 base_ref를 git diff <base_ref> --와 git archive에 전달했으며, 빈 값이나 하이픈으로 시작하는 값이 잘못 해석될 수 있음을 확인합니다. 이는 셸 메타문자 인젝션이 아닙니다. 인자 배열은 셸 파싱을 막지만 호출된 프로그램의 옵션 파싱은 막지 않습니다. AWS에 따르면 프로세스 OS 권한 범위에서 의도한 workspace 밖의 파일을 만들거나 덮어쓰거나 잘라낼 수 있었습니다. 병합된 수정은 Git 호출 전 base_ref를 검증하고 빈 값 또는 공백 제거 후 -로 시작하는 값을 거부합니다. 테스트는 거부된 입력에서 하위 프로세스나 업로드가 발생하지 않음을 확인합니다. 영향 버전은 >=0.1.1 및 <0.2.0이며 0.2.0에서 수정되었습니다. CVE 레코드는 CVSS 4.0 6.9 Medium을 기록하고 GitHub Advisory는 CVSS 3.1 8.2 High도 표시합니다. 여기서는 익스플로잇 페이로드를 재현하지 않습니다.[1], [2], [3], [4]

단계별 공격 실행 흐름

단계 1

에이전트가 diff scan 도구를 호출

로컬 MCP 서버는 호출자가 영향을 줄 수 있는 base_ref를 받습니다. 신뢰할 수 없는 저장소, 콘텐츠 또는 사용자가 이 값을 결정할 수 있는 흐름에서 위험이 생깁니다. 프롬프트 인젝션만으로 이 코드 경로에 자동 진입하는 것은 아닙니다.[2]

단계 2

값이 위치 인자로 Git에 전달

영향받는 코드는 해당 참조를 Git diff 및 archive 명령으로 전달합니다. Python이 셸을 사용하지 않아도 앞에 붙은 하이픈을 Git이 옵션으로 해석할 수 있습니다.[2], [3]

단계 3

Git의 옵션 파싱이 예상 경계를 벗어남

상황에 맞는 옵션이 workspace 밖으로 쓰기를 유도할 수 있습니다. 공개된 영향은 프로세스가 쓸 수 있는 파일의 생성, 덮어쓰기 또는 절단이며 범위는 권한과 흐름에 달려 있습니다.[1], [3]

단계 4

부작용 전에 위험한 참조를 거부

0.2.0은 Git, S3 업로드 또는 Agent Space 확인 전에 base_ref를 검증합니다. 업데이트하고 MCP 프로세스를 최소 권한과 격리 환경에서 실행하세요.[1], [3], [6]

경계 흐름: 리비전 문자열과 Git 옵션

개념적 데이터 흐름이며 명령 시퀀스나 exploit 재현이 아닙니다.

두 파서, 서로 다른 두 경계

셸 파싱
인자 배열은 셸이 값을 셸 문법으로 해석하지 못하게 하여 이 경계를 닫습니다.[3]
Git 옵션 파싱
Git은 자체 명령줄 문법을 계속 해석합니다. 인자 배열은 호출자가 영향을 줄 수 있는 ref가 옵션으로 해석되는 것을 막지 못하므로 Git을 실행하기 전에 검증해야 합니다.[2], [3]
1

호출자가 리비전에 영향을 줌

diff scan 도구는 워크플로에서 base_ref를 받습니다. 신뢰할 수 없는 입력이 이 값을 바꿀 수 있을 때만 위험이 생깁니다.[2], [3]

2

인자 배열도 Git 파서에는 전달됨

Python은 각 값을 따로 전달해 셸 파싱을 피할 수 있지만, Git은 자체 명령줄 옵션을 계속 해석합니다.[3], [2]

3

workspace 경계 가정이 깨질 수 있음

Git이 값을 옵션으로 처리하면 파일 출력이 의도한 workspace 밖으로 나갈 수 있으며, 범위는 MCP 프로세스의 OS 권한으로 제한됩니다.[1], [2]

4

검증이 입력 경계를 닫음

0.2.0은 Git 실행이나 후속 부작용 전에 빈 ref와 옵션처럼 보이는 ref를 거부합니다. 호출자 입력이 Git 옵션 동작을 더 이상 선택하지 못하지만, 유효한 ref는 요청한 리비전을 계속 선택합니다.[3], [6]

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

업스트림 호출 경계에 초점을 둔 비교이며 scanner 전체 사본은 아닙니다. 병합된 변경은 Git 실행 전에 참조를 확인하고, 테스트는 빈 값과 하이픈 시작 값에서 하위 프로세스와 업로드가 없음을 검사합니다. 인자 배열은 셸 파싱을 막지만 Git의 옵션 해석은 막지 않습니다. 이 발췌문은 git diff 호출만 보여 줍니다. git archive를 포함해 base_ref를 사용하는 모든 곳에서 같은 검증을 적용해야 합니다.[3]

취약한 구현
def start_diff_scan(path: str, base_ref: str):
    # 옵션처럼 보이는 ref 값이 검증 전에 Git에 전달됩니다.
    return subprocess.run(
        ["git", "diff", base_ref, "--"],
        cwd=path,
        check=False,
    )
보안 강화 패치
def _validate_git_ref(base_ref: str) -> None:
    if not base_ref or not base_ref.strip():
        raise ValueError("base_ref must not be empty.")
    if base_ref.strip().startswith("-"):
        raise ValueError("base_ref must not start with '-'.")

def start_diff_scan(path: str, base_ref: str):
    _validate_git_ref(base_ref)  # 하위 프로세스나 업로드를 시작하기 전에 거부합니다.
    return subprocess.run(
        ["git", "diff", base_ref, "--"],
        cwd=path,
        check=False,
    )

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

출처