
실제 설치된 Apache Shiro 모듈과 버전을 스캔해 공식 CVE 26개 중 실제로 해당되는 항목을 하나씩 판정합니다. 「CVE × 모듈」 기준으로 판정하며, 제로 의존성 단일 jar입니다. CVE-2026-49268
실제로 설치된 Apache Shiro 모듈과 버전을 스캔하여, 공식 26개 CVE 중 어떤 것이 실제로 당신에게 해당되는지 항목별로 판정합니다.
의존성 없는 단일 jar, 네트워크 연결 없음, 당신의 pom을 읽지 않음 —— 빌드 산출물(jar / war / fat jar / 디렉터리)을 직접 스캔합니다.
java -jar shiro-check.jar --utf8 your-app.jar
Shiro의 CVE는 「Shiro」에 달려 있는 것이 아니라, 구체적인 모듈에 달려 있습니다. 같은 번호라도 모듈이 다르면 규칙이 다릅니다:
| CVE | 영향받는 모듈 | shiro-core만 사용하는 사람 |
|---|---|---|
| CVE-2020-17510 | shiro-spring | 해당 없음 |
| CVE-2020-17523 | shiro-web / shiro-spring / shiro-spring-boot-starter | 해당 없음 |
| CVE-2023-34478 | shiro-web | 해당 없음 |
| CVE-2026-56091 | shiro-guice | 해당 없음 |
공식 26건 중 13건은 shiro-core를 전혀 건드리지 않습니다. 이것들을 「Shiro < 1.7.1에는 취약점이 있다」라는 한 문장으로 뭉뚱그리는 것은,
사용자가 스스로 해야 할 판단을 대신 해 주는 것 —— 게다가 틀리게 해 주는 것입니다.
이 도구의 판정 단위는 CVE × 모듈입니다: 26건의 CVE가 37개의 규칙으로 전개되어 7개 모듈을 커버합니다.
Dependabot은 종속성 좌표로 GitHub advisory를 매칭합니다. 26개 중 5개가 매칭되지 않습니다:
| 항목 | 매칭되지 않는 이유 |
|---|---|
| CVE-2026-56091(shiro-guice 인증 우회, high) | advisory가 여전히 unreviewed 상태이며, 영향받는 패키지가 비어 있음 |
| CVE-2026-56130(RememberMe 쿠키가 만료되지 않음) | 위와 동일 |
| CVE-2014-0074(LDAP 빈 비밀번호 우회) | 위와 동일 |
| CVE-2023-22602(Spring Boot 2.6+ 인증 우회, high) | advisory가 org.apache.shiro:shiro-root에만 연결됨 |
| CVE-2010-3863 | 위와 동일 |
그런데 shiro-root는 packaging=pom인 부모 POM입니다 —— Maven Central에
해당하는 jar가 없고(HTTP 404),
어떤 프로젝트도 이것에 의존하지 않으므로 좌표 매칭으로는 절대 매칭되지 않습니다.
ℹ️
unreviewed는 GitHub의 정상적인 프로세스 상태입니다(NVD 자동 가져오기, 아직 영향받는 패키지에 대한 수동 표시가 없음). 좌표 매칭도 합리적인 설계입니다. 여기서는 「경고에 들어가지 못한다」는 사실만 서술하는 것이지, 누가 잘못했다는 뜻이 아닙니다.
shiro-all은 여러 모듈을 함께 패키징한 uber jar입니다. 실측 결과 shiro-all-1.3.2.jar 내부에는 6개의
META-INF/maven/org.apache.shiro/<모듈>/pom.properties가 있습니다:
shiro-all shiro-core shiro-web shiro-spring shiro-ehcache shiro-quartz
즉, pom에 shiro-all만 적힌 프로젝트는 좌표层面上 이름이 하나뿐이며
(26개 중 CVE-2016-6802만 이 좌표에 걸려 있음), jar 안에는 실제로 core / web / spring 세 모듈의 코드가 들어 있다.
실물을 스캔하면 이 층을 꿰뚫어 볼 수 있다. 실제로 shiro-all-1.3.2.jar 하나를 테스트한 결과, 이 도구는 3개 모듈에 걸쳐 20개를 보고했다.
3개 advisory의 first_patched_version은 3.0.0-alpha-2인데, 이 버전은 Maven Central에 한 번도 배포된 적이 없다
(공식은 곧바로 3.0.0 정식 버전을 배포했다). 이 버전을 따라 업그레이드하는 것은 불가능하다 —— 이 도구는 이를 표시하고, 업그레이드 제안을
실제로 받을 수 있는 버전으로 바꿔 준다.
「적중」= 이 모듈이 존재하고 버전이 공식 영향 범위 안에 있음. 「이미 악용됨」 또는 「반드시 악용 가능」과 같지 않다.
26개 중 대다수는 특정 설정이 있어야 성립하므로, 도구는 이들을 분리해서 나열한다:
조건 예시(공식 설명 원문과 글자 그대로 대조, 외삽 없음):
CVE-2026-49268 仅当使用 DefaultLdapRealm(用户名未转义即拼进 LDAP DN)
CVE-2023-22602 仅当与 Spring Boot 2.6+ 一起使用,且未把
spring.mvc.pathmatch.matching-strategy 设回 ant_path_matcher
CVE-2026-23903 仅当静态文件放在大小写不敏感的文件系统上(如 macOS 默认设置),
且 Shiro 里只配了小写的 filter 路径;只影响静态文件
🔴 도구는 당신의 설정을 파싱하지 않습니다. shiro.ini / application.yml / Java 코드 어디에서든 Shiro를 설정할 수 있지만, 파싱해서 나온 결론은 파싱하지 않는 것보다 더 위험합니다. 조건은 명시적으로 나열되어 있으며, 판단은 당신이 직접 합니다 — 이는 의도된 설계이지 게으름이 아닙니다.
# 扫一个 jar / war
java -jar shiro-check.jar your-app.jar
# 扫整个目录(递归)
java -jar shiro-check.jar /path/to/libs
# 连「不适用」的条目也列出来
java -jar shiro-check.jar --all your-app.jar
# Windows 控制台中文乱码时
java -jar shiro-check.jar --utf8 your-app.jar
식별 능력: 일반 jar · Spring Boot fat jar(BOOT-INF/lib/) · 전통적 WAR(WEB-INF/lib/) ·
uber jar(shiro-all, 내장 모듈 전개) · 이름이 변경된 jar(pom.properties 기준) ·
백슬래시로 경로를 쓴 기형 아카이브.
**JDK 17+**가 필요합니다. 런타임 의존성 제로.
한 줄도 손으로 베끼지 않았습니다. tools/gen_rules.py가 두 개의 일차 소스에서 생성합니다:
| 출처 | 제공 내용 |
|---|---|
| shiro.apache.org/security-reports.html | 전체 항목 목록, 설명 원문, 트리거 조건 원문 |
| GitHub Advisory API | 영향을 받는 모듈 좌표, 구조화된 버전 범위, 등급 |
생성 과정에는 12개의 단언이 있으며, 하나라도 충족되지 않으면 중단하고 파일을 쓰지 않습니다(「파싱 실패로 빈 껍데기 표가 생성되어도 테스트는 여전히 전부 통과」하는 것을 방지):
발행 전에는 별도로 tools/recheck_before_publish.py가 있으며, 두 번째 독립 기준으로 핵심 논거를 다시 한 번 검증합니다
(생성 스크립트를 import하지 않고 그 출력도 읽지 않음 —— 동일한 파싱 로직을 재사용하면 버그까지 함께 재현되기 때문).
unreviewed를 reviewed로 전환할 수 있음shiro-check는 빌드 산출물(jar / war / fat jar / 디렉터리)을 스캔하여 실제로 배포하는 Apache Shiro 모듈을 찾아낸 다음, 정확한 모듈 + 버전 조합에 대해 26개의 공식 CVE를 모두 평가합니다.
존재 이유: Shiro CVE는 "Shiro"가 아니라 모듈에 귀속됩니다. 26개 중 13개는 shiro-core를
전혀 건드리지 않습니다. 이 도구는 CVE × 모듈 단위(37개 규칙, 7개 모듈)로 동작합니다.
좌표 기반 매칭이 볼 수 없는 세 가지:
unreviewed 상태이며
영향을 받는 패키지 목록이 비어 있고, 2개는 org.apache.shiro:shiro-root에만 연결되어 있는데
이는 packaging=pom 부모 POM으로 Maven Central에 jar가 없으며(HTTP 404), 따라서 어떤 프로젝트도
이에 의존하지 않습니다.shiro-all은 uber jar입니다 — shiro-all-1.3.2.jar에는 6개의 pom.properties 항목
(core, web, spring, ehcache, quartz + 자기 자신)이 포함되어 있습니다. pom에는 좌표 하나만 표시되지만,
jar에는 세 모듈 분량의 코드가 담겨 있습니다.3.0.0-alpha-2를 수정 버전으로 지목하는데, 이 버전은 Maven
Central에 게시된 적이 없습니다. 이 도구는 이를 표시하고 실제로 업그레이드할 수 있는 버전을 제안합니다."적중"은 모듈이 존재하고 AND 버전이 공식 영향 범위 내에 있음을 의미합니다. 이것이 악용 가능을 의미하지는 않습니다 — 대부분의 항목은 특정 구성이 필요하며, 도구는 이를 공식 권고에서 그대로 나열합니다. 이 도구는 의도적으로 사용자의 구성을 파싱하지 않습니다.
java -jar shiro-check.jar [--all] [--utf8] <jar | war | directory> ...
JDK 17+가 필요합니다. 런타임 의존성은 없습니다. 규칙 테이블은 두 개의 기본 소스에서 생성되며, 실패 시 중단되는 12개의 어서션이 있습니다. tools/gen_rules.py를 참조하세요.
Apache License 2.0
이 도구가 답하는 것은 「내가 걸렸는가, 안 걸렸는가」입니다. 아래의 것들은 이 도구가 답할 수 없으니, 저에게 맡기실 수 있습니다:
📮 [email protected] —— 상황을 설명해 주시면 24시간 이내에 한 페이지 분량의 서면 답변을 드립니다: 가능한지, 어디가 어려운지, 대략 얼마나 걸리는지. 이 단계는 무료이며, 먼저 무엇을 약속하실 필요도 없습니다.
| 코드 | 의미 |
|---|---|
0 | 스캔이 끝났고, 모든 파일이 실제로 읽혔으며, 조치가 필요한 발견 사항이 없음 |
4 | 읽을 수 없는 파일이 있음 —— zip이 아니거나, 내용이 잘렸거나, 읽기에 실패함 |
🔴 4는 2026-09-09에 추가되었으며, 추가한 이유는 분명히 말할 가치가 있습니다.
그 이전에는 읽을 수 없는 파일이 출력에 한 줄 힌트만 남기고 종료 코드는 그대로 0 이었습니다 ——
흔적을 남기는 것은 사람이 보기 위한 것이고, CI와 스크립트가 보는 것은 종료 코드이므로, 「나는 그것을 읽지 못했다」가 자동화에서는 「통과」와 같았습니다.
손상되었거나, 암호화되었거나, 다운로드가 불완전한 jar는 조용히 「문제를 발견하지 못함」이라는 한마디가 되어 버렸습니다.
「나는 그것을 읽을 수 없다」와 「당신은 안전하다」는 반드시 서로 다른 두 문장이어야 합니다.
⚠️ 합법적인 빈 jar는 읽을 수 없는 것으로 치지 않습니다(22바이트짜리 EOCD 레코드는 진짜 빈 zip입니다), 4를 트리거하지 않습니다 ——
거짓 경보가 많아지면 진짜 경보를 아무도 보지 않게 됩니다.
나머지 종료 코드의 의미는 위의 각 판정 등급과 사용 설명을 참조하십시오.