GitLab Security Incident: Attempted Exploitation of CVE-2026-97229
GitLab 보안 사고: CVE-2026-97229 악용 시도
Alpine Linux는 GitLab의 Ruby 정규식 취약점을 노린 공격이 서버 코드 실행에 성공했는지 배제할 수 없어 인스턴스를 폐기하고 재구축했습니다. 저장소와 패키지, 릴리스 변조 흔적은 찾지 못했으며, 자체 Ruby나 컨테이너 이미지를 쓰는 운영자는 GitLab 버전뿐 아니라 Ruby 패치 적용 여부도 확인해야 합니다.
- 주제
에디터 노트
가장 실질적인 쟁점은 GitLab 버전만 올려서는 취약점을 닫지 못했다는 점입니다. Alpine이 자체 이미지에 표준 Ruby를 넣은 탓에 GitLab 19.3.6 업그레이드도 부족했고, Ruby 패치가 든 이미지를 다시 받아야 했습니다. 공식 이미지와 배포판 패키지를 쓰면 이 경로가 단순해지지만, 버전 고정이나 자체 빌드 환경에서는 구성 요소별 패치 확인이 필요하다는 댓글의 지적이 이번 사례와 맞닿습니다. Alpine은 침해를 확인한 것이 아니라 성공 가능성을 배제하지 못해 재구축을 택했습니다. 공격 로그 일부와 외부 연결 기록이 없다는 조건을 밝히면서도, 저장소 커밋을 외부 개발자 복제본과 45개 빌더에 대조해 패키지 변조 여부를 따로 확인했습니다. Hacker News에서는 이 대응을 투명하다고 보는 반응과 패치 추적 부담을 지적하는 반응이 함께 나왔습니다. Rust의 메모리 안전성이 이번 유형의 악용을 막을 수 있다는 댓글도 있었지만, 이는 댓글의 일반론이며 Alpine의 조사 결과와는 구분됩니다.
AI 요약
Alpine Linux는 10월 20일과 21일 GitLab 인스턴스에 CVSS 10.0 취약점 CVE-2026-97229를 이용한 공격이 들어왔다고 밝혔습니다. 공격자는 신규 계정을 만들어 조작한 CI 설정을 전송했고, GitLab 작업자 프로세스를 8차례 중단시켰습니다. 그중 네 차례는 공격이 다음 단계에 이르기 전에 실패했습니다. 공격자는 Alpine이 사용한 GitLab 컨테이너 이미지도 내려받았습니다. Alpine은 공격자가 실제로 서버에서 코드를 실행했다는 증거를 찾지 못했지만 성공 가능성을 배제하지 못해 인스턴스를 침해된 것으로 간주했습니다.
취약점과 패치
CVE-2026-97229는 GitLab이 CI 설정의 정규식을 평가하는 과정에서 발생합니다. 근본 원인은 Ruby에 포함된 정규식 엔진 Onigmo의 취약점입니다. GitLab은 10월 12일 수정판을 냈지만, 수정은 GitLab 자체 코드가 아니라 공식 패키지와 컨테이너 이미지에 포함된 Ruby 패치였습니다. Ruby는 10월 23일 3.3.13, 3.4.12, 4.0.9에서 수정 사항을 배포했습니다.
Alpine은 10월 22일 GitLab을 19.3.6으로 올렸지만 취약점은 남았습니다. 사용 중인 이미지가 GitLab이 자체 패치한 Ruby 대신 표준 Ruby를 포함했기 때문입니다. 소스에서 빌드하거나 자체 컨테이너 이미지를 만드는 운영자는 GitLab만 올려서는 충분하지 않습니다. Ruby 3.3.13, 3.4.12, 4.0.9 이상도 사용해야 합니다. Alpine의 alpinelinux/gitlab 이미지는 10월 27일 공개된 19.3.6에 Ruby 3.3.13을 담았습니다. 그 전에 받은 19.3.6 이미지와 이전 태그는 취약합니다.
조사 결과와 대응
Alpine은 GitLab을 외부에 공개하지 않고 인스턴스를 처음부터 다시 구축했습니다. 모든 비밀번호를 초기화하고 GitLab 비밀 키도 교체했습니다. 재개 후 사용자는 로그인 화면의 비밀번호 찾기를 통해 새 비밀번호를 설정해야 합니다. 같은 비밀번호를 다른 곳에서도 썼다면 해당 계정 비밀번호도 바꾸라고 안내했습니다. GitLab은 재개 전 테스트를 진행 중이며 패키지 미러, cgit, 메일링 리스트와 IRC는 계속 운영됩니다.
Alpine은 aports 저장소와 패키지, 10월 21일 릴리스에서 변조 흔적을 찾지 못했습니다. 10월 20일부터 22일까지 추가된 저장소 커밋을 GitLab 외부의 개발자 복제본과 45개 빌더 기록에 대조했습니다. 10월 20일부터 24일까지 모든 아키텍처에서 빌드한 패키지도 확인했습니다. 10월 21일 Alpine 3.21.9, 3.22.7, 3.23.7, 3.24.3 릴리스와 ISO, minirootfs 역시 검증한 커밋으로 만들어졌다고 밝혔습니다. 패키지와 릴리스 서명 키는 GitLab 서버에 보관하지 않아 노출되지 않았습니다. 다만 10월 24일까지의 검증을 10월 27일 GitLab 폐쇄 시점까지 연장하고 있습니다.
공격자가 코드를 실행했다는 흔적은 없었고, 타이밍 검사에서 지연이 나타나지 않았습니다. 예상하지 못한 파일, 키, 훅, 프로세스도 발견하지 못했습니다. 확인 가능한 웹이나 API 요청으로 비공개 데이터가 유출된 정황도 없었습니다. 하지만 성공한 공격은 충돌이나 웹 로그 흔적을 남기지 않을 수 있고, 공격 당일 일부 백그라운드 작업 로그와 구 컨테이너 파일시스템은 남아 있지 않습니다. 외부 네트워크 연결 로그도 수집하지 않았고 호스팅 업체에도 기록이 없습니다. 성공했을 경우 사용자 이메일, 이름, IP 주소, 비밀번호 해시, 2단계 인증 비밀값, CI/CD 변수와 러너 토큰, 웹훅 및 통합 자격 증명, 개인 액세스 토큰, 비공개 저장소와 비공개 이슈·병합 요청이 노출될 수 있었습니다.
Alpine은 앞으로 치명적인 GitLab 보안 업데이트를 하루 안에 적용하고, 자체 빌드에 필요한 Ruby 등 구성 요소의 패치를 매번 확인하겠다고 밝혔습니다. GitLab 호스트의 외부 연결과 데이터베이스 연결 로그를 남기고 보존 기간도 14일보다 늘립니다. GitLab과 별도로 릴리스를 검증할 수 있도록 서명된 릴리스 태그도 도입할 계획입니다. Alpine의 Ruby 패키지는 3.21에서 3.3.13, 3.22·3.23·3.24와 edge에서 3.4.12를 제공하며 apk upgrade로 수정판을 받을 수 있습니다.
Hacker News 반응
- @JLO64 — GitLab 19.3.6으로 올려도 취약점이 해결되지 않았다는 대목과, Ruby 정규식 엔진 결함이라 신뢰할 수 없는 입력으로 정규식을 만드는 모든 프로그램이 위험하다는 대목을 인용했습니다. 자체 빌드나 이미지를 쓰는 사람은 제공된 이미지를 자주 갱신하는 사람보다 이런 공격과 패치에 더 취약해 보인다고 했습니다. 최신 소식을 24시간 따라가는 것 말고는 좋은 해결책이 떠오르지 않아 지칠 것 같다고 덧붙였습니다.
- @esseph — 자동 빌드가 아니면 유지할 수 없습니다. 맞습니다, 계속 업그레이드해야 합니다.
- @Gigachad — Ruby 패치는 6일 전에 나왔습니다. 대부분의 Rails 앱은 패키지 관리자의 Ruby를 쓰지 않고 저장소에 버전을 고정합니다. 개발자가 Ruby가 나오는 즉시 버전 갱신 PR을 내지 않으면 안전하지 않습니다. 당연해 보일 수 있지만 Ruby 최신 버전을 출시 즉시 쓰는 Rails 앱은 거의 없습니다.
- @edoceo — PHP, Python, JS, Lua도 마찬가지겠죠? 누군가 오래된 Perl 취약점을 찾으면 어쩌죠.
- @edoceo — PHP2Shell은 수익성이 높으면서도 지치는 일이었습니다. 오래된 PHP 앱을 여러 개 관리합니다.
- @Gigachad — 이제 자체 호스팅한다면 모든 서비스를 VPN 뒤에 둬야 합니다. 자체 보안·개발팀이 있는 회사만 서비스를 공용 인터넷에 공개해야 합니다.
- @jamesfinlayson — 저는 대기업에 다니는데 자체 호스팅 도구는 VPN 같은 기술로만 접근할 수 있는 것 같습니다. 공개된 건 Jira, Confluence, SharePoint 정도입니다. Jira와 Confluence는 Atlassian의 자체 호스팅 가격 정책 때문인 것 같습니다.
- @Operyl — Atlassian의 Jira Server는 더 이상 지원되지 않고, 더 큰 기업용 제품도 2029년에 종료되므로 모두 클라우드로 옮겨가고 있습니다.
- @egeozcan — 많은 회사가 대안을 분위기 코딩하고 있습니다. 전문가는 아니지만 유럽 회사 대부분은 고객 데이터를 Atlassian 서버로 옮기는 게 불법일 수도 있습니다.
- @bombcar — SaaS가 이렇게 죽는군요. 분위기 코딩으로 죽습니다. 저도 한몫하고 있습니다.
- @griffiths — 유럽 회사 대부분에게 불법이라는 말에 관해 더 설명해 주실 수 있나요? Jira를 쓰는 EU 회사라 질문합니다.
- @awesome_dude — 자체 빌드나 이미지를 만드는 쪽과 공식 이미지를 받아 자주 갱신하는 쪽의 차이는 이번 사건에서 두드러졌지만 늘 있던 일입니다. Go 개발자로서 벤더링은 관리하고 유지해야 할 의존성 캐시를 만든다고 자주 말합니다. 의존성 버전을 고정하는 경우도 같은 어려움을 겪습니다. 공식 이미지를 쓰면 안 되냐고요? 공식 이미지도 늦을 수 있습니다. Linux 배포판의 Go 컴파일러 패키지는 대체로 너무 늦게 나와서 공식 Go 페이지를 지켜보라고 자주 말합니다.
- @weinzierl — 산업화 초기에 증기 보일러 사고가 많았습니다. 규제와 지금도 존재하는 조직들의 도움으로 통제했습니다. 지금처럼 취약점과 패치를 계속 쫓는 시대는 정상적이지 않고 계속될 수도 없습니다. 지금은 쫓고 쫓기는 일이지만 꼭 그래야 하는 건 아닙니다.
- @rconti — 15년 전만 해도 빌드와 배포 과정에서 인터넷의 아마도 믿을 만한 사이트에서 최신 버전을 그냥 받아 쓰는 건 완전히 미친 짓이라고 생각했습니다.
- @milkshakes — 2026년에 이런 대응은 정말 좋지 않아 보입니다. Ruby 공지에는 수정에 CVE 번호를 요청하지 않았다고 합니다. Ruby는 신뢰할 수 없는 입력으로 만든 정규식을 컴파일하고 쓰는 일을 안전하지 않다고 여겨 왔지만, 이전에도 정규식 컴파일의 double free를 충분히 조사한 뒤 취약점으로 처리한 사례가 있다고 인용했습니다.
- @couchand — 신뢰할 수 없는 입력을 정규식으로 컴파일하는 건 나쁜 생각입니다. 정규식은 프로그래밍 언어입니다. 신뢰할 수 없는 입력을 어떤 프로그래밍 언어로든 컴파일하는 건 나쁜 생각입니다. SQL 문자열을 이어 붙이지 말고 eval을 쓰지 말라는 것과 같은 이야기입니다.
- @0x1F8B — 소프트웨어 공장에서 토큰을 계속 써서 이 일을 자동화하는 미래가 다가옵니다. 연구소가 자기 제품 수요를 키우는 셈입니다.
- @Gigachad — 그건 당장의 문제입니다. 미래에는 인터넷에 노출되는 소프트웨어가 줄고, 네트워크에 노출되는 소프트웨어에서 안전하지 않은 언어를 없애며, Cloudflare 같은 서비스가 방화벽으로 공격을 탐지할 겁니다. 현재 활동 중인 봇과 주거용 프록시 IP 데이터베이스를 갱신해 IP를 차단하는 서비스도 생기겠죠. 지금의 스캔과 패치도 계속될 겁니다.
- @0x1F8B — 동의합니다. LLM이 사람이 처리할 수 있는 수준을 넘어 계측, 신호 수집, 감사를 확장하면 로그와 지표도 늘어날 겁니다. 그러면 토큰도 더 쓰고 Datadog 비용도 늘겠죠.
- @pixl97 — 거짓말을 기반으로 세계의 인프라를 만든 결과가 나타나기 시작했습니다. 지금과 다른 미래도 가능했습니다. 몇몇 정부가 비밀 예산으로 LLM을 개발해 전쟁 같은 큰 사건까지 숨겼다가 공개했다면 컴퓨터와 디지털 인프라 대부분이 갑자기 망가졌을 수도 있습니다. 적어도 지금은 보안이 다른 누군가의 문제라는 생각에 기대 세운 세계 인프라가 잘못됐다는 사실을 보고 고칠 시간이 있을지도 모릅니다.
- @jayd16 — 동적으로 연결되는 의존성, CI와 의미 버전을 인식하는 자동 의존성 추적, 개인 앱 저장소를 대상으로 한 자동 업데이트는 어떨까요?
- @cowlevel — 이 버그는 정규식 라이브러리 같은 무작위 C 데이터 처리 라이브러리의 정수 오버플로에서 원격 코드 실행으로 이어집니다. 이번 주만 해도 C 라이브러리에 지친 사람이 또 있나요?
- @Gigachad — 오래전부터 문제를 제기했지만 C를 잘 다루는 개발자라면 괜찮고 C 소프트웨어는 충분히 검증되어 안전하다는 말을 들었습니다. 이제 그 말이 틀렸다는 걸 보고 있습니다.
- @cristoperb — 이제 더 많이 검증됐네요!
- @grg0 — Rust가 어떻게 도움이 되나요? Rust에서 정수 오버플로는 디버그 빌드에서 패닉이 나지만 릴리스 빌드에서는 래핑되는 것으로 압니다. 코드 실행 부분을 막는 데 도움이 되나요?
- @jooops1 — Rust에서 정수 오버플로가 나더라도 안전한 Rust에서는 메모리 안전성을 깨뜨리지 않으므로 악용으로 이어지지 않는다는 점이 핵심입니다.
- @ferrisjoke — 농담은 많이 들었지만 프로그래밍도 게로 진화하고 싶어 할 줄은 몰랐습니다.
- @andrewinardeer — 연구자들이 Superbug나 MegaVuln 같은 말을 만들었나요? LLM이 모든 OS 버전과 장치에 존재하는 치명적이고 고칠 수 없는 취약점을 찾아 무책임하게 공개하고, 전 세계 관리자가 집단적 충격을 받고 핵심 인프라가 멈추며 사망자가 나오는 상황에 다가가는 것 같습니다.
- @Gigachad — Meltdown, Spectre, Rowhammer 같은 하드웨어 버그가 그런 사례였습니다. 하드웨어를 패치할 수 없어도 소프트웨어 차원의 완화책은 있었습니다. 저수준 구성 요소 대부분은 네트워크에 노출되지 않으므로 펌웨어 버그가 있어도 네트워크를 통해 접근하는 방법을 찾아야 합니다.
- @missmewiththatl — 우리 조직은 위험을 전혀 감수하지 않는 방침을 채택했습니다. PHP, Node, Python과 관련된 서비스를 제대로 검증할 때까지 여러 개 중단했습니다. 최근 내부 회의에서 공용 소프트웨어 시대가 끝난다고 농담했는데 단기적으로는 맞을지도 모르겠습니다.
- @fhn — 여러분의 Linux 배포판도 Perl과 Python을 기반으로 만들어집니다.
- @jtchang — 보안 사고를 훌륭하게 정리했습니다. 이런 사고에는 모르는 점이 생기기 마련인데 그 부분을 분명히 밝혔습니다. 공격이 성공했을 때 무엇이 유출될 수 있었는지를 설명한 점이 특히 좋았습니다. 어떤 해시를 썼는지도 포함할 수 있었을 것 같습니다.
- @stevepike — 지원이 끝난 Ruby 버전 중 어떤 버전이 영향을 받는지 확실히 아는 사람이 있나요? 네 버전 중 세 버전은 오래되어 보안 패치를 받지 못하는 것 같습니다. Ruby를 업데이트하세요. double free 문제인 CVE-2026-89078은 Ruby 3.3.11 이상에만 영향을 줄 수도 있습니다. Ruby 3.4와 4에서 도입된 버그가 3.3.11과 3.3.12에 실수로 백포트됐을 수 있기 때문입니다. 해당 취약점이 영향을 주는 모든 Ruby 버전은 패치를 받는 것 같습니다.
- @literallyroy — 제목이 상황을 축소하는 것 같습니다. 저는 Attempted를 읽고 공격이 실패했다고 생각했는데, 실제로는 성공했을 가능성도 완전히 있다는 뜻이었습니다.
원문: Alpine Linux / 번역·요약: Trawling