Skip to content

Fix uppercase-scheme bypass in LLM tool-input guard#13

Merged
jlc488 merged 1 commit into
mainfrom
fix/case-insensitive-scheme-detection
Jul 5, 2026
Merged

Fix uppercase-scheme bypass in LLM tool-input guard#13
jlc488 merged 1 commit into
mainfrom
fix/case-insensitive-scheme-detection

Conversation

@jlc488

@jlc488 jlc488 commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

Security fix

JsonToolInputGuard.looksLikeUrl collected candidate URLs with a case-sensitive http:// / https:// prefix test:

return trimmed.startsWith("http://") || trimmed.startsWith("https://");

A tool-input URL with an uppercase scheme (HTTP://169.254.169.254/…, HtTpS://evil.com/) was never collected as a candidate, so it skipped policy validation entirely — bypassing the host allowlist and IP-literal checks. URI schemes are case-insensitive (RFC 3986 §3.1) and the downstream scheme check already used equalsIgnoreCase, so the case-sensitive collection step was an unintended inconsistency. Detection is now case-insensitive.

Blast radius

JsonToolInputGuard is the single tool-input scanner; both ssrf-guard-springai and ssrf-guard-langchain4j route tool input through it, so both LLM-framework adapters were affected.

Changes

  • Case-insensitive scheme detection in JsonToolInputGuard.looksLikeUrl
  • Regression tests: uppercase HTTP:// metadata URL and mixed-case HtTpS:// nested URL blocked; uppercase HTTPS:// whitelisted URL still passes
  • CHANGELOG (docs/changelog.md + root mirror) under [Unreleased] → Security

Verification

Full CI-equivalent build green locally: ./gradlew build jacocoTestReportBUILD SUCCESSFUL, all module tests pass.

Context

Same bug found and fixed in the JS sibling ssrf-guard-js (shipped in @devslab/ssrf-guard-js@0.1.2). Suggest a v3.1.1 patch release after merge.


보안 수정 (한국어)

looksLikeUrl가 URL 수집을 대소문자 구분으로 해서 대문자 스킴 URL(HTTP://…)이 정책 검증을 건너뛰던 우회를 수정. 스킴은 대소문자 무시(RFC 3986)이고 다음 코드가 이미 equalsIgnoreCase를 쓰므로 수집 단계만 case-sensitive였던 불일치. springai·langchain4j 둘 다 영향. 로컬 전체 빌드 green. JS 형제와 동일 버그 → 머지 후 v3.1.1 권장.

JsonToolInputGuard.looksLikeUrl matched http:// and https:// prefixes
case-sensitively, so a tool-input URL with an uppercase scheme
(HTTP://169.254.169.254/, HtTpS://evil.com/) was never collected as a
candidate and skipped policy validation entirely, bypassing the host
allowlist and IP-literal checks.

URI schemes are case-insensitive (RFC 3986 3.1) and the downstream
scheme check already used equalsIgnoreCase, so the case-sensitive match
in the collection step was an unintended inconsistency. Lower-case
before the prefix test. Adds regression tests for uppercase/mixed-case
blocked URLs and confirms an uppercase whitelisted URL still passes.

Affects ssrf-guard-springai and ssrf-guard-langchain4j, which both
route tool input through this guard. Same class of bug fixed in the
JS sibling ssrf-guard-js.
@jlc488
jlc488 merged commit 505b5e5 into main Jul 5, 2026
1 check passed
@jlc488 jlc488 mentioned this pull request Jul 5, 2026
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant