website: Dependabot High 취약점 패치 (next/sharp)
이슈 #403에서 정리해둔 프론트엔드 Dependabot 취약점 목록 중, non-breaking하게 고칠 수 있는 것들만 골라 처리한 PR이다.
이슈를 열어보니 High 10건, Medium 6건이 쌓여 있었다. 전부 한 번에 손대면 리스크가 크니, 일단 patch 버전 업만으로 해결되는 것부터 정리하기로 했다. 가장 먼저 눈에 띈 건 next였다. 16.2.9에서 16.2.12로 patch 버전만 올리면 되는데도 SSRF(Server Actions/rewrites), 미들웨어 우회(Turbopack + 단일 로케일), Server Actions DoS 등 severity 높은 항목이 다수 해결됐다. breaking change 없이 이 정도를 잡을 수 있으면 안 할 이유가 없었다.
문제는 sharp였다. next가 내부적으로 물고 있는 의존성이라 package.json에서 직접 버전을 올릴 수가 없었다. 이런 경우 선택지는 사실 하나였다 — overrides로 강제 지정하는 것. libvips CVE가 패치된 0.35.3으로 override를 걸었다.
postcss도 비슷한 상황이라 같은 방식으로 override를 시도했는데, 이건 next 내부에 optionalDependency로 박혀있어서 override를 걸자 설치 상태가 invalid로 깨졌다. 여기서 무리하게 밀어붙이는 대신 보류 쪽으로 판단했다. 프로젝트 자체에 postcss.config.mjs가 있어서 실제 빌드에서는 top-level에 이미 패치돼 있는 postcss(8.5.25)를 쓰고 있었고, 그러면 실사용 위험은 낮다고 봤다. next가 자체 postcss를 올리는 다음 릴리스가 나올 때까지 기다리는 게 맞다고 결론 내리고 이슈 #403에 남겨뒀다.
패치 자체는 간단했는데, 그다음부터 lockfile 문제로 발이 묶였다. 로컬(Windows)에서 npm install로 만든 lockfile을 그대로 올렸더니 CI(Linux)의 npm ci에서 @emnapi/runtime@1.11.3 missing from lock file 에러가 났다. 플랫폼별 optionalDependencies 메타데이터가 OS마다 다르게 기록되는 게 원인이었다. node_modules와 lockfile을 완전히 지우고 처음부터 재생성해서 해결했고, 로컬에서 npm ci·build·vitest 74개를 다시 돌려서 확인했다.
이후 리뷰 대응으로 한 번 더 손을 봤다. 처음에 ^16.2.12로 넣어뒀던 걸 ~16.2.12로 좁혔는데, caret(^)으로 두면 npm install 시 16.3.x 같은 minor 버전까지 올라갈 여지가 있어서 "patch(non-breaking) 업그레이드"라는 이 PR의 의도와 어긋날 수 있었다. tilde(~)로 patch 범위만 허용하도록 고쳤다. 그 김에 eslint-config-next도 16.2.9에 그대로 머물러 있어서 next 본체 버전과 어긋나 있던 걸 16.2.12로 맞췄다. 이 과정에서 lockfile은 또 재생성했다.
중간에 dev 브랜치와 충돌이 나서 merge를 한 번 거쳤고, package.json/package-lock.json 양쪽에서 conflict를 정리한 뒤 최종적으로 병합됐다.
돌아보면 이번 작업에서 실제로 판단이 필요했던 지점은 두 곳이었다. 하나는 override로도 안 풀리는 postcss를 억지로 밀어붙이지 않고 "지금 실사용 경로는 안전하다"는 근거를 확인한 뒤 보류한 것, 다른 하나는 semver 범위 지정(^ vs ~)이 패치 정책의 의도를 그대로 반영하는지 다시 짚어본 것이다. 취약점 패치는 버전만 올리면 끝날 것 같지만, 실제로는 lockfile 플랫폼 이슈나 semver 범위처럼 눈에 잘 안 띄는 부분에서 시간이 더 걸렸다.