보안이슈

Fastify CVE 2건|파일 업로드 DoS·OAuth 로그인 CSRF

Fastify 생태계의 @fastify/multipart와 @fastify/oauth2에서 각각 디스크 고갈과 로그인 CSRF로 이어질 수 있는 취약점이 공개됐습니다. 영향 조건, 패치 버전, 업그레이드 뒤 필요한 설정과 운영 검증 순서를 정리합니다.

Fastify 취약점 2건: 파일 업로드 DoS와 OAuth 로그인 CSRF 표지
Fastify 취약점 2건: 파일 업로드 DoS와 OAuth 로그인 CSRF 표지

두 취약점, 서로 다른 운영 경계

Fastify 플러그인 두 곳에서 2026년 8월 14일 연이어 보안 권고가 공개됐습니다. CVE-2026-19474는 @fastify/multipart가 여러 파일 파트를 저장하다 연결이 끊겼을 때 이미 완성된 임시파일을 남길 수 있는 문제입니다. 같은 요청을 반복하면 디스크 사용량이 선형으로 늘어나 서비스 거부로 이어질 수 있습니다. CVE-2026-18165는 @fastify/oauth2가 OAuth state와 PKCE verifier를 일반 호스트 쿠키에 보관하는 구성에서, 관련 서브도메인이 그 쿠키를 덮어쓸 수 있는 문제입니다. 공격자는 피해자의 브라우저를 자신이 승인한 OAuth 흐름에 묶어 로그인 맥락을 바꿀 수 있습니다.

두 문제는 모두 Fastify 애플리케이션의 경계에서 생기지만 대응 방식은 다릅니다. multipart 취약점은 수정 버전으로 패키지를 교체하는 것이 우선이며, 교체 전에는 실패한 요청의 임시파일을 명시적으로 정리해야 합니다. oauth2 취약점은 8.3.0으로 올리는 것만으로 보호가 켜지지 않습니다. 새로 제공되는 호스트 접두사 쿠키 옵션을 HTTPS 환경에서 활성화하거나, state를 서버 측 세션에 결속하는 별도 검증 설계를 적용해야 합니다. 따라서 잠금 파일에서 버전만 확인하는 점검으로는 두 취약점을 함께 닫을 수 없습니다.

CVE-2026-19474|중단된 업로드가 디스크에 남는 과정

@fastify/multipart는 업로드된 파일을 운영체제의 임시 디렉터리에 저장하는 request.saveRequestFiles() 기능을 제공합니다. 여러 파트로 구성된 요청에서 앞쪽 파일이 저장을 마친 뒤, 클라이언트가 다음 파트를 시작하고 연결을 끊으면 요청 처리기는 오류로 종료됩니다. 취약한 버전에서는 이 오류가 파일별 정리 범위 밖에서 전파될 수 있어, 앞서 저장을 마친 임시파일이 삭제되지 않습니다. 애플리케이션은 실패 응답을 돌려주더라도 디스크에는 파일이 남는 셈입니다.

다중 파트 업로드 중단 뒤 임시파일이 누적되는 5단계 흐름
CVE-2026-19474 공격 흐름|완료된 앞쪽 파일이 실패한 요청의 정리 경로에서 빠지며 임시 디렉터리에 누적됩니다.

영향 조건과 반복 위험

영향 범위는 @fastify/multipart 3.0.0 이상 10.1.1 미만입니다. 애플리케이션이 신뢰할 수 없는 사용자의 요청을 받는 경로에서 request.saveRequestFiles()를 호출하고, 한 요청에 둘 이상의 파트를 허용할 때 공격 조건이 갖춰집니다. 인증이 없는 업로드 경로라면 공격 비용은 더 낮아집니다. 반대로 스트림을 직접 소비하고 자체 저장·정리 수명주기를 구현했거나 saveRequestFiles()를 쓰지 않는 경로는 권고문에 기술된 취약 흐름과 구분해 볼 수 있습니다.

이 문제는 한 번의 큰 파일이 아니라, 요청 실패 뒤 남는 작은 파일을 반복해서 쌓는 방식으로도 운영 용량을 소진시킬 수 있습니다. 임시 디렉터리가 애플리케이션 로그, 컨테이너 쓰기 계층, 다른 서비스의 작업 파일과 같은 볼륨을 공유하면 영향이 업로드 기능에만 머물지 않습니다. 파일 생성 실패, 로그 기록 중단, 프로세스 재시작, 노드 압박이 순차적으로 나타날 수 있으므로 HTTP 오류율과 디스크 사용량을 함께 봐야 합니다. 업로드 요청 수만 세면 정상 실패와 저장 흔적이 남는 실패를 나누기 어렵습니다.

  • 패키지 잠금 파일과 실행 중 컨테이너에서 @fastify/multipart 버전을 각각 확인합니다.
  • saveRequestFiles()를 호출하는 라우트와 한 요청에서 허용하는 파일·필드 수를 목록화합니다.
  • 해당 라우트의 인증 여부, 요청 본문 크기 제한, 동시 연결 제한을 함께 기록합니다.
  • 임시파일 경로가 전용 볼륨인지, 다른 서비스와 용량을 공유하는지 확인합니다.
  • 스테이징에서 두 번째 파트 전송을 중단한 뒤 요청 전후의 임시파일 수와 사용량을 비교합니다.

수정 버전과 임시 대응

Fastify는 @fastify/multipart 10.1.1에서 문제를 수정했습니다. 10.1.0 계열의 수정만 적용된 상태라면 CVE-2025-24033의 후속 불완전 수정에 해당하므로 10.1.1 이상으로 교체해야 합니다. 패키지 관리자에서 직접 의존성만 바꾼 뒤 끝내지 말고, 모노레포·잠금 파일·컨테이너 이미지에 남은 하위 버전을 확인해야 합니다. 여러 서비스가 공통 베이스 이미지를 쓴다면 새 이미지가 실제 배포 대상에 반영됐는지도 구분해 검증하는 편이 안전합니다.

즉시 업그레이드하기 어려운 경우에는 saveRequestFiles()가 거부될 때 request.cleanRequestFiles()를 호출해 요청에 연결된 임시파일을 정리하는 방식을 권고문이 제시합니다. 이 처리는 성공 경로의 정리와 별도로 실패 분기에서 실행돼야 하며, cleanup 자체의 실패도 로그와 경보에 남겨야 합니다. 동시에 업로드 요청 크기와 파트 수를 낮추고, 인증 없는 경로의 동시 요청을 제한하면 디스크 증가 속도를 줄일 수 있습니다. 다만 제한값은 정리 누락을 없애는 수정이 아니므로 패치 일정의 대체재로 취급해서는 안 됩니다.

CVE-2026-18165|OAuth 쿠키 경계가 바뀌는 조건

@fastify/oauth2의 기본 state 검증은 콜백 쿼리의 state 값을 브라우저 쿠키와 비교합니다. PKCE를 켠 경우 verifier도 쿠키에 저장됩니다. 취약한 구성에서는 이 쿠키 이름에 호스트 전용 접두사가 붙지 않아, 같은 등록 가능 도메인 아래의 다른 호스트가 애플리케이션 호스트에 전달될 쿠키를 설정할 수 있습니다. 공격자가 관리하는 서브도메인, 서브도메인 탈취가 가능한 DNS 레코드, XSS가 남아 있는 관련 서비스가 이 경계에 포함될 수 있습니다.

관련 호스트의 쿠키 설정부터 공격자 계정 로그인까지 이어지는 OAuth 로그인 CSRF 흐름
CVE-2026-18165 공격 흐름|관련 호스트가 state와 verifier를 심으면 피해자의 콜백이 공격자 승인 흐름과 결합될 수 있습니다.

로그인 CSRF가 만드는 실제 결과

공격자는 먼저 자신의 OAuth 계정으로 인증 흐름을 시작해 승인에 필요한 값을 준비한 뒤, 관련 호스트에서 피해자 브라우저의 state와 verifier 쿠키를 그 값으로 맞춥니다. 피해자가 조작된 로그인 링크를 열면 콜백 검증은 공격자가 준비한 흐름과 일치하고, 서비스는 피해자 브라우저를 공격자 소유 계정으로 로그인시킬 수 있습니다. 이후 피해자가 입력한 검색어, 업로드 파일, 주소, 주문 정보 같은 행동은 공격자 계정에 저장될 수 있습니다.

이 결과는 피해자의 OAuth 자격 증명이나 기존 계정 토큰을 빼앗는 계정 탈취와는 다릅니다. 보안 권고가 다루는 직접 영향은 피해자가 의도하지 않은 공격자 계정에서 행동하도록 만드는 로그인 CSRF입니다. 운영팀은 로그인 성공 여부만 보지 말고, 로그인 직후 표시되는 계정 식별자와 사용자가 시작한 인증 흐름이 같은 브라우저 세션에 결속됐는지 확인해야 합니다. 금융·문서·파일 공유 서비스처럼 로그인 뒤 민감한 내용을 입력하는 제품에서는 이 맥락 혼동이 데이터 노출로 이어질 수 있습니다.

업그레이드 뒤 필요한 설정

영향 버전은 @fastify/oauth2 7.2.0 이상 8.3.0 미만입니다. 8.3.0은 호스트 접두사 쿠키를 사용할 수 있는 hostPrefixedCookies 옵션을 추가했지만 기본값은 꺼져 있습니다. 따라서 8.3.0 이상으로 올린 뒤 HTTPS 환경에서 이 옵션을 명시적으로 활성화해야 쿠키 이름에 __Host- 접두사가 적용됩니다. __Host- 쿠키는 Secure 속성과 경로 조건을 요구하며 Domain 속성을 허용하지 않아, 형제 서브도메인이 애플리케이션 호스트용 쿠키를 심는 경로를 막습니다. HTTP 개발 환경과 실제 HTTPS 배포 환경의 동작 차이도 배포 전 시험해야 합니다.

  • @fastify/oauth2를 8.3.0 이상으로 올리고 hostPrefixedCookies를 활성화합니다.
  • 프록시 뒤에서 실행한다면 애플리케이션이 HTTPS 원본 요청을 올바르게 인식하는지 점검합니다.
  • 브라우저 개발자 도구에서 state·verifier 쿠키가 __Host- 접두사, Secure, Path=/ 조건을 갖추는지 확인합니다.
  • 등록 가능 도메인 아래의 운영·개발·중단된 서브도메인을 함께 조사하고, 미사용 DNS와 외부 SaaS 연결을 정리합니다.
  • 기존 버전을 유지해야 한다면 generateStateFunction과 checkStateFunction으로 state를 서버 측 세션에 결속하는 설계를 검토합니다.

PKCE만으로 막히지 않는 이유

PKCE는 인증 코드를 교환하는 클라이언트가 처음 요청을 만든 주체와 같은지 검증하는 장치입니다. 하지만 verifier 자체가 공격자가 바꿀 수 있는 일반 쿠키에 저장되면, state와 verifier를 한 세트로 심어 브라우저 흐름을 공격자 세션에 맞출 수 있습니다. PKCE를 켰다는 사실만으로 로그인 CSRF 대응을 완료했다고 판단하면 안 되는 이유입니다. state를 서버 측에 저장하고 브라우저 세션과 결속하는 구성은 쿠키 주입에 의존하지 않으므로, 복수 서브도메인을 운영하는 조직에서 추가 방어선으로 사용할 수 있습니다.

배포 순서와 검증 항목

Fastify 두 취약점의 패키지·업로드 정리·HTTPS·쿠키·서브도메인 배포 점검 순서
배포 전 확인 순서|multipart는 패치와 실패 정리를, oauth2는 업그레이드와 호스트 접두사 쿠키를 함께 검증합니다.
  1. 의존성 인벤토리: package.json만 보지 않고 잠금 파일, 빌드 산출물, 실행 중 이미지에서 두 Fastify 플러그인의 실제 버전을 확인합니다.
  2. multipart 배포: @fastify/multipart 10.1.1 이상을 적용하고, 중단된 다중 파트 요청 뒤 임시파일 수와 디스크 사용량이 원래 수준으로 돌아오는지 스테이징에서 검증합니다.
  3. OAuth 배포: @fastify/oauth2 8.3.0 이상과 hostPrefixedCookies 활성화를 한 변경 묶음으로 적용하고, HTTPS에서 발급된 쿠키 속성을 브라우저로 검사합니다.
  4. 도메인 경계: 동일 등록 가능 도메인의 모든 서브도메인과 외부 서비스 연결을 인벤토리에 넣고, 미사용 CNAME·만료된 호스팅·테스트 서버를 제거합니다.
  5. 운영 관찰: 배포 뒤 임시 디렉터리 증가율, 업로드 실패율, OAuth state 불일치, 로그인 직후 계정 변경 문의를 대시보드와 경보 항목에 반영합니다.

운영팀이 남겨야 할 확인 기록

변경 이력에는 패키지 버전뿐 아니라 multipart 라우트의 정리 분기와 oauth2의 쿠키 옵션 값을 함께 남겨야 합니다. 재배포 시 기본 설정으로 되돌아가는 문제를 막으려면 통합 테스트가 실패 조건을 직접 확인하도록 구성하는 편이 좋습니다. 업로드 테스트는 첫 파일이 저장된 뒤 다음 파트 연결을 끊고 임시 디렉터리가 정리되는지 비교합니다. OAuth 테스트는 관련 호스트에서 같은 이름의 쿠키를 설정하려 해도 애플리케이션의 __Host- 쿠키가 대체되지 않는지 확인합니다.

국내에서 Fastify를 사용하는 조직도 공개 서비스의 언어와 관계없이 동일한 패키지·브라우저 쿠키 조건의 영향을 받습니다. 특히 여러 브랜드·개발 환경·고객 전용 호스트를 한 도메인 아래 운영하는 구조에서는 보안팀만으로 서브도메인 소유권을 판단하기 어렵습니다. 플랫폼팀, DNS 관리자, 서비스 담당자가 같은 목록을 기준으로 사용 중인 호스트와 폐기 대상을 구분해야 합니다. 파일 업로드 기능도 애플리케이션 코드와 컨테이너 볼륨 설정을 함께 확인해야 실제 잔여 파일 경로를 찾을 수 있습니다.

우선순위는 인터넷에 노출된 비인증 업로드 라우트와, 다수의 관련 서브도메인을 가진 OAuth 로그인 서비스에 두는 것이 합리적입니다. 한쪽은 디스크 가용성을, 다른 한쪽은 로그인 맥락의 무결성을 훼손합니다. 수정 버전 적용, 옵션 활성화, 실패 조건 재현, 운영 지표 반영까지 이어져야 배포가 마무리됩니다.

확인한 출처

  1. Temporary File Cleanup Bypass in @fastify/multipart Leads to Disk ExhaustionFastify · 공식 자료
  2. OAuth Login CSRF via Cookie Injection in @fastify/oauth2Fastify · 공식 자료
  3. Security AdvisoriesOpenJS Foundation CNA · 공식 자료

시큐포커스 NOW는 위 자료를 바탕으로 내용을 재구성했으며, 원문을 대신하지 않습니다.

독자 의견

의견을 남겨주세요

0

아직 등록된 댓글이 없습니다.

개인정보는 입력하지 마세요.