주요 내용
- 빌드 도구는 애플리케이션 런타임 코드로 배포되지 않더라도 운영상의 위험을 초래할 수 있습니다.
- webpack은 LTS 브랜치를 공개하지 않으며, 수정 사항은 이전 마이너 버전 대신 활성 5.x 계열에 반영됩니다.
- 빌드 시 코드는 빌드 프로세스가 접근할 수 있는 모든 소스, 자격 증명 및 토큰을 사용하여 실행됩니다.
- 동일한 취약점이 있는 Webpack으로 다시 빌드해도 아무것도 바뀌지 않습니다. 왜냐하면 이 결함이 매번 다시 발생하기 때문입니다.
대부분의 취약점 관리 프로그램은 빌드 체인을 묵묵히 제외합니다. 빌드 체인은 devDependencies에 포함되어 있고, 프로덕션 호스트에서는 절대 실행되지 않으며, 스캔 보고서에 나타나더라도 그저 어깨를 으쓱하며 처리 대기열 맨 아래로 밀려나기 일쑤입니다. 의존성이 프로덕션 환경에 절대 도달하지 않는다면 이러한 논리는 타당해 보입니다. 하지만 웹팩의 경우, 두 가지 구체적인 측면에서 이 논리가 성립하지 않습니다.
이 글에서는 웹팩(Webpack)의 지원 모델이 실제로 무엇인지, 고정된 5.x 마이너 버전이 실제로는 지원되지 않는 코드인 이유, 그리고 매 릴리스마다 작업을 지연시키지 않으면서도 빌드 체인을 공격 표면으로 간주하여 다루는 방법에 대해 다룹니다.
빌드가 여전히 성공하므로 아무도 건드리지 않는다
구형 저장소에 있는 웹팩 구성은 여전히 잘 작동하기 때문에 건드려서는 안 되는 것으로 여겨지며, 아무도 이를 망가뜨리는 사람이 되고 싶어 하지 않습니다. 안정적인 빌드 시스템은 회사 내에서 가장 오래된 소프트웨어가 되기 마련인데, 아무도 그걸 다시 살펴볼 필요성을 느끼지 못하기 때문입니다.
그러면 우선순위 결정 회의가 열립니다. 스캐너가 웹팩(Webpack)의 CVE를 탐지하면, 누군가가 이를 대충 훑어보고 “이건 빌드 시에만 발생하는 문제야”라고 말하며, 해당 티켓은 실제 운영상 위험이 있다고 여겨지는 모든 항목 뒤로 밀려나게 됩니다. 이 논리는 타당해 보이지만, 두 가지 측면에서 모두 틀렸습니다.
첫 번째 실수는 웹팩의 출력물을 번들러 자체와 별개의 것으로 취급하는 것입니다. 웹팩은 번들에 자체 런타임 코드를 삽입하기 때문에, 해당 런타임에 결함이 있으면 배포하는 애플리케이션에도 결함이 생기게 됩니다.
두 번째는 빌드 도구가 오직 빌드 시에만 접근 가능하다고 가정하는 것입니다. 개발 서버에는 이를 운영하는 엔지니어를 직접 겨냥한 고유한 유형의 취약점이 존재합니다. 그리고 더 근본적인 문제는 devDependencies를 애초에 위험 등급으로 취급하는 것 자체입니다. 이는 패키징 라벨일 뿐, 보안 경계가 아닙니다. 번들러가 이를 유난히 뚜렷하게 드러내는 것뿐인데, 이는 번들러가 생성한 결과물 중 일부가 결국 프로덕션 환경에 반영되기 때문입니다.
webpack 4는 개발이 완료되었으며, webpack 5에는 LTS 버전이 없습니다.
webpack은 LTS 일정, 지원 매트릭스, 또는 지원 종료 일정을 공개하지 않습니다. 버그 수정 사항은 유지 관리 중인 구버전 브랜치보다는 활발히 개발 중인 5.x 계열에 반영되므로, 특정 마이너 버전을 고정해 두었다가도 업스트림에서 버그가 수정되는 순간 해당 버전이 뒤처질 수 있습니다.
webpack 4는 2018년 2월에 출시되었고, webpack 5는 2020년 10월에 등장했으며, 4.x 계열은 2023년 9월 4.47.0을 끝으로 종료되었습니다. 4에서 5로의 마이그레이션에는 생태계 전체적으로 수년이 걸렸으며, 많은 팀이 이를 끝내지 못했습니다. 아직 4를 사용 중이라면, 업스트림에서 어떤 수정 사항도 적용받지 못하는 코드를 실행하고 있는 것입니다.
webpack 5는 더 안정적이지만, 이는 최신 버전에만 해당됩니다. 현재 릴리스 버전은 2026년 9월에 출시된 5.110.3이며, 아래의 두 가지 수정 사항은 실질적인 문제를 보여줍니다. 왜냐하면 이 수정 사항들은 문제가 있는 이전 마이너 버전에 백포트된 것이 아니라, 각각 더 새로운 5.x 릴리스에 포함되어 나왔기 때문입니다. 이 프로젝트의 2026년 로드맵 네이티브 CSS 처리 기능, 범용 컴파일 대상, 로더가 필요 없는 TypeScript, 그리고 Webpack 6을 위한 기반을 마련했으며, 이 모든 분야에서 릴리스 일정이 빠르게 진행되어 왔습니다. 5.107 버전에서는 실험적인 TypeScript 지원이 추가되었고, 5.110 버전에서는 다음 기능이 더 이상 사용되지 않게 되었습니다. css-loader, style-loader, 그리고 mini-css-extract-plugin 웹팩의 내장 CSS 지원 기능을 선호하기 때문입니다. 다시 말해, 업스트림의 패치된 버전 역시 여러분이 사용하는 동안 계속해서 변경되고 있는 것입니다.
알고 계셨나요? “webpack 5를 사용 중”이라고 해서 패치 상태가 어떤지 거의 알 수 없습니다. 5.76.1 버전으로 고정된 저장소는, 비록 webpack 5가 여전히 해당 프로젝트의 최신 메이저 릴리스이긴 하지만, 현재 패치된 버전 라인보다 30개 이상의 마이너 릴리스가 뒤처져 있습니다.
“지원되는 메이저 버전”과 “패치된 버전” 사이의 그 간극이 바로 감사 과정에서 문제가 되는 부분입니다. 파이프라인이 인증된 상태라 툴체인을 변경하면 전체를 다시 인증 절차를 거쳐야 하기 때문에, 은행의 프론트엔드가 특정 5.x 마이너 버전에 고정되어 있는 상황을 상상해 보십시오. 번들러를 변경하려면 해당 절차를 다시 수행해야 하므로 고정 상태는 유지되고, 지원되지 않는 코드도 그대로 남게 됩니다. 바로 이러한 상황을 위해 확장 지원이 마련된 것으로, 팀이 쉽게 벗어나기 어려운 브랜치에서도 패치를 계속 적용할 수 있게 해줍니다.
일부 번들러 버그가 브라우저에 반영되기도 합니다
일부 웹팩 취약점은 빌드 단계에서 전혀 발생하지 않습니다. 이러한 취약점은 웹팩이 번들에 기록하는 코드 내에 존재하기 때문에, 이 번들러는 단순한 빌드 시간 점검 항목에 그치지 않고 프로덕션 환경의 공격 표면에 포함되어야 합니다.
43788 다음은 깔끔한 예시입니다. 이는 webpack의 AutoPublicPathRuntimeModule, 그리고 다음의 경우에 적용됩니다. output.publicPath 설정되어 있지 않거나 다음으로 설정되어 있습니다. auto. 업스트림 보안 권고문에 따르면 5.93.0 이전 버전은 취약점이 있는 것으로, 5.94.0 이후 버전은 패치된 것으로 명시되어 있으며, NVD는 이 취약점에 대해 6.4의 ‘중간(Medium)’ 등급을 부여했습니다. 알아두면 좋은 점은 auto 아무도 설정하지 않을 경우, 웹 및 웹 워커 대상에 대한 실질적인 기본값은 publicPath, 따라서 이것은 그리 특이한 구성이 아닙니다.
‘Medium’ 등급은 실제 운영 상황을 과소평가하고 있습니다. 이 보안 권고문은 Canvas LMS에서 실제 악용 사례가 발생했다고 보고하고 있으며, 취약한 코드는 CI 러너에 국한되지 않고 번들에 포함되어 생성됩니다. 하지만 악용이 자동으로 이루어지는 것은 아닙니다. 웹팩으로 생성된 파일이 포함되어 있고, 공격자가 충분히 정제되지 않은 스크립트 없는 HTML을 삽입할 수 있는 페이지가 있어야만 악용이 가능합니다. name 또는 id 속성들입니다. 이러한 조건들이 모두 충족될 경우, 해당 가젯은 스크립트가 어디에서 로드되는지에 영향을 미칠 수 있으며, 이는 빌드 도구에 의해 생성되어 사용자의 브라우저에서 실행되는 크로스사이트 스크립팅 경로가 됩니다.
28154 이 점이 유용한 대조를 이룬다. 왜냐하면 이 문제는 빌드 단계를 벗어나지 않기 때문이다. 이는 ImportParserPlugin 웹팩 5.76.0 이전 버전에 영향을 미치는 ‘매직 코멘트’ 처리 취약점입니다. 컴파일 과정에서, 관련 신뢰할 수 없는 객체에 영향을 미칠 수 있는 공격자는 웹팩이 호스트 영역의 전역 객체에 접근하도록 유도할 수 있습니다. NVD는 이 취약점에 9.8점을 부여하며 ‘Critical’ 등급으로 분류한 반면, 레드햇은 동일한 취약점에 9.1점을 부여했습니다.
동일한 취약점이 있는 webpack을 사용하여 다시 빌드하는 것은 서로 다른 이유로 두 문제 모두 해결에 도움이 되지 않습니다. CVE-2024-43788의 원인이 되는 런타임 코드는 webpack 자체에 패치가 적용될 때까지 모든 번들에 재삽입되며, CVE-2023-28154는 webpack 자체의 주석 파싱 기능에 존재하기 때문에 해당 버전이 컴파일을 수행하는 한 계속 남아 있게 됩니다. 두 수정 사항 모두 수년 전부터 업스트림에서 제공되어 왔습니다.
주의하세요: 누군가 심각도 점수에 대해 이의를 제기하기 전에, 먼저 버전과 구성 설정을 확인해 보세요. 이 보안 권고문에는 5.93.0 이전 버전의 webpack이 취약한 것으로, 5.94.0 이후 버전은 패치된 것으로 명시되어 있으므로, 5.94.0 미만의 버전은 모두 점검이 필요하며, output.publicPath 설정되지 않음 또는 켜짐 auto 이것이 해당 런타임을 번들에 포함시키는 과정입니다. 그런 다음, 애플리케이션에서 사용자가 검증되지 않은 HTML을 삽입할 수 있는지 확인하십시오. name 또는 id 속성들, 왜냐하면 이러한 조건들이 악용 가능성의 핵심이기 때문이다.
개발 의존성이 반드시 위험이 낮다는 뜻은 아닙니다
빌드 단계에서만 발생하는 취약점조차도 그 위험성이 결코 낮지 않습니다. 빌드 단계의 코드가 접근할 수 있는 범위가 넓기 때문입니다. 번들러는 빌드 프로세스에서 사용할 수 있는 모든 자원을 활용하여 실행되는데, 여기에는 대개 소스 코드, 환경 변수, 인증 정보, 그리고 많은 파이프라인에서 사용되는 게시 토큰이 포함됩니다. 이는 공격자에게 매력적인 표적이 됩니다.
30359 그리고 이와 관련된 30360 두 문제 모두 webpack-dev-server의 소스 코드 유출로 이어지지만, 5.2.1 버전에서 수정되었으며, 그 원인은 서로 다릅니다. 첫 번째 문제는 <script> 태그는 동일 출처 정책의 적용을 받지 않으므로, 악의적인 페이지가 실행 중인 개발 서버에서 번들을 가져와 약간의 프로토타입 오염을 통해 소스를 다시 읽어낼 수 있습니다. __webpack_modules__ ~를 사용하여 Function::toString. 두 번째는 크로스사이트 WebSocket 하이재킹으로, 오리진 검사(Origin check)가 IP 주소 기반 오리진을 허용함으로써 크롬ium 기반이 아닌 브라우저를 사용하는 개발자들이 노출되는 문제이며, 이는 5.2.0 버전까지의 릴리스에 영향을 미칩니다.
지금 더 중요한 점은 5.2.1 버전이 끝이 아니었다는 사실입니다. 그 수정 사항은 Sec-Fetch-Mode 그리고 Sec-Fetch-Site 브라우저가 잠재적으로 신뢰할 수 있는 출처에 대해서만 전송하는 헤더들이기 때문에, 일반 HTTP를 통해 접속할 경우 해당 헤더가 포함되지 않아 검사가 완전히 생략됩니다. 이 우회 취약점(CVE-2026-6402)은 5.2.3 버전까지의 webpack-dev-server에 영향을 미치며, 5.2.4 버전에서는 다음을 설정하여 이 문제를 해결했습니다. Cross-Origin-Resource-Policy: same-origin. 개발 서버를 HTTPS를 통해 제공하는 것은 업그레이드를 대체하는 것이 아니라, 문서화된 임시 해결책입니다. 이후 5.2.5 버전에서는 CVE-2026-9595 취약점이 수정되었는데, 이 취약점은 광범위한 권한을 가진 사용자 프록시가 ws: true 개발 서버 자체의 HMR 웹소켓을 가로채어 쿠키와 Origin 헤더를 포함한 채 프록시 대상 서버로 전달했습니다. 그 후, 5.2.6 버전에서는 내부 open-editor 및 invalidate 엔드포인트를 통한 크로스사이트 요청 위조(CSRF) 취약점을 수정했으며, 잘못된 형식의 Host 또는 Origin 헤더로 인해 발생하는 서비스 거부(DoS) 문제도 해결했습니다. 이후 패키지 자체는 6.0.0 버전으로 업데이트되었습니다. 이러한 일련의 수정 사항들은 개발 서버에서 발견된 문제들을 단순한 ‘배경 잡음’으로 치부해서는 안 된다는 충분한 근거가 됩니다.
이 취약점으로 인해 누가 위험에 노출되는지 생각해 보십시오. CVE-2025-30359에 대해 공개된 공격 사례에는 localhost의 개발 서버에서 번들을 요청하는 악성 페이지가 포함되어 있으므로, 개발 서버를 실행한 상태에서 웹을 탐색하는 개발자만으로도 공격에 노출될 수 있습니다. 공격자는 포트 번호와 출력 엔트리포인트 경로가 필요하며, 이 두 가지 모두 기본값으로 설정되어 있는 경우가 많습니다. 이는 귀하가 통제하지 않는 컴퓨터를 사용하는 계약직 직원이나, 웹 서핑을 하는 동안 하루 종일 개발 서버를 켜 놓는 모든 사람을 포함하며, 이러한 취약점은 생산 환경에 초점을 맞춘 스캔에서는 전혀 탐지되지 않습니다.
현장의 목소리: 누군가가 설정한다 host 에 0.0.0.0 휴대폰에서 테스트하다가 다시 원래대로 되돌리는 것을 깜빡하는 경우입니다. 이 한 번의 수정으로 로컬호스트 전용 도구가 네트워크를 수신 대기하는 도구로 바뀌게 되는데, 이는 잘못된 헤더를 이용한 서비스 거부 공격과 같이 네트워크 접근이 필요한 버그의 경우 중요한 문제입니다. 하지만 이것이 크로스 오리진 소스 도용을 유발하는 원인은 아닙니다. 해당 기능은 로컬호스트에 대해서는 정상적으로 작동합니다.
따라서 선별 기준은 결코 ‘localhost 대 그 외 모든 경우’의 문제가 아니었습니다. 핵심은 현재 사용 중인 정확한 버전, 개발자가 브라우징하는 동안 개발 서버를 계속 가동하는지 여부, 일반 HTTP를 통해 서비스를 제공하는지 여부, 그리고 포트 번호와 출력 경로가 얼마나 쉽게 추측될 수 있는지에 달려 있습니다.
기본 설정을 적용한 5.2.3 버전을 사용하는 시스템은 바인드 주소가 무엇이든 상관없이 실제 취약점이 존재합니다. HTTPS는 CVE-2026-6402에서 발생하는 소스 노출 경로를 완화해 주지만, 그 이후에 발표된 보안 권고 사항을 무효화하지는 않으므로 5.2.4 버전이 일반적인 안전 기준이 될 수는 없습니다. 5.x 버전의 수정 사항은 5.2.6까지 이어지며, 해당되는 각 보안 권고 사항은 일괄적인 판단이 아닌 개별적인 검토가 필요합니다.
'hidden migration'의 규모는 webpack보다 더 큽니다.
이러한 핀이 계속 유지되는 이유는 게으름 때문이 아닙니다. 성숙한 웹팩 환경을 이전하는 것은 그 자체로 하나의 본격적인 프로젝트이며, 팀들이 현 상태를 고수하는 데에는 타당한 이유가 있습니다. 그 이유는 맞춤형 로더와 플러그인, 그 위에 구축된 프레임워크 전용 빌드 시스템, 수년간의 패치를 통해 축적된 구성, 출력 결과에 민감한 캐싱, CI에 여전히 남아 있는 지원되지 않는 Node 버전, 그리고 아무도 완전히 이해하지 못하는 파이프라인을 변경하는 것에 대한 단순한 두려움 등이 있습니다.
대규모 업데이트 역시 상황을 그냥 내버려 두지 않습니다. 이는 청킹, 모듈 해결, 폴리필 동작, 에셋 처리, 그리고 출력 형식을 변경할 수 있습니다. 즉, 빌드 프로세스와 그 결과로 생성된 애플리케이션 모두를 검증해야 하므로, 테스트 계획이 하나가 아닌 두 개가 필요하게 됩니다.
유용한 방법은 “webpack”을 단일 항목으로 취급하는 것을 중단하고, 각 구성 요소가 실제로 실행되는 위치에 따라 구분하는 것입니다. 이것이 바로 Vulnerability Exploitability eXchange(VEX) 문서가 전달하고자 하는 ‘악용 가능성 맥락’으로, CI 러너상의 로더와 배포된 번들 내의 런타임 코드가 서로 다른 위험 요소를 지닌다는 점을 기록하는 것입니다.
| 구성 요소 | 어디서 실행되는지 | 생산량에 도달하다 | 트라이아지 우선순위 |
|---|---|---|---|
| webpack으로 생성된 런타임 코드 | 빌드한 다음, 브라우저에서 실행 | 네, 문제가 있는 런타임 모듈이 번들에 포함되어 있을 때 | 높음 |
| webpack-dev-server | 개발자용 컴퓨터와, 외부로 노출된 경우의 로컬 네트워크 | 아니요 | 버전 및 구성에 따라 다르며, 관련 권고 사항이 있는 릴리스에서 가장 높음 |
| 로더와 플러그인 | CI 또는 개발 환경에서의 빌드 시간 | 때로는 로더에 따라 다릅니다. | 사안별로 |
| 전이가 가능한 빌드 유틸리티 | 빌드 시간 | 드물게 | 접근 가능한 경우가 아니면 낮음 |
레거시 빌드를 위한 의사결정 프레임워크
5.x 내에서 앞으로 나아가기
설정 내용이 문서화되어 있고 관련 종속성이 유지 관리되고 있다면, 현재 5.x 릴리스로 업데이트하세요. 이것이 가장 비용 효율적인 방법이며, 패치 공급도 정상화할 수 있습니다. 다음 분기로 미루지 말고 이번 스프린트 내에 처리하세요.
파이프라인을 재구축합니다
만약 기존의 복잡한 구조가 그 가치를 상실했다면, Rspack, Vite, esbuild를 모두 진지하게 고려해 볼 만합니다. 다만 그에 따르는 비용을 솔직하게 인정해야 합니다. 이 도구들은 더 빠르긴 하지만, 맞춤형 로더나 모듈 페더레이션(Module Federation), 세심한 코드 분할 등을 통해 이미 잘 정립된 구성 파일을 다시 작성하는 것은, 사용자에게는 눈에 띄는 결과가 전혀 없는 본격적인 프로젝트가 될 수 있습니다.
고정된 버전에 패치를 적용하고 마이그레이션 범위를 최소화하세요
파이프라인이 인증을 받았다면, 올해는 번들러를 교체하지 않을 것입니다. 바로 이럴 때 확장 지원의 진가가 드러납니다. 긴급하게 대응할 필요 없이 자신의 일정에 맞춰 더 큰 변화를 계획하는 동안, 고정된 브랜치를 패치된 상태로 유지해 주기 때문입니다. TuxCare의 ‘Endless Lifecycle Support’는 webpack 5.50.0, 5.55.0, 5.76.1, 5.88.2, 5.94.0은 물론, npm을 통해 제공되는 webpack-dev-server 2.7.1부터 5.2.2까지의 릴리스를 지원합니다.
하지만 백포트가 무엇을 보존하는지에 대해서는 명확히 파악해야 합니다. 백포트는 웹팩 버전, 구성 설정, API 표면을 그대로 유지하므로, 전체 툴체인 마이그레이션에 비해 재인증 범위를 훨씬 좁게 유지할 수 있습니다. 다만, 생성된 런타임 코드를 수정하는 것은 결국 생성된 런타임 코드를 변경하는 것을 의미하므로, 출력된 번들의 바이트 단위를 완전히 동일하게 유지하는 것은 불가능합니다.
TuxCare의 확장된 Webpack 지원 접근 방식
빌드 도구에 대한 확장 지원은 단순히 구버전을 유지 관리하는 것 이상의 의미를 지닙니다. 진정한 작업은 세부 사항에 있으며, 그 대부분은 사내 팀이 매달 반복해 수행하기 어려운 종류의 일입니다.
먼저 웹팩과 이에 포함된 전이적 종속성을 모니터링한 다음, 공개된 문제가 단순히 발표된 버전 범위에만 의존하는 것이 아니라 실제로 레거시 브랜치에 영향을 미치는지 여부를 평가합니다. EOL(지원 종료) 상태와 전이적 종속성 위험을 고려한 이러한 상황 인식적 관점을 통해 팀은 스캔 보고서의 모든 항목을 일일이 검토하는 대신, 실제 위험에 우선순위를 둘 수 있습니다.
이 과정을 통해, 후속 릴리스에 포함된 아키텍처 변경 사항을 반영하지 않은 채 수정 사항만 역포트됩니다. 패치된 각 릴리스는 호환성과 회귀 현상에 대한 검증을 거쳐, 기존 빌드 파이프라인이 계속 작동하도록 보장합니다. 이는 일반적으로 인증된 스택에 패치를 적용하는 데 있어 가장 큰 걸림돌이 되는 부분입니다. TuxCare는 업스트림 webpack을 대체하려는 것이 아닙니다. TuxCare의 역할은 프로젝트가 이미 넘어간 버전들에 대한 장기적인 관리이며, 여기에는 실제 운영 시스템에 필요한 회귀 테스트와 호환성 작업이 포함됩니다. 모든 패치된 릴리스에는 소프트웨어 자재 명세서(SBOM)와 VEX 문서가 함께 제공되며, 아티팩트에는 TuxCare 자체 레지스트리에서 발급된 분리된 GPG 서명이 포함됩니다.
OpenJS와 핵심 툴의 긴 수명
webpack은 OpenJS Impact 프로젝트이며, OpenJS 생태계 지속 가능성 프로그램( ESP)은 아카이브된 버전, 지원 종료(EOL) 버전 및 구버전에 대한 상용 보안 지원을 제공함으로써, 수익의 일부가 해당 프로젝트와 재단에 환원되도록 마련되었습니다. TuxCare는 골드 멤버이자 ESP 파트너이며, 이 프로그램은 비독점적이므로 유지보수자는 원하는 버전을 자유롭게 지원할 수 있습니다.
빌드 파이프라인은 고객이 결코 볼 수 없더라도 제품의 일부입니다. 레거시 빌드 역시 다른 모든 곳에서 이미 실행하고 있는 라이프사이클 계획에서 영구적으로 제외되는 것이 아니라, 이를 통해 생성되는 애플리케이션과 동일한 라이프사이클 계획을 적용받아야 합니다.
