Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
rewrite-cve-2026-22732 — OpenRewrite 레시피로, Content-Length 헤더 오용을 식별하고 즉시 헤더 작성 구성을 생성하여 Spring Security 헤더 억제(CVE-2026-22732)를 탐지하고 수정합니다. | Kitploit
도구/GitHubGitHub/moderneinc/rewrite-cve-2026-22732
Static AnalysisVulnerability AnalysisCode AnalysisWeb SecurityDevSecOps
GitHubmoderneinc/rewrite-cve-2026-22732

rewrite-cve-2026-22732

OpenRewrite 레시피로, Content-Length 헤더 오용을 식별하고 즉시 헤더 작성 구성을 생성하여 Spring Security 헤더 억제(CVE-2026-22732)를 탐지하고 수정합니다.

저장소 보기

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
9시간 17분 전아직 검토되지 않음
공유

rewrite-cve-2026-22732

CVE-2026-22732에 취약한 코드를 탐지하는 OpenRewrite 레시피입니다. 이는 세 가지 응답 메서드 중 하나를 통해 Content-Length를 설정하면 Spring Security의 OnCommittedResponseWrapper를 우회하는 Spring Security 결함입니다. 래퍼가 헤더를 인식하지 못하므로 onResponseCommitted()가 실행되지 않고, 지연 추가되는 보안 헤더(X-Frame-Options, X-Content-Type-Options, Cache-Control 등)가 조용히 누락됩니다.

탐지 대상

취약한 Spring Security 6.4.12 + Spring Boot 3.4.3 / 내장 Tomcat에서 확인된 실제 트리거는 다음과 같습니다:

  1. 래퍼를 우회하는 오버로드를 통한 서블릿 Content-Length

    root@kitploit:~
    response.setHeader("Content-Length", "42");
    response.setIntHeader("Content-Length", 42);
    response.addIntHeader("Content-Length", 42);
    

    이 세 가지 오버로드는 OnCommittedResponseWrapper에서 재정의되지 않습니다. 이후 본문 쓰기가 선언된 길이를 완성하고 컨테이너는 지연 헤더 작성기를 실행하지 않고 커밋합니다.

  2. HttpHeaders를 통한 WebFlux Content-Length

    root@kitploit:~
    serverHttpResponse.getHeaders().set("Content-Length", "42");
    serverHttpResponse.getHeaders().add("Content-Length", "42");
    serverHttpResponse.getHeaders().setContentLength(42L);
    
  3. WebFlux 무조건적 응답 커밋

    root@kitploit:~
    serverHttpResponse.writeWith(Mono.just(dataBuffer));
    serverHttpResponse.writeAndFlushWith(publisher);
    serverHttpResponse.setComplete();
    

이 레시피는 Spring Security 존재 여부(즉, org.springframework.security.* 타입을 참조하지 않는 파일에서는 아무것도 출력하지 않음)와 영향받는 Spring Security 버전 범위에 따라 게이팅됩니다. 2026-03-19에 게시된 Spring 권고에 따르면 영향 범위와 수정 버전은 다음과 같습니다:

해당 시리즈의 수정 버전 이상(또는 7.0 / 6.5 이후의 향후 시리즈)의 Spring Security 버전을 해석하는 프로젝트는 영향받지 않는 것으로 처리되며 싱크 또는 파일별 마커를 받지 않습니다. 버전을 해석할 수 없는 프로젝트는 일반적인 패턴 기반 탐지로 폴백되어 스캐너가 반증할 수 없는 발견을 보고하는 쪽으로 오류를 범합니다. SpringSecurityVersionByProject 데이터 테이블은 여전히 해석된 버전을 기록하고 각 프로젝트를 영향 여부로 플래그하므로 필터링된 내용을 감사할 수 있습니다.

의도적으로 플래그하지 않는 항목

다음은 위험해 보이지만 래퍼가 추적하므로 응답이 커밋되기 전에 보안 헤더가 작성됩니다:

Semgrep 데모의 /vuln/flush 엔드포인트는 flushBuffer()가 트리거라고 주장하지만, 취약한 Spring Security 6.4.12에서 응답은 실제로 여섯 개의 보안 헤더를 모두 반환합니다. 데모의 실제 트리거는 /vuln/stream 및 /vuln/content-length의 setIntHeader("Content-Length", ...) 호출입니다.

탐지

다음을 실행하세요:

레시피용도
io.moderne.recipe.cve202622732.FindSpringSecurityHeaderSuppression모든 탐지를 실행하고 버전 보고 테이블을 출력합니다

구성 요소 (고급)

위의 집계기는 두 개의 더 작은 레시피로 구성됩니다. 하나의 탐지만 원하는 경우 개별적으로 호출할 수 있습니다.

수정

다음을 실행하세요:

레시피용도
io.moderne.recipe.cve202622732.FixSpringSecurityHeaderSuppression각 프로젝트가 실제로 취할 수 있는 가장 저렴한 수정을 선택합니다

두 단계를 순서대로 실행합니다.

1. 프로젝트 자체 시리즈의 수정 버전으로 업그레이드. Spring Security는 수정 버전을 Maven Central에 6.5.9 및 7.0.4로 게시했습니다. 각 업그레이드는 FindAffectedSpringSecuritySeries 사전 조건에 게이팅됩니다. UpgradeDependencyVersion은 대상이 더 새로운 버전인지만 확인하기 때문입니다. 7.0.4로 이동하라고 지시하면 5.8 프로젝트를 두 개의 메이저 버전을 가로질러 끌고 갈 수 있습니다.

2. 1단계에서 수정할 수 없는 항목에 대해 선제적 헤더 작성 구성을 추가. 이는 프로젝트당 하나의 @Configuration 클래스를 생성합니다:

root@kitploit:~
@Bean
public static BeanPostProcessor eagerHeaderWriterFilterBeanPostProcessor() {
    return new BeanPostProcessor() {
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof HeaderWriterFilter) {
                ((HeaderWriterFilter) bean).setShouldWriteHeadersEagerly(true);
            }
            return bean;
        }
    };
}

헤더를 미리 작성하면 래퍼가 커밋을 관찰하는지 여부가 무의미해지므로 프로젝트의 모든 싱크가 한 번에 닫힙니다. 여기에는 "알려진 제한 사항"의 Map 흐름처럼 오염 분석이 도달할 수 없는 싱크도 포함됩니다. BeanPostProcessor는 AutowireBeanFactoryObjectPostProcessor가 빈 팩토리를 통해 필터를 초기화하므로 HttpSecurity DSL로 빌드된 필터를 볼 수 있습니다. 이 CVE에 대해 독립적으로 게시된 두 가지 수정 사항이 정확히 이 형태를 사용합니다(hmcts/idam-web-public 및 armory-io의 Spinnaker 포크는 동등한 ObjectPostProcessor를 통해).

2단계는 1단계가 도울 수 없는 프로젝트를 다룹니다:

상황업그레이드가 작동하지 않는 이유
5.7, 5.8, 6.3, 6.4수정 사항이 Spring Enterprise 구독자에게만 제공됨 — Maven Central에 없음
6.0 - 6.2해당 시리즈에는 수정 버전이 게시된 적 없음
가져온 BOM으로 관리되는 버전업그레이드가 편집할 로컬 선언이 없음

마지막 행은 가장자리 사례가 아닙니다. nla/bamboo는 오픈소스 수정 버전이 있는 시리즈인 7.0.3을 전적으로 Spring Boot BOM에서 해석하므로 버전 확인만으로는 두 단계 모두에서 건너뛰고 취약한 상태로 남게 됩니다. 따라서 AddEagerHeaderWriterConfiguration은 프로젝트에 오픈소스 수정 버전이 있고 자체 버전을 선언한 경우에만 업그레이드에 위임합니다.

생성된 클래스는 @EnableWebSecurity 클래스가 있는 경우 그 옆에 배치되고, 없으면 @SpringBootApplication, 그 다음에는 모든 @Configuration으로 폴백되므로 항상 컴포넌트 스캔이 도달하는 위치에 배치됩니다. 이미 헤더를 선제적으로 작성하는 프로젝트나 패치된 OnCommittedResponseWrapper를 벤더링하는 프로젝트(jogetworkflow/jw-community처럼)는 그대로 둡니다.

구성 요소 (고급)

레시피용도
io.moderne.recipe.cve202622732.UpgradeSpringSecurityToPatchedVersion시리즈 게이팅된 6.5.9 / 7.0.4 업그레이드
io.moderne.recipe.cve202622732.AddEagerHeaderWriterConfiguration생성된 구성 자체
io.moderne.recipe.cve202622732.FindAffectedSpringSecuritySeries영향받는 시리즈의 프로젝트를 표시합니다. 업그레이드 사전 조건입니다

실행 중인 서버로 검증

취약한 Spring Security 6.4.12의 semgrep/cve-2026-22732-demo에 내장 Tomcat을 대상으로 적용했습니다. 해당 HeaderVerificationTest는 보안 헤더가 누락되었음을 주장하므로 작동하는 수정 사항은 이를 실패하게 만듭니다:

X-Frame-Options 및 Cache-Control도 동일한 패턴을 따릅니다.

빌드되는 코퍼스의 16개 저장소(식별된 29개 중)에서 수정 사항은 세 개에 대한 구성을 생성하고 나머지는 올바르게 그대로 두었습니다:

세 개의 패치된 저장소에 수정 사항을 다시 실행하면 추가 생성이 없으므로 수정은 실제 프로젝트에서 자체 출력에 대해 멱등적입니다.

두 번째 더 넓은 코퍼스는 수정 사항이 실제로 다루는 모집단(싱크가 필요 없으므로 영향받는 모든 서블릿 Spring Security 애플리케이션)을 대상으로 합니다. 코드 검색으로 찾은 64개 프로젝트 중 52개가 빌드되었고, 48개가 영향받는 버전을 해석했으며, 38개가 패치되었고 그중 35개가 컴파일됩니다(나머지 3개는 생성된 파일 없이도 동일하게 실패). Spring Security 5.2 미만의 8개 프로젝트는 모두 올바르게 건너뛰었습니다. SUSCEPTIBLE-REPOSITORIES.md 섹션 8을 참조하세요.

제한 사항

  • WebFlux 탐지는 이 CVE가 아닌 다른 위험입니다. OnCommittedResponseWrapper extends jakarta.servlet.http.HttpServletResponseWrapper이므로 CVE-2026-22732는 서블릿 전용이며 리액티브 애플리케이션은 이에 노출되지 않습니다. FindHttpResponseContentLengthOrFlushBuffer의 발견은 유사한 리액티브 패턴을 플래그하며 여전히 수동 검토가 필요하지만 수정 사항은 의도적으로 이에 대해 조치하지 않습니다. AddEagerHeaderWriterConfiguration은 뒤에 서블릿 API 없이 HeaderWriterFilter를 볼 수 있는 모든 모듈을 건너뜁니다. 필터는 OncePerRequestFilter를 확장하고 spring-security-web은 서블릿 API를 비전이적 provided 종속성으로 포함하므로 거기서 생성하면 cannot access jakarta.servlet.Filter로 실패합니다(apache/shenyu에서 관찰됨).
  • Spring Security 5.2 미만 버전은 탐지되지만 수정되지 않습니다. HeaderWriterFilter.setShouldWriteHeadersEagerly는 5.2에서 도입됩니다. 4.0.4에서 필터에는 생성자와 doFilterInternal만 있습니다. 탐지는 여전히 EOL 버전을 보고하지만 컴파일할 수 없는 호출을 출력하는 대신 수정이 보류됩니다.

데이터 테이블

테이블행
TaintFlowTable (rewrite-program-analysis에서)Content-Length 헤더 오염 적중당 한 행
HttpResponseDirectCommitTableWebFlux 구조적 적중당 한 행
SpringSecurityVersionByProject탐지된 Spring Security 버전이 있는 프로젝트당 한 행

실행

Moderne CLI를 통해:

root@kitploit:~
mod run . --recipe io.moderne.recipe.cve202622732.FindSpringSecurityHeaderSuppression

rewrite.yml을 통해:

root@kitploit:~
---
type: specs.openrewrite.org/v1beta/recipe
name: com.example.DetectSpringSecurityHeaderSuppression
displayName: Detect CVE-2026-22732
recipeList:
  - io.moderne.recipe.cve202622732.FindSpringSecurityHeaderSuppression

평가 코퍼스 재현

repos.csv는 이 레시피가 개발되고 측정된 75개의 공개 저장소를 각각 평가된 정확한 커밋에 고정하여 나열합니다. 여러 저장소는 활발히 유지 관리되며 업스트림에서 패치될 예정이므로 changeset 열이 아래 숫자를 단순히 그럴듯하게 만드는 것이 아니라 재현 가능하게 만듭니다.

root@kitploit:~
mod git sync csv ./corpus repos.csv --with-sources
mod build ./corpus
mod run ./corpus --recipe=io.moderne.recipe.cve202622732.CveDevCenter
mod devcenter ./corpus --last-recipe-run

동기화는 약 20초와 1.4GB가 걸리고, 빌드는 약 15분이 걸리며 유일하게 느린 단계입니다. mod devcenter는 corpus/.moderne/run/<runId>/에 devcenter.html을 작성하고 조직 하위 디렉터리당 하나씩 추가로 작성합니다.

org1 열은 각 저장소가 존재하는 이유를 반영하는 그룹으로 코퍼스를 분할합니다. 두 가지 취약한 호출 형태에 대한 Servlet Sinks 및 WebFlux Sinks, 이미 업스트림에서 수정된 저장소에 대한 Patched, Spring Security 자체 및 기타 비소비자에 대한 Reference, 실행 중인 서버에 대해 확인된 사례에 대한 Verified, 빌드 도구 범위에 대한 Gradle, 대량 샘플에 대한 Wide입니다.

고정된 커밋에서 기대할 수 있는 결과:

결과
업그레이드 카드메이저 39, 마이너 21, 패치 6, 완료 4 (저장소 70개)
보안 카드노출된 저장소 65개
해당 없음Spring Security 종속성을 해석하지 않는 저장소 5개

그 다섯 개 중 네 개는 실제로 Spring Security를 사용하지 않습니다. spring-projects/spring-security는 라이브러리 자체이고, JoeyBling/bootplus는 Apache Shiro를 사용하며, jenkinsci/stapler는 서블릿 API를 직접 대상으로 하고, infofabrik/reportserver에는 해석할 Maven 또는 Gradle 빌드가 없습니다. 다섯 번째인 xtuer/template-app은 spring-security-web:5.0.0.RELEASE를 선언하지만 해당 Gradle 빌드는 mod build 중에 종속성을 전혀 해석하지 않으므로 어떤 레시피도 버전을 볼 수 없습니다. 영향받지 않는 것이 아니라 측정되지 않은 것으로 취급하세요.

수정 사항을 적용하고 결과를 확인하려면:

root@kitploit:~
mod run ./corpus --recipe=io.moderne.recipe.cve202622732.FixSpringSecurityHeaderSuppression
mod git apply ./corpus --last-recipe-run
mod exec ./corpus --last-recipe-run MODERNE_BUILD_TOOL_CHECK

mod git apply는 체크아웃에 직접 작성합니다. 코퍼스 전체에 대한 전체 check는 느리며 이 변경과 무관한 실패(누락된 JDK 툴체인, 도달할 수 없는 종속성 저장소, 이미 빨간 테스트)를 표면화하므로 의미 있는 신호는 적용 전에 동일한 명령을 실행한 것과의 델타입니다.

리터럴 데모 이상으로 다루는 내용

rewrite-program-analysis의 오염 분석은 로컬 데이터 흐름과 메서드별 요약을 처리하므로 다음 패턴이 자동으로 탐지됩니다:

  • 상수 전파된 Content-Length 헤더 이름. String h = "Content-Length"; response.setIntHeader(h, 42);가 플래그됩니다. 프레임워크가 로컬 할당을 통해 리터럴 오염을 추적합니다.
  • 호출을 래핑하는 헬퍼 — 메서드 요약을 통해 반환 값을 통해 오염이 흐릅니다.

알려진 제한 사항

  • 제네릭 컨테이너 타입을 통한 흐름(Map, List, 사용자 정의 컬렉션). stash.put("k", "Content-Length") 다음에 response.setIntHeader(stash.get("k"), 42)가 오는 경우는 탐지되지 않습니다. put/get의 동일성은 분석에 불투명합니다.

라이선스

Moderne 독점. 상업 계약 조건에 따라 Moderne 고객만 사용할 수 있습니다.

도구 다운로드
시리즈영향 범위수정 버전
5.7.x5.7.0 – 5.7.215.7.22 (엔터프라이즈)
5.8.x5.8.0 – 5.8.235.8.24 (엔터프라이즈)
6.3.x6.3.0 – 6.3.146.3.15 (엔터프라이즈)
6.4.x6.4.0 – 6.4.146.4.15 (엔터프라이즈)
6.5.x6.5.0 – 6.5.86.5.9 (OSS)
7.0.x7.0.0 – 7.0.37.0.4 (OSS)
코드안전한 이유
response.setContentLength(int) / setContentLengthLong(long)재정의됨 — 래퍼가 선언된 길이를 기록하고 본문이 완료되면 onResponseCommitted()를 실행합니다.
response.flushBuffer()재정의됨 — super.flushBuffer() 이전에 doOnResponseCommitted()를 호출합니다.
response.getOutputStream().write(..) / flush() / close()SaveContextServletOutputStream을 반환합니다. 모든 쓰기/플러시/닫기는 위임 전에 doOnResponseCommitted()를 실행합니다.
response.getWriter().write(..) / print(..) / println(..) / flush() / close()SaveContextPrintWriter를 반환합니다. 동일한 패턴입니다.
response.addHeader("Content-Length", v)래퍼에서 특수 처리됨 — setContentLength(long)을 통해 라우팅됩니다.
레시피용도
io.moderne.recipe.cve202622732.FindHttpResponseContentLengthHeadersetHeader / setIntHeader / addIntHeader(서블릿) 또는 HttpHeaders.set / add(WebFlux)에 도달하는 "Content-Length" 리터럴에 대한 오염 흐름
io.moderne.recipe.cve202622732.FindHttpResponseContentLengthOrFlushBufferWebFlux 무조건적 커밋: writeWith, writeAndFlushWith, setComplete, HttpHeaders.setContentLength
엔드포인트수정 전수정 후
/vuln/streamX-Content-Type-Options: nullnosniff
/vuln/content-lengthX-Content-Type-Options: nullnosniff
/safenosniffnosniff
저장소결과
semgrep/cve-2026-22732-demo@EnableWebSecurity 옆의 com/example/vuln에 생성됨. 컴파일되고 헤더가 복원됨
nla/bamboo@SpringBootApplication 옆의 ui/src/bamboo에 생성됨. 컴파일됨. 업그레이드가 도달할 수 없는 BOM 관리 7.0.3 사례
star-whale/starwhale@EnableWebSecurity 옆의 ai/starwhale/mlops/configuration/security에 생성됨. 컴파일됨(선언된 대상인 JDK 11)
hmcts/idam-web-public그대로 둠 — 이미 setShouldWriteHeadersEagerly 호출
okta/okta-idx-java (6.5.9), psi-probe (6.5.11), Ant-Media-Server (6.5.11)그대로 둠 — 해당 시리즈의 수정 버전 이후
apache/shenyu (6.3.1)그대로 둠 — 리액티브 전용. HeaderWriterFilter 뒤에 서블릿 API가 없고 CVE는 서블릿 전용
brutusin/Brutusin-RPC (4.0.4)그대로 둠 — setShouldWriteHeadersEagerly(5.2) 이전
bootplus, template-app, front50, igor, rosco, spring-security, reportserver그대로 둠 — 영향받는 Spring Security 버전이 해석되지 않음
  • 모든 요청에 대해 선제적 헤더가 작성됩니다. 나중에 오류 디스패치로 대체되는 요청도 포함됩니다. 이는 Spring Security의 지연 기본값이 피하는 트레이드오프이며 업그레이드가 먼저 실행되는 이유입니다.