From 93e72dcc25ba4d5ef5606dda7efb67a053e6c5a9 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Mon, 6 Jul 2026 20:51:53 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITICAL]?= =?UTF-8?q?=20=EC=8B=AC=EB=B3=BC=EB=A6=AD=20=EB=A7=81=ED=81=AC=20=EC=9A=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=B7=A8=EC=95=BD=EC=A0=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `canonicalFile`을 사용하여 발생하던 디렉토리 심볼릭 링크 우회(Path Traversal) 취약점을 수정했습니다. `.toPath().toAbsolutePath().normalize().toFile()`로 대체하여 심볼릭 링크를 유지한 상태에서 검사하도록 변경했습니다. --- .jules/sentinel.md | 5 +++++ CHANGELOG.md | 5 +++++ src/main/kotlin/html4tree/main.kt | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 6c61284..cfdec2b 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -22,3 +22,8 @@ **Vulnerability:** Defense in Depth (CSP Missing) **Learning:** Even when inputs are properly escaped, statically generated HTML that displays file/directory structures should implement a Content Security Policy (CSP) to provide an extra layer of defense against potential XSS bypasses. **Prevention:** Include a strict CSP meta tag (e.g., `default-src 'none'; style-src 'unsafe-inline';`) in auto-generated HTML headers when external scripts or resources are not required. + +## 2024-07-06 - [html4tree] Directory Traversal Bypass via Canonical File +**Vulnerability:** Path traversal and directory boundary escape through top-level symbolic links. +**Learning:** Using `File.canonicalFile` resolves symbolic links to their absolute target paths before any subsequent checks are performed. This renders `Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)` useless because the path passed to it has already had all symlinks resolved by `canonicalFile`, meaning it will appear as a normal directory and bypass symlink checks. +**Prevention:** When you need an absolute path but must preserve symbolic links for validation purposes, use `.toPath().toAbsolutePath().normalize().toFile()` instead of `.canonicalFile`. This normalizes `.` and `..` without resolving symbolic links, allowing `LinkOption.NOFOLLOW_LINKS` checks to function correctly. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d83b924 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# 변경 사항 + +## [Unreleased] +### 보안 (Security) +- `canonicalFile` 대신 `normalize()`를 사용하여 `html4tree`의 심볼릭 링크 기반 디렉토리 탐색 우회 취약점을 수정했습니다. `canonicalFile`은 사전에 심볼릭 링크를 대상 경로로 해석하여 이어지는 `LinkOption.NOFOLLOW_LINKS` 검사를 무력화하는 문제가 있었습니다. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index 2e2809f..ae3e0b5 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -23,7 +23,7 @@ fun main(args: Array) = Html4tree().main(args) fun go(topDir: String, maxLevel: Int) { require(topDir.isNotBlank()) - val top_dir = File(topDir).canonicalFile + val top_dir = File(topDir).toPath().toAbsolutePath().normalize().toFile() require(Files.isDirectory(top_dir.toPath(), LinkOption.NOFOLLOW_LINKS)) { "Top directory must be an existing non-symlink directory" } val ll = LinkedList()