초록
공개 CVE-2025-66478 는 최신 웹 애플리케이션 보안의 중요한 변곡점이 될 것입니다. Next.js와 같은 프레임워크가 다음을 사용하여 클라이언트와 서버의 경계를 허물고 있기 때문에 서버 작업기존 보안 모델이 해결하지 못하는 새로운 공격 표면을 소개합니다. 이 취약점은 단순한 인젝션 결함이 아니라 안전하지 않은 역직렬화에서 비롯된 정교한 로직 버그로, 다음과 같은 공격이 가능합니다. 프로토타입 오염로 에스컬레이션할 수 있습니다. 원격 코드 실행(RCE) 특정 조건 하에서.
이 최종 가이드는 기본적인 권고 사항을 뛰어넘는 내용을 담고 있습니다. JavaScript 런타임 수준에서 취약점을 분석하고, 위험을 야기하는 정확한 코드 패턴을 분석하고, WAF와 같은 경계 방어가 효과가 없는 이유를 설명하고, 다음과 같이 개척한 AI 기반 상황 인식 유효성 검사가 어떻게 작동하는지 설명합니다. 펜리전트이 새로운 패러다임을 확보하는 데 필요합니다.
새로운 개척지: 서버 액션과 직렬화 위험
Next.js 서버 액션('서버 사용')는 개발자가 클라이언트 측 구성 요소에서 직접 서버 측 함수를 호출할 수 있게 함으로써 풀스택 개발에 혁신을 가져왔습니다. 이러한 원활한 환경은 네트워크 경계를 넘어 데이터 양식, 개체, 클로저를 통합하는 복잡한 내부 직렬화 메커니즘을 기반으로 합니다.
그러나 편리함에는 종종 보안이 희생되기도 합니다. CVE-2025-66478은 이 하이드레이션 프로세스 중에 Next.js가 신뢰할 수 없는 입력을 처리하는 방식에 근본적인 결함이 있음을 드러냅니다. 이 프레임워크는 들어오는 객체의 구조를 암묵적으로 신뢰하여 공격자가 기본 JavaScript 객체 속성을 조작할 수 있도록 허용했습니다.
결함의 해부학: 프로토타입 오염에서 RCE까지
CVE-2025-66478의 핵심은 다음과 같습니다. 프로토타입 오염 요청 데이터를 서버 작업 인수에 바인딩하는 동안 활성화된 취약점입니다.
메커니즘: 안전하지 않은 재귀 병합
자바스크립트의 동적 특성 덕분에 객체는 프로토타입에서 프로퍼티를 상속할 수 있습니다. 루트 프로토타입은 Object.prototype. 공격자가 이 루트 프로토타입을 수정할 수 있으면 실행 중인 애플리케이션 인스턴스의 모든 개체가 해당 수정 사항을 상속받습니다.
이 취약점은 서버 액션이 복잡한 데이터 구조(예: 중첩된 JSON 또는 특별히 제작된 FormData)와 프레임워크 또는 액션 내의 개발자 코드가 안전하지 않은 재귀적 병합 또는 할당을 수행합니다.
공격 벡터:
공격자는 다음과 같은 특수 속성 키를 사용하여 오브젝트 프로토타입 체인을 통과하도록 설계된 조작된 페이로드를 제출합니다. proto생성자 또는 프로토타입을 사용합니다.
JSON
// 서버 액션으로 전송된 개념적 공격 페이로드 { "userUpdate": { "__proto__": { "isAdmin": true, "execPath": "/bin/sh" // 잠재적 RCE를 위한 가젯 } } }
서버 측 로직이 순진하게 이것을 병합하는 경우 사용자 업데이트 객체를 기존 사용자 객체 또는 구성 블록에 추가하면 __proto__ 키는 데이터 필드가 아니라 대상 객체의 프로토타입을 수정하는 명령으로 해석됩니다.
에스컬레이션: RCE 가젯 체인
프로토타입 오염은 최종 목표가 아니라 조력자에 불과합니다. 하드코어 보안 엔지니어에게 중요한 질문은 다음과 같습니다: "오염을 실행으로 바꾸려면 어떻게 해야 할까요?"
이를 위해서는 애플리케이션 또는 애플리케이션의 종속성 내에서 미리 정의된 프로퍼티를 위험한 방식으로 사용하는 합법적인 코드 조각인 '가젯'을 찾아야 합니다. 공격자는 해당 프로퍼티를 전역적으로 오염시킴으로써 가젯의 동작을 제어합니다.
Node.js의 RCE 시나리오 예시:
child_process.spawn() 또는 이와 유사한 유틸리티를 사용하여 가끔 자식 프로세스를 생성하는 백엔드 프로세스를 생각해 보세요. 이러한 유틸리티는 종종 shell, env 또는 execPath와 같은 속성을 찾을 수 있는 옵션 객체를 받습니다.
- 오염: 공격자는 서버 동작에서 CVE-2025-66478을 사용하여 다음을 오염시킵니다.
Object.prototype.shell와 같은 값으로/bin/sh또는cmd.exe. - 트리거: 나중에 애플리케이션의 다른 곳에서 완전히 관련 없는 함수가 호출됩니다.
spawn('ls', ['-la'], {}). - 실행: 옵션 객체가
{}는 오염된 프로토타입을 상속합니다,스폰본다{ shell: '/bin/sh' }. 이제 명령이 셸 내에서 실행되므로 인수를 통해 명령을 삽입할 수 있습니다.
이 에스컬레이션 경로는 CVE-2025-66478이 위험 등급을 받은 이유를 강조합니다. 데이터 처리 오류를 전체 서버 손상으로 전환합니다.
개발자의 딜레마: 취약한 코드 패턴 대 안전한 코드 패턴
이 취약점을 식별하려면 객체 연산에서 사용자 입력을 너무 암묵적으로 신뢰하는 특정 '코드 냄새'를 찾아야 합니다.
안티 패턴(취약한 코드)
가장 흔한 실수는 직접 변환하는 것입니다. FormData 또는 유효성 검사되지 않은 JSON을 개체로 변환하여 딥 병합을 수행하는 함수나 개체 구조에 의존하는 데이터베이스 연산에 전달합니다.
자바스크립트
`// 앱/액션/사용자.js '서버 사용'
import { db } from '@/lib/db'; // 코드베이스에서 흔히 볼 수 있는 일반적이고 안전하지 않은 딥 병합 유틸리티 import { deepMerge } from '@/utils/genericHelpers';
export async 함수 updateProfileSettings(formData) { // 위험: 신뢰할 수 없는 FormData를 객체로 직접 변환 const rawInput = Object.fromEntries(formData);
// getCurrentConfig()가 기본 구성 객체를 반환한다고 가정합니다.
const currentConfig = await db.config.findFirst();
// 취약점 트리거:
// deepMerge가 __proto__를 명시적으로 차단하지 않는 경우,
// 공격자가 기본 구성 객체 유형을 오염시킬 수 있습니다.
const newConfig = deepMerge({}, currentConfig, rawInput);
// 오염된 구성은 저장되거나 위험한 방식으로 사용됩니다.
await db.user.update({
where: { id: rawInput.userId },
data: { settings: newConfig }
});
}`
보안 패턴(조드 방패)
대량 할당 및 프로토타입 오염 공격에 대한 유일한 강력한 방어는 다음과 같습니다. 엄격한 스키마 기반 유효성 검사. 같은 라이브러리 Zod 는 애플리케이션 로직의 방화벽 역할을 하여 허용된 속성의 화이트리스트를 생성하고 다른 모든 속성을 제거합니다.
자바스크립트
`// 앱/액션/사용자.js '서버 사용'
'zod'에서 { z } import; '@/lib/db'에서 { db } import;
// DEFENSE: 엄격한 스키마를 정의합니다. 이 키만 통과합니다. // 어떤 'proto' 또는 알 수 없는 키는 자동으로 제거됩니다. const ProfileSettingsSchema = z.object({ userId: z.string().uuid(), theme: z.enum(['light', 'dark', 'system']), notificationsEnabled: z.boolean(), metadata: z.object({ bio: z.string().max(280).optional(), website: z.string().url().optional() }).strict() // .strict() 금지 중첩된 개체에서 알려지지 않은 키 });
export async 함수 updateProfileSettings(formData) { // 1단계: 구문 분석 및 유효성 검사 // safeParse는 성공하면 입력된 깨끗한 객체를 반환하고, 실패하면 오류를 반환합니다. const parseResult = ProfileSettingsSchema.safeParse( Object.fromEntries(formData) );
if (!parseResult.success) {
// 내부 구조를 노출하지 않고 잘못된 입력을 우아하게 처리합니다.
console.error('유효성 검사 실패:', parseResult.error);
새로운 오류('잘못된 요청 데이터')를 던집니다;
}
// 2단계: 위생 처리된 데이터 사용
// parseResult.data는 정의된 키만 포함하도록 보장합니다.
await db.user.update({
where: { id: parseResult.data.userId },
data: {
theme: parseResult.data.theme,
알림: parseResult.data.notificationsEnabled,
메타데이터: parseResult.data.metadata
}
});
}`

기존 보안 계층이 실패하는 이유
많은 조직이 기존의 경계 방어가 CVE-2025-66478을 탐지할 수 있다고 잘못 생각합니다. 이 가정은 위험합니다.
WAF 블라인드와 비행 프로토콜
웹 애플리케이션 방화벽(WAF)은 일반적으로 URL 매개변수 및 JSON 본문과 같은 표준 HTTP 요소에 대한 정규식 일치를 기반으로 작동하며, SQLi(' 또는 1=1) 또는 XSS(<script>) 서명.
그러나 Next.js 서버 액션은 다음을 사용하여 통신합니다. 비행 프로토콜-텍스트와 바이너리 데이터의 복잡한 스트리밍 하이브리드입니다. 악성 페이로드는 멀티파트/폼 데이터 요청 내에 깊숙이 중첩되거나 직렬화되어 __proto__ 키가 있는지 확인합니다. Next.js 직렬화 형식을 특별히 이해하지 못하는 WAF는 정상 트래픽을 보게 됩니다.
시맨틱 갭
또한 다음과 같은 페이로드는 {"생성자": {"프로토타입": {"isAdmin": true}}} 은 구문적으로 유효한 JSON입니다. WAF는 이 요청이 복잡한 구성 개체를 업데이트하기 위한 합법적인 요청인지, 아니면 공격인지 판단할 수 없습니다. 이를 위해서는 다음이 필요합니다. 시맨틱 이해 의 애플리케이션 로직이 부족합니다.
고급 검증: 펜리전트를 통한 AI 기반 접근 방식
수동 감사와 기존 도구의 한계를 고려할 때 새로운 접근 방식이 필요합니다. 펜리전트 는 애플리케이션 컨텍스트를 이해하도록 설계된 AI 기반 침투 테스트 엔진을 활용합니다.
정적 분석 그 이상: 컨텍스트 인식 퍼징
기존의 정적 애플리케이션 보안 테스트(SAST) 도구는 자바스크립트의 동적 특성으로 인해 너무 많은 오탐을 발생시키거나 서버 동작 경계를 가로지르는 복잡한 데이터 흐름을 놓치는 경우가 많습니다.
펜리전트의 AI 엔진은 애플리케이션의 AST(추상 구문 트리)를 분석하여 식별합니다:
- 출처: 표시된 기능
'서버 사용'. - 싱크대: 객체 병합, 데이터베이스 쓰기 또는 명령 실행과 같은 위험한 작업.
- 데이터 흐름: 신뢰할 수 없는 입력이 소스에서 싱크까지 이동하는 경로입니다.
이러한 맥락을 이해함으로써 Penligent는 식별된 데이터 경로에서 프로토타입 오염을 테스트하기 위해 특별히 설계된 타겟 퍼징 페이로드를 생성합니다.
비파괴 개념 증명(안전 PoC)
프로덕션 중단 없이 취약점이 존재한다는 것을 증명하는 것이 가장 중요합니다. 펜리전트는 "안전한 PoC" 방법론을 사용합니다.
펜리전트 에이전트는 RCE를 시도하거나 애플리케이션 상태를 방해하는 대신 양성, 일시적 속성을 오염시키려고 시도합니다.
- 액션: 에이전트가 페이로드를 서버 액션으로 보냅니다:
{"__proto__": {"penligent_validation_flag_{unique_id}": true}}. - 인증: 그런 다음 에이전트는 다른 엔드포인트에 후속 요청을 하고 응답 데이터에 전역적으로 오염된 플래그가 나타나는지 확인합니다.
- 결과: 플래그가 존재하면 100% 확실성으로 취약점이 확인되며 비즈니스에 미치는 영향은 없습니다.
펜리전트 인사이트: "최신 웹 아키텍처에서 보안은 네트워크 수준 차단에서 애플리케이션 수준 로직 유효성 검사로 전환되어야 합니다. AI는 이러한 격차를 해소할 수 있는 유일한 확장 가능한 방법입니다."
최종 해결 체크리스트
개발자 보안 팀과 아키텍트의 경우, Next.js 환경을 보호하기 위해 즉각적인 조치가 필요합니다.
- 즉시 패치: 모든 Next.js 인스턴스를 다음과 같이 업그레이드합니다. v15.0.4+ 또는 v14.2.16+. 공식 패치에는 시리얼라이즈 중 특정 유형의 프로퍼티 중독에 대한 프레임워크 수준의 강화가 포함되어 있습니다.
- 스키마 유효성 검사 적용: 다음과 같은 정책을 채택합니다. 모든 서버 작업은 Zod, Yup 또는 Valibot을 사용하여 엄격한 입력 유효성 검사로 시작해야 합니다. 코드 검토에서 유효성이 검사되지 않은 입력은 심각한 보안 위반으로 취급하세요.
- 방어 코딩:
- 사용자 입력에 일반적인 '딥 병합' 기능을 사용하지 마세요.
- 병합보다는 명시적 속성을 가진 새 개체를 만드는 것을 선호합니다:
const newData = { prop1: input.prop1, prop2: input.prop2 }; - 다음을 사용하는 것이 좋습니다.
Object.create(null)를 사용하여 사용자 입력을 저장할 객체에 프로토타입이 없는지 확인합니다.
- 런타임 강화(핵 옵션): 마지막 방어선으로 애플리케이션 시작 시 객체 프로토타입을 고정할 수 있습니다. 이렇게 하면 프로토타입 수정에 의존하는 타사 라이브러리가 손상될 수 있습니다.
// instrumentation.js 또는 루트 레이아웃에서 if (process.env.NODE_ENV === 'production') { Object.freeze(Object.protype); Object.freeze(Array.protype); }
참조 및 권한 링크:

