주요 내용
- lodash 4.17.21은 수년 동안 안전하다고 여겨졌던 엔드포인트가 더 이상 아니며, 현재 CVE-2025-13465, CVE-2026-2950, CVE-2026-4800 등 세 가지 확인된 취약점을 포함하고 있습니다. 이 취약점들은 4.17.23 및 4.18.x 계열에서만 해결되었습니다.
- 취약점 대응에서 어려운 부분은 기술적인 측면보다는 조직적인 측면에 있으므로, 실제 호출 위치를 파악하고, 경계에서 입력 값을 강화하며, 악용 여부를 모니터링하는 것이 즉각적인 업그레이드가 현실적으로 어려운 상황에서 시간을 벌 수 있는 방법입니다.
- TuxCare의 ELS for Libraries와 같은 서비스를 통해 역포트된 수정 사항을 활용하면, 팀은 위험한 마이그레이션을 서두르지 않고 4.18.x 버전으로 신중하게 마이그레이션을 계획하는 동안, 안정성이 검증된 4.17.21 빌드를 계속 사용할 수 있습니다.
여러분의 팀은 해당 취약점에 대해 알고 있습니다. 해당 티켓은 9개월째 열려 있는 상태입니다. 아무도 손을 대지 않았습니다. 이 글에서는 그 이유와, 기다리기만 하는 대신 무엇을 해야 하는지에 대해 다룹니다.
고쳐지지 않는 특정한 종류의 취약점이 있습니다. 이는 엔지니어들이 부주의해서도, 보안 팀이 방심해서도 아닌, 기술적으로는 해결이 가능하지만 운영상으로는 너무나도 두려운 일이기 때문입니다. lodash 버전 4.17.21은 현대 자바스크립트 프로젝트에서 이러한 패턴을 보여주는 대표적인 사례이며, 수년 동안 업계 전반의 운영 환경에 그대로 남아 있습니다.
이 글은 CVE 분류에 대한 설명이 아닙니다. 그런 내용은 직접 찾아보시면 됩니다. 이 글은 ‘무언가 잘못되었다는 것을 아는 것’과 ‘그에 대해 실제로 조치를 취할 수 있는 것’ 사이의 간극에 관한 것이며, 팀들이 그 간극이 존재하지 않는 척하지 않고 이를 헤쳐 나가는 실질적인 방법에 대해 다룹니다.
lodash 4.17.21이 어떻게 등장했고, 지금까지 자리를 지키게 되었는지
lodash는 실제 문제를 해결했기 때문에 역사상 가장 많이 다운로드된 자바스크립트 패키지 중 하나가 되었습니다. 당시 자바스크립트 표준 라이브러리는 기능이 부족했고, 환경에 따라 일관성이 없었으며, 브라우저 호환성 문제는 마치 지뢰밭과도 같았기 때문입니다. 전성기에는 스타트업의 부업 프로젝트부터 포춘 500대 기업의 플랫폼에 이르기까지 모든 분야에서 lodash가 사용되었습니다.
그러다 현대적인 자바스크립트가 성숙해졌습니다. 네이티브 배열 메서드도 개선되었습니다. ES6 이후 버전에서는 lodash가 개척했던 유틸리티 패턴의 상당 부분이 흡수되었습니다. 새로운 프로젝트들은 lodash 없이 출시되기 시작했습니다. 하지만 기존 프로젝트들, 특히 수년에 걸쳐 개발된 대규모 코드베이스의 경우, 갑자기 lodash를 제거하지는 않았습니다. 이미 수천 군데에 달하는 호출 지점이 누적되어 있었기 때문입니다. 이를 리팩토링하는 것은 막대한 작업이었을 뿐만 아니라, 그 성과도 불확실했습니다.
2021년 2월에 출시된 버전 4.17.21은 _.template의 고위험 명령어 삽입 취약점(CVE-2021-23337)과 정규식 기반 서비스 거부(DoS) 문제(CVE-2020-28500)를 수정하기 위해 출시되었으며, 생태계 전반에서 공식 고정 버전으로 자리 잡았습니다. 그리고 이후 거의 5년 동안 추가 릴리스 없이 이 버전이 유지되었습니다. 이는 4.17.21 버전이 영구적으로 안전하기 때문이 아닙니다. 이후 새로 구성된 거버넌스 팀이 이 버전에 영향을 미치는 새로운 결함들을 공개했기 때문입니다. 바로 _.unset 및 _.omit의 프로토타입 오염(CVE-2025-13465 및 CVE-2026-2950)과 _.template의 코드 주입 우회(CVE-2026-4800)입니다. 이 문제들에 대한 수정 사항은 현재 lodash 4.18.x 버전에 포함되어 있지만, lodash를 업그레이드하거나 완전히 제거하는 데는 상당한 비용이 소요되며, 비용 대비 편익을 따져볼 때 당장 조치를 취하는 것이 유리하다고 판단되는 경우는 거의 없습니다.
타동사 의존성 문제
lodash 4.17.21을 사용 중인 많은 팀은 이를 직접 실행하고 있지도 않습니다. 이 취약점은 2년 전에 설치한 프레임워크의 의존성 중 의존성, 다시 그 의존성 안쪽, 즉 세 단계 아래에 존재합니다. 다음 명령어를 실행해 보세요. 중간 규모의 Node.js 프로젝트에서 을 실행해 보면, 간접 참조가 가지치기를 이룬 구조를 자주 발견하게 될 것입니다. 애플리케이션 코드 자체는 lodash를 전혀 임포트하지 않을 수도 있습니다.
이 때문에 책임 소재 문제가 매우 골치 아픈 문제가 됩니다. 팀원 중 누구도 의도적으로 도입하지 않은 전이적 의존성을 수정할 책임은 누구에게 있을까요? 보안 팀은 엔지니어링 팀의 책임이라고 주장합니다. 엔지니어링 팀은 업스트림 패키지를 관리하는 팀의 책임이라고 말합니다. 해당 팀은 현재 배포 환경에서는 기술적으로 악용될 여지가 없다고 말합니다. 결국 해당 티켓은 미해결 상태로 남아 있습니다.
알려진 취약점의 심리학
보안 관련 문헌은 주로 알려지지 않은 위협, 즉 제로데이 공격, 새로운 공격 경로, 방어자보다 더 빠르게 움직이는 공격자 등에 집중하고 있습니다. 하지만 실제로는 실제 사고의 상당 부분이 이미 알려져 있고, 경고가 있었음에도 의도적으로 대응을 미루었던 취약점에서 비롯됩니다.
엔지니어들은 사고 후 검토 과정에서 같은 상황을 끊임없이 반복해 설명합니다. 그들은 그 문제를 알고 있었지만, 수년 동안 안정적으로 작동해 온 코드베이스의 일부를 수정할 승인을 받지 못했고, 아무도 그 시스템을 망가뜨리는 사람이 되고 싶어 하지 않았습니다.
이는 과실이 아닙니다. 이는 조직의 인센티브에 대한 합리적인 대응입니다. 기능을 출시하는 것은 눈에 보이는 가치를 창출합니다. 반면, 아직 사고로 이어지지 않은 취약점을 해결하기 위해 의존성 그래프를 리팩토링하는 것은 눈에 보이지 않는 가치를 창출할 뿐 아니라, 회귀 현상, 지연, 그리고 운영 환경에서 문제가 발생할 경우 비난을 받을 수 있는 구체적인 하방 리스크를 수반합니다.
그 결과, 리스크 전문가들이 때때로 ‘기본 리스크 허용도’라고 부르는 현상이 발생합니다. 이는 리스크를 수용하겠다는 의도적인 결정이 아니라, 리스크가 주변 환경의 일부가 될 때까지 미루기를 반복한 결과입니다. 리스크가 항상 존재해 왔기 때문에 팀원들은 더 이상 이를 명확하게 인식하지 못하게 됩니다. 스캐너가 이를 감지하고, 티켓이 업데이트되며, 스프린트가 끝나도 lodash 4.17.21은 여전히 남아 있습니다.
작은 도서관, 넓은 공격 표면
lodash는 규모가 작게 느껴집니다. 이는 유틸리티 라이브러리입니다. 대부분의 사람들이 보안에 민감한 코드와 연관 짓는 요소인 인증, 권한 부여, 네트워크 통신과는 전혀 관련이 없습니다. 이러한 인식이 ‘나중에 처리하기’ 현상을 부추기고 있습니다.
그러나 공격 표면은 기능의 문제가 아닙니다. 노출의 문제입니다. lodash 함수는 애플리케이션 로직 전반에 걸쳐 호출되며, 종종 신뢰 경계를 넘어온 데이터와 함께 사용됩니다. 공격자가 조작된 입력을 제공하여 자바스크립트의 객체 상속 체인을 조작할 수 있는 ‘프로토타입 오염’ 취약점은, 겉으로 드러나지 않는 방식으로, 또한 상황에 따라 달라지는 방식으로 애플리케이션의 동작에 영향을 미칠 수 있습니다.
A _.merge() 호출은 구성 처리 유틸리티의 깊은 곳에서 사용자가 제공한 JSON을 처리하는 과정에 포함되어 있어, 언뜻 보기에는 위험해 보이지 않습니다. 하지만 이는 주변 애플리케이션 로직에 따라 접근 제어 우회, 애플리케이션 상태 변조, 심지어 코드 실행 경로로 이어질 수 있는 전형적인 호출 지점입니다. 이 함수가 겉보기에는 무해해 보인다는 점이 바로 위험한 이유 중 하나입니다.
| 취약성 | 영향을 받는 메서드 | 악용 가능성 / 영향 | 위험도 |
| 코드 삽입 (CVE-2026-4800) | _.template (options.imports) | 템플릿 컴파일 시점에 발생하는 원격 임의 코드 실행; CVE-2021-23337에 대한 불완전한 수정 | 높음 (8.1) |
| 프로토타입 관련 취약점 (CVE-2026-2950) | _.unset, _.omit | 배열로 감싸진 경로를 통해 전역 프로토타입에서 메서드를 삭제하며, CVE-2025-13465 수정 사항을 우회합니다. | 중간 (5.3) |
| 프로토타입 관련 취약점 (CVE-2025-13465) | _.unset, _.omit | 특정 문자열 경로를 통해 전역 프로토타입에서 메서드를 삭제하며, 이로 인해 서비스 거부(DoS)가 발생할 수 있음 | 중간 (5.3) |
취약점의 악용 가능성은 상황에 따라 크게 달라집니다. 사용자가 제어하는 데이터를 해당 메서드에 절대 전달하지 않는 애플리케이션은 사실상 취약점에 노출되지 않은 것과 같습니다. 하지만 대규모 코드베이스 내의 모든 호출 위치를 파악하고, 이를 확신하며 그렇게 말할 수 있는 팀이 과연 몇 개나 될까요? 대부분의 조직에서 솔직한 대답은 ‘별로 없다’일 것입니다.
이를 어렵게 만드는 현실적인 제약 조건들
명백한 해법인 ‘lodash를 업그레이드하거나 제거하라’는 추상적인 관점에서는 옳지만, 실제로는 실행하기 어렵습니다. 구체적으로 말하면, 규모에 상관없이 모든 조직에서 반복적으로 발생하는 세 가지 구조적 문제에 부딪히게 됩니다.
릴리스 주기 및 안정성 요구 사항
많은 운영 환경에서는 광범위한 테스트, 여러 이해관계자의 승인, 배포 전 최소한의 안정화 기간을 요구하는 변경 관리 프로세스를 따릅니다. 통합 테스트 스위트에서 예기치 않은 동작을 유발하는 의존성 버전이 업데이트되면 릴리스 일정이 몇 주나 지연될 수 있습니다. 금융 서비스, 의료, 중요 인프라와 같은 규제 대상 환경에서는 이러한 장벽이 훨씬 더 높습니다. 보안 개선 사항도 다른 모든 변경 사항과 동일한 절차를 거쳐 도입되므로, 측정 가능한 비즈니스 가치를 창출하는 기능들과 주목과 승인을 놓고 경쟁해야 합니다.
기존 코드베이스의 회귀 위험
lodash 4.x는 수년 동안 API가 안정적으로 유지되어 왔지만, lodash를 제거하거나 네이티브 메서드로 대체하려면 모든 호출 위치를 검토해야 하며, 새로 출시된 4.18.x 버전으로 전환하는 것만으로도 미묘한 동작상의 변화가 발생할 수 있습니다.
5년 이상에 걸쳐 lodash 호출이 누적된 코드베이스의 경우, 이는 주말에 끝낼 수 있는 작업이 아닙니다. 테스트 커버리지는 종종 고르지 않은데, 코드베이스에서 가장 오래되고 lodash 사용 빈도가 높은 부분은 조직의 현대적인 테스트 관행이 도입되기 이전에 작성된 부분인 만큼, 오히려 테스트가 가장 미흡한 경우가 많습니다.
소유권 및 조직적 격차
마이크로서비스 아키텍처와 대규모 엔지니어링 조직에서는 코드베이스에 담당자가 지정되어 있지만, 현재의 팀 구조가 형성되기 이전에 구축된 레거시 서비스의 경우 담당자 구분이 모호한 경우가 종종 있습니다. 이미 개편된 팀이 구축한 서비스의 경우 명확한 담당자가 없을 수 있습니다. 보안 팀은 해당 취약점을 지적하고, 운영 팀은 보고서에 해당 서비스를 기재하겠지만, 실제로 변경을 수행할 권한과 상황을 파악하고 있는 사람은 아무도 없을 것입니다. 이러한 상황은 대부분의 조직이 인정하고 싶어 하지 않는 것보다 훨씬 더 흔하게 발생합니다.
구조적 통찰
취약점 자체는 어려운 문제가 아닙니다. 진짜 어려운 문제는 조직적인 측면에 있습니다. 즉, 책임자를 파악하고, 우선순위 설정을 위한 근거를 마련하며, 스프린트 일정을 확보하고, 회귀 위험을 감수하는 것입니다. 기술적인 복잡성은 대개 이러한 과제 중 가장 작은 부분에 불과합니다.
팀의 실제 업무와 효과적인 방법
이러한 제약 사항을 고려할 때, 수준 높은 엔지니어링 조직들은 단순히 lodash 4.17.21을 무시하고 상황이 잘 풀리기를 바랄 뿐이 아닙니다. 이들은 업그레이드가 당장 이루어질 수 없다는 점을 인정하면서도, 그 동안 발생할 수 있는 위험을 줄이기 위해 다양한 위험 완화 전략을 적용합니다. 이 중 어느 것도 완벽하지는 않지만, 아무것도 하지 않는 것보다는 낫습니다.
노출 요인의 분리 및 매핑
첫 번째 단계는 솔직한 평가입니다. 의존성 트리에 lodash를 포함하고 있는 모든 애플리케이션이 동일한 위험에 노출되어 있는 것은 아닙니다. 실제 호출 위치를 파악하는 데 시간을 투자하는 팀, 특히 다음과 같이 알려진 4.17.21 버전의 위험과 관련된 메서드들을 면밀히 분석하는 팀은 _.template, _.unset, _.omit와 같은 메서드 —를 매핑하는 데 시간을 투자하는 팀은 현실적인 위험 순위를 도출할 수 있습니다. —를 사용하면 현실적인 위험 순위를 산출할 수 있습니다. lodash를 오직 _.isEqual 및 _.cloneDeep 만 사용하는 서비스와는 근본적으로 다릅니다. _.template 출력을 생성하는 방식과는 근본적으로 다릅니다.
이 매핑 작업은 당장 문제 해결로 이어지지 않더라도 그 자체로 가치가 있습니다. 이 작업을 통해 lodash에 대한 막연하고 포괄적인 불안감을 실제 위험 요소의 우선순위 목록으로 전환함으로써, 문제 해결 방안을 수립하는 과정을 보다 체계적으로 진행할 수 있게 됩니다.
입력 검증 및 경계에서의 보안 강화
Prototype 오염 및 명령어 주입 취약점은 일반적으로 취약한 함수에 도달하기 위해 공격자가 제어하는 입력이 필요합니다. 애플리케이션 경계에서 입력 유효성 검사를 강화하여, 들어오는 JSON에 대해 스키마 유효성 검사를 적용하고, 다음과 같은 의심스러운 키 패턴을 가진 입력을 거부해야 합니다. __proto__ 또는 생성자와 같은 의심스러운 키 패턴을 가진 입력을 거부하는 것, 템플릿 함수에 입력되기 전에 문자열을 정제하는 것 —은와 같은 의심스러운 키 패턴을 가진 입력을 거부하고, 템플릿 함수로 들어가기 전에 문자열을 정제하는 등 애플리케이션 경계에서 입력 검증을 강화하면, 기본 의존성을 건드리지 않고도 악용 가능성을 줄일 수 있습니다.
이는 근본적인 해결책이 아닌 보완적인 제어 조치입니다. 취약점은 여전히 남아 있습니다. 하지만 공격자의 입력이 취약한 코드에 도달할 수 있는 경로를 제한하는 것은 타당한 임시 조치이며, 전체 릴리스 주기를 거치지 않고도 종종 적용할 수 있는 종류의 변경 사항입니다.
모니터링 및 탐지
런타임 애플리케이션 자가 보호(RASP) 도구와 웹 애플리케이션 방화벽을 구성하여 프로토타입 오염 시도 패턴을 탐지하고 차단할 수 있습니다. 수신 요청에서 의심스러운 객체 키 패턴에 대한 로깅 및 경고를 통해, 아직 패치를 적용할 수 없는 상황이라 하더라도 해당 취약점이 적극적으로 탐색되고 있는지 여부를 파악할 수 있습니다.
탐지가 위험을 완전히 제거하는 것은 아니지만, 위험 프로필을 변화시킵니다. 능동적으로 모니터링되는 알려진 취약점은 경고를 발생시키지 않는 시스템 내의 동일한 취약점보다 훨씬 덜 위험합니다. 최소한, 탐지는 악용이 발생할 경우 더 신속한 사고 대응을 가능하게 합니다.
선택적으로 지원 확대하기
레거시 의존성이 있는 여러 애플리케이션을 관리하는 조직의 경우, 지원 기간 연장을 명시적인 위험 관리 도구로 활용하는 것이 점점 더 실용적인 접근 방식이 되고 있습니다. 별도의 위험을 초래할 수 있는 일정에 맞춰 불안정한 업그레이드를 강행하기보다는, 팀은 다음과 같은 서비스를 활용할 수 있습니다. TuxCare의 ELS for Libraries 와 같은 서비스를 활용하여 특정 라이브러리 버전에 대한 백포트된 보안 수정 사항을 적용받을 수 있습니다. 이를 통해 검증된 구성의 안정성을 유지하면서 가장 중요한 취약점에 대한 패치를 적용할 수 있습니다.
이는 영구적인 해결책이 아니며, 그렇게 여겨져서는 안 됩니다. 목표는 숨 쉴 여유를 확보하는 것입니다. 즉, 그 동안 아무런 대비 없이 허둥지둥하지 않고도 적절한 마이그레이션을 계획하고 실행할 시간을 마련하는 것입니다. 엄격한 변경 관리 체제 하에서 운영되거나, 상호 의존 관계가 명확히 파악되지 않은 서비스를 관리하는 팀의 경우, 이 접근 방식은 조직이 감당할 준비가 되지 않은 업그레이드를 강요하기보다는 보안 개선과 운영 현실을 조화롭게 맞출 수 있게 해줍니다.
빅뱅 방식의 전면 재작성보다 점진적인 마이그레이션
Lodash를 완전히 제거하는 것이 궁극적인 목표라면, 점진적인 접근 방식은 마이그레이션 자체의 위험을 줄여줍니다. 위험이 가장 높은 호출 지점부터 시작하여 점차 범위를 넓혀가며 Lodash 유틸리티를 메서드별로 교체하면, 실패하기 쉬운 ‘빅뱅 방식’의 재작성을 피할 수 있습니다. 팀은 의존성 심사를 통해 진행 상황을 추적하고, 서비스별로 Lodash 사용을 단계적으로 중단하며, 제거된 각 사용 사례를 단순히 구분되지 않은 백로그상의 작업이 아닌, 측정 가능한 위험 감소로 간주합니다.
정직한 회계
lodash 4.17.21에 대한 불편한 진실은 이 버전이 현재 운영 환경에 배포되어 있다는 사실이 아닙니다. 보안 스캐너의 보고 결과나 보안 권고 사항이 무엇이든 간에, 대부분의 조직에서 이 버전이 오랫동안 운영 환경에 남아 있을 것이라는 점입니다. 엔지니어링 역량은 한정되어 있습니다. 위험 허용 범위는 조직 차원에서 실제로 존재하는 현상입니다. “지금 바로 업그레이드”와 “실질적인 마이그레이션을 계획하는 동안 신중하게 관리” 중 어느 쪽을 선택할지에 대한 판단은, 많은 상황에서 후자를 선호하는 쪽으로 기울어질 것입니다.
이러한 현실에 대한 대응은 체념이 아닙니다. 그것은 정직한 위험 관리입니다. 즉, 어떤 호출 지점이 취약한지 파악하고, 경계를 강화하며, 악용 여부를 모니터링하고, 업그레이드에 걸리는 시간이 실제로 긴 경우에는 근본적인 문제가 해결된 척하지 않으면서도 이용 가능한 도구를 활용해 취약점이 노출될 수 있는 기간을 최소화하는 것입니다.
보안 성숙도란 알려진 취약점이 하나도 없다는 것을 의미하지 않습니다. 이는 위험에 대한 가시성을 확보하고, 조치 유예를 보이지 않는 누적 현상이 아닌 신중한 결정으로 간주하며, 체계적으로 취약점을 보완해 나가는 것을 의미합니다. lodash 4.17.21은 조직이 이를 성실히 수행할 수 있는지 여부를 가늠해 볼 수 있는 적절한 테스트 사례입니다.
이 티켓은 9개월 동안 미해결 상태로 남아 있습니다. 이제 이 티켓을 어떻게 처리할지 결정해야 할 때입니다.

