Skip to content

security: next 16.4.2 — 10/22 Next.js 보안 권고 3건 반영 - #47

Merged
mikim merged 1 commit into
mainfrom
chore/next-16.4.2
Oct 24, 2026
Merged

mikim merged 1 commit into
mainfrom
chore/next-16.4.2

Conversation

@mikim

@mikim mikim commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

무엇을

  • next 16.3.8 → 16.4.2 (package.json 정확 고정, pnpm-lock.yaml). @next/env·@next/swc-*도 함께 16.4.2가 됩니다.
  • baseline-browser-mapping 2.10.27 → 2.11.29: lockfile만 바꿨고, next가 선언한 ^2.9.19 범위 안입니다. GHSA-w5vr-8v7q-w6rv(중간)를 해소합니다.
  • pnpm-workspace.yaml auditConfig
    • 더 이상 매칭되지 않는 GHSA-6g55-p6wh-862q(postcss <= 8.5.11)를 지웠습니다.
    • 남은 4건의 출처 주석을 고쳤습니다. 매칭되는 것은 next의 postcss 8.5.23이 아니라 @tailwindcss/postcss가 가져오는 postcss 8.5.14(nanoid 3.3.12)입니다.
  • 바꾸지 않은 것
    • sharp 0.35.5: next 16.4.2의 optional 의존성이 ^0.35.5입니다.
    • source-map-js 1.2.2
    • allowBuilds: sharp 0.35.x와 baseline-browser-mapping은 install 스크립트가 없습니다.

왜

2026-10-22에 공개된 Next.js 권고 3건의 범위에 16.3.8이 들어갑니다.

권고 등급 내용 영향 → 수정
GHSA-2464-fhr4-w9xw 치명 이미지 최적화 API 비인증 RCE(SVG, glibc Linux) 16.0.0–16.4.0 → 16.4.1
GHSA-673q-mjm6-r5xr 치명 use cache 함수가 typed array를 반환할 때 비인증 RCE 16.0.0–16.4.0 → 16.4.1
GHSA-p3m5-59mp-jv5r 높음 Server Action이 있는 App Router의 CPU DoS 16.0.0–16.4.0 → 16.4.1

이 앱의 현재 노출은 낮습니다.

  • 원격 이미지 소스가 없고 dangerouslyAllowSVG는 꺼져 있습니다.
  • Server Action은 0개이고 cacheComponents는 꺼져 있습니다.

그래도 지금 올리는 이유는 두 가지입니다.

  • GHSA-673q는 우회책이 없습니다. 제공자는 해당 함수가 없어도 업그레이드하라고 권합니다.
  • CI의 pnpm audit --audit-level=high가 이 3건 때문에 실패합니다. main 693c890에서 로컬로 재현했습니다(exit 1, 치명 2·높음 1). scripts/deploy.sh는 CI가 녹색이 아닌 SHA를 배포하지 않습니다. 그래서 이 bump가 없으면 다른 변경도 배포되지 않습니다.

16.4.2를 고른 이유는 이렇습니다.

  • 16.4.1과 16.4.2 모두 수정본입니다.
  • 16.4.2(10/15 공개)는 16.4.1에 백포트 버그 수정(주로 Turbopack)과 문서 수정만 더한 버전이고, 공개된 지 1주가 넘었습니다.
  • 16.4.3(10/23)에는 보안 수정이 없고 공개된 지 하루도 안 되어 이번에는 쓰지 않습니다.

확인한 것

로컬 새 클론에서 pnpm 11.28.6, Node 26으로 돌렸습니다(CI는 Node 22). 순서와 환경은 ci.yml과 같습니다: NODE_ENV=production, DB_PATH·MIC_DATA_PATH는 임시 경로.
별도 클론에서 Node 22.22.1과 빈 pnpm store로 같은 단계를 다시 돌려 아래 표와 같은 결과를 얻었습니다. 바뀐 패키지 11개의 lockfile integrity는 레지스트리(registry.npmjs.org) 값과 모두 같습니다.

단계 main 693c890 이 브랜치
pnpm install --frozen-lockfile 통과 통과(빌드 스크립트 경고 없음)
pnpm exec tsc --noEmit 0 0
pnpm test 28/28 28/28
pnpm build 통과(16.3.8, 경고 8) 통과(16.4.2, 같은 경고 8)
tsx scripts/check-health.ts OK — 12 subsystems 같음
pnpm audit --audit-level=high exit 1: 치명 2·높음 1·중간 1·낮음 1, 무시 4 exit 0: 낮음 1, 무시 4
  • 남은 낮음 1건은 esbuild 0.27.7(tsx 경유)의 GHSA-g7r4-m6w7-qqqr입니다. Windows 개발 서버에서만 해당합니다.
  • ignore 목록을 비우고 다시 돌렸을 때 매칭된 것은 GHSA-r28c·GHSA-fxqj·GHSA-28wg·GHSA-2v37 네 건뿐입니다. 모두 @tailwindcss/postcss 경로입니다.
  • 빌드 출력
    • 라우트 표(45개)는 전후가 같습니다.
    • 빌드 경고 8건도 전후가 같습니다(기존 Dynamic fs 추적 경고).
  • next start 전후 두 개를 나란히 띄워 24개 경로를 비교했습니다.
    • 상태 코드는 모두 같습니다.
    • /opengraph-image, /apple-icon, /icon.svg, /robots.txt, /llms.txt, /manifest.webmanifest는 바이트까지 같습니다.
    • /_next/image는 래스터 원본의 결과가 바이트까지 같고, SVG 원본은 전후 모두 400입니다.
    • HTML 12개 페이지에서 보이는 텍스트(script·style 제외)는 11개가 같습니다. 홈만 시세 값과 '몇 초/분 전' 표시가 다른데, 요청 시각이 달라서입니다.
    • 마크업 차이는 프레임워크 내부뿐입니다.
      • 빌드 ID·청크 이름
      • RSC payload 형식
      • Turbopack 청크 로딩용 인라인 스크립트: 현재 CSP 설정에서 막히지 않습니다.
      • 폰트 CSS 모듈 클래스 이름 축약(…-module__CUItYG__variable → CUItYG_variable): 바뀐 이름이 CSS에도 그대로 정의되어 있습니다.
  • baseline-browser-mapping만 바꾼 빌드와 바꾸지 않은 빌드의 .next/static은 빌드 ID 폴더를 빼면 같습니다.
  • 다음 두 가지도 전후가 같습니다.
    • Server Action manifest: 비어 있습니다.
    • images-manifest: formats webp, remotePatterns 없음, SVG 꺼짐.
  • 16.4.0 릴리스 노트에서 기본값 변경을 확인했습니다.
    • strict route matching: 이 앱에는 catch-all·parallel·intercepting 라우트가 없습니다.
    • React browser bailout, production export mangling: 빌드와 스모크 테스트에서 문제가 없었습니다.
    • proxy·middleware는 없습니다.
  • 로컬 RSS(참고용, macOS·빈 DB)는 같은 요청 45회 뒤 이전 158MB, 이후 141MB였습니다.

이 PR의 CI(Node 22, pnpm 11)가 녹색인지 확인한 뒤 병합합니다. lockfile 변경은 버전·integrity 줄뿐이고 형식(v9)은 그대로입니다.

배포

  • 병합이 곧 배포입니다. 기존 pull 배포 그대로입니다.
    • squash 병합 → main CI(checks) 녹색 → 배포 poller(scripts/deploy-loop.sh → scripts/deploy.sh)의 다음 주기
    • poller는 새 릴리스 폴더에서 install·test·build·smoke를 한 뒤 전환합니다. CI가 녹색이 아닌 SHA는 배포하지 않습니다.
    • DEPLOY_QUIET_HOURS_KST 시간대에는 다음 주기로 미뤄집니다.
  • 브랜치 push와 PR 열기로는 배포되지 않습니다. CI(ci.yml)는 pull_request와 main push에서만 돌고, 권한은 contents: read입니다.
  • 병합 시점은 메인테이너가 정합니다. 병합 직후 배포와 관찰을 이어서 할 수 있을 때 병합합니다.
  • 배포 후 약 10분 동안 확인합니다.
    • /, /api/health, /opengraph-image, /ask가 200인지
    • 앱 재시작 수, 메모리 사용량, 오류 로그
    • 실행 중인 next가 16.4.2인지

되돌림

  1. scripts/deploy.sh의 operator hold를 먼저 겁니다. 그래야 poller가 main을 다시 올리지 않습니다.
  2. 직전 릴리스 폴더로 전환합니다. deploy.sh의 pm2_swap_to와 같은 방식이고 재빌드는 없습니다.
  3. revert PR은 해결책이 아닙니다. 16.3.8로 돌아가면 CI audit이 실패해 필수 check 때문에 병합되지 않습니다.
    • 원인은 전진 PR로 고칩니다(예: 16.4.1 또는 16.4.3).
    • hold는 그 PR이 배포될 때 풉니다.

후속(범위 밖)

  • @tailwindcss/postcss의 postcss 8.5.14 → 8.5.23(^8.5.6 범위 안)
    • lockfile 갱신만으로 남은 ignore 4건이 모두 빠질 수 있습니다.
    • 별도 PR로 합니다.
  • esbuild GHSA-g7r4(낮음)
    • tsx 4.21.0이 ~0.27.0으로 묶여 있고, allowBuilds도 esbuild@0.27.7로 고정되어 있습니다.
    • Windows 개발 서버만 해당하므로 그대로 둡니다.

🤖 Generated with Claude Code

next 16.3.8 → 16.4.2 (정확 고정). @next/env·@next/swc-* 는 next 를 따라
16.4.2 로 바뀐다. 16.3.8 은 2026-10-22 공개된 GHSA-2464-fhr4-w9xw(치명,
이미지 최적화 RCE), GHSA-673q-mjm6-r5xr(치명, 'use cache' RCE),
GHSA-p3m5-59mp-jv5r(높음, Server Actions DoS) 범위 안이고, 이 셋 때문에
CI 의 `pnpm audit --audit-level=high` 가 실패한다. CI 가 빨간 SHA 는
scripts/deploy.sh 가 배포하지 않으므로, 이 bump 없이는 다른 변경도 배포되지
않는다.

baseline-browser-mapping 2.10.27 → 2.11.29: lockfile 만, next 가 선언한
^2.9.19 범위 안. GHSA-w5vr-8v7q-w6rv(중간, 빌드 시 입력 처리 DoS) 해소.
2.11.29 는 10/15 공개본(1주 이상)이고, 이것만 바꾼 빌드의 .next/static
은 바꾸기 전과 같았다(빌드 ID 폴더만 다름).

pnpm-workspace.yaml auditConfig: 주석대로 ignore 목록을 빼고 audit 를
다시 돌렸다. GHSA-6g55-p6wh-862q(postcss <= 8.5.11)는 이미 매칭되지 않아
지운다. 남은 4건은 next 의 postcss 8.5.23 이 아니라 @tailwindcss/postcss
가 가져오는 postcss 8.5.14(nanoid 3.3.12)에 매칭되므로 주석을 실제에 맞게
고친다.

sharp 는 0.35.5 그대로(next 16.4.2 optional ^0.35.5), source-map-js 1.2.2
그대로. sharp 0.35.x·baseline-browser-mapping 모두 install 스크립트가
없어 allowBuilds 는 바꾸지 않는다.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mikim
mikim merged commit ced97df into main Oct 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant