
오프라인 체커 for Thymeleaf CVE-2026-40477 / CVE-2026-41901 — 두 CVSS 9.0 SSTI 결함 중 어느 것에 노출되었는지, 그리고 사용 중인 버전 라인에 수정 사항이 있는지(3.0.x: 없음) 알려줍니다.
Thymeleaf CVE-2026-40477 / CVE-2026-41901 오프라인 점검 도구 —— 제로 의존성, 단일 jar, 네트워크 불필요.
CVSS 9.0 두 건의 SSTI 우회, 9일 만에 수정판이 두 번 나왔습니다. 먼저 "내가 어느 건에 해당하는가"를 답하고, 그다음 더 곤혹스러운 질문에 답합니다:
내 버전 라인에, 올릴 수 있는 수정판이 있나?
3.1.x는 있습니다(3.1.5.RELEASE로 올리면 끝).
3.0.x 및 이전은 없습니다 —— 그리고 바로 그게 설치 규모가 가장 큰 사용자층입니다.
두 advisory의 영향 범위는 OSV에서 모두 introduced: 0입니다:
curl -s https://api.osv.dev/v1/vulns/GHSA-r4v4-5mwr-2fwr | jq '.affected[0].ranges'
# [{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"3.1.4.RELEASE"}]}]
즉 3.0 라인 전체가 포함되며, 버전별 목록에 3.0.15.RELEASE부터 1.0.0까지 전부 열거되어 있습니다.
그리고 Maven Central에서 3.0 라인은 3.0.15.RELEASE에서 끝나며, 이후 릴리스가 없습니다:
curl -s https://repo1.maven.org/maven2/org/thymeleaf/thymeleaf/maven-metadata.xml \
| grep -o '<version>3\.0\.[^<]*</version>' | tail -1
# <version>3.0.15.RELEASE</version>
두 CVE의 수정판은 모두 3.1 라인에 있습니다. 따라서 3.0.x 사용자에게는 "버전 번호만 바꾸는" 옵션이 없고,
대형 버전 라인 간 마이그레이션만 가능합니다 —— 그리고 3.1은 공식 문서에 명시된 파괴적 변경입니다(공식 ChangeLog.txt의 3.1.0.M1 항목에서 그대로 인용):
- Removed web-API based expression security objects (#request, #response, #session, #servletContext).
- Removed support for Spring 3.x and Spring 4.x.
- Set minimum JDK compatibility level to JDK 8 project-wide (JDK 17 for thymeleaf-spring6).
템플릿에서 ${#request.…} / ${#session.…}을 쓴 적이 있다면, 올리면 바로 오류가 나며, 이 값들은 Controller가 Model에 넣는 방식으로 바꿔야 합니다.
이것은 일정을 잡아야 하는 마이그레이션이지, 버전 번호만 바꾸는 일이 아닙니다.
deps.dev의 의존성 수(2026-09-04 직접 조회, 누구나 재계산 가능):
설치 규모가 가장 큰 단일 버전은 3.0.11.RELEASE로, 3.1 라인 최고치인 3.1.3보다 36% 높지만 같은 라인에서의 해결책이 없습니다.
java -jar thymeleaf-check.jar <디렉터리 또는 jar/war 경로> [--utf8|--gbk]
$ java -jar thymeleaf-check.jar ./target
[CRITICAL] ./target/myapp.war :: BOOT-INF/lib/thymeleaf-3.0.11.RELEASE.jar
아티팩트:thymeleaf 버전 3.0.11.RELEASE(3.0 라인, 근거: MANIFEST(Implementation-Version))
해당: CVE-2026-40477 + CVE-2026-41901
영향받음, 그리고 3.0 라인은 Maven Central에 수정판이 전혀 없음(해당 라인은 3.0.15.RELEASE에서 종료).
종료 코드: 2 = 같은 라인에 수정판이 없는 버전의 아티팩트 발견 · 1 = 영향받지만 같은 라인으로 업그레이드 가능 / 판별 불가 · 0 = 발견 없음 · 3 = 사용법 또는 경로 오류.
CI에 바로 연결할 수 있습니다.
빌드 산출물(target/*.jar, *.war)을 스캔하고, 소스 디렉터리는 스캔하지 마세요.
Thymeleaf는 대부분 spring-boot-starter-thymeleaf를 통해 전이적으로引入되며, starter 자체는 버전을 담지 않습니다 ——
pom에서는 Thymeleaf 버전을 전혀 볼 수 없습니다. 이런 경우 도구는 "pom으로는 판별 불가"라고 명확히 말하며, 없는 것으로 취급하지 않습니다.
신뢰도 순으로 정렬된 세 가지 식별 근거:
Implementation-Version —— jar가 리패키징 도구로 이름이 바뀌어도 인식합니다.
(Thymeleaf 공식 jar의 META-INF/ 아래에는 MANIFEST.MF만 있고 maven/ 디렉터리는 없으므로, 이것이 가장 확실한 근거입니다.)pom.propertiesfat jar / war 내부의 BOOT-INF/lib/, WEB-INF/lib/는 분해해서 하나씩 확인하며, 내장 jar의 MANIFEST도 읽습니다.
두 번째 건의 영향 범위는 3.1.4를 포함하므로, 첫 번째 advisory에 따라 3.1.4로 올린 사람들은 두 번째 건에 해당합니다.
하지만 이것을 "공식이 제대로 수정하지 않았다"로 읽지 마세요 —— 두 advisory는 서로 다른 메커니즘을 설명하며,
3.1.4(2026-04-12)와 3.1.5(2026-04-21) 두 공식 버전은 9일 차이이고,
이전 수정이 불완전하다는 공식 문구는 없습니다. 이 도구는 사실을 나란히 제시할 뿐, 그 결론을 대신 내리지 않습니다.
RuleTable.java의 모든 숫자는 거슬러 검증할 수 있습니다:
python tools/gen_rules.py --show
이 스크립트는 두 가지 1차 소스로 판정표를 대조합니다 —— OSV의 영향 범위 및 버전별 목록, Maven Central의
maven-metadata.xml —— 불일치가 있으면 0이 아닌 코드로 종료합니다.
세 가지 원칙:
mvn package # JDK 17;target/thymeleaf-check-0.1.0.jar
mvn test # 19개 테스트 케이스
런타임 제로 의존성은 의도적입니다: 점검 도구는 어떤 환경에든 던져 넣고 바로 실행할 수 있어야 합니다.
Apache-2.0
| 버전 | 의존성 수 | 해당 CVE | 같은 라인으로 업그레이드 가능? |
|---|
| 3.0.11.RELEASE | 1124 | 두 건 | ❌ 3.0 라인에 수정판 없음 |
| 3.0.15.RELEASE | 678 | 두 건 | ❌ 위와 동일, 이미 해당 라인의 종점 |
| 3.0.12.RELEASE | 641 | 두 건 | ❌ |
| 3.1.3.RELEASE | 826 | 두 건 | ✅ 3.1.5로 업그레이드 |
| 3.1.2.RELEASE | 677 | 두 건 | ✅ |
| 3.1.4.RELEASE | 70 | CVE-2026-41901만 해당 | ✅ |
| 3.1.5.RELEASE | 590 | — | 이미 안전 |
CVE-2026-40477 | CVE-2026-41901 |
|---|
| GHSA | GHSA-r4v4-5mwr-2fwr | GHSA-c9ph-gxww-7744 |
| CVSS | 9.0 | 9.0 |
| 영향 범위 | <= 3.1.3.RELEASE | <= 3.1.4.RELEASE |
| 수정 | 3.1.4.RELEASE | 3.1.5.RELEASE |
| 공개일 | 2026-04-15 | 2026-05-04 |
| 공식 원문 | "fails to properly restrict the scope of accessible objects" | "fails to properly neutralize specific constructs", sandboxed (restricted) 컨텍스트에서 발생 |