From ba140de438f6547028128604e9149b308c221c36 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 4 Jul 2026 20:48:15 +0000 Subject: [PATCH] =?UTF-8?q?=EB=B3=B4=EC=95=88:=20=EC=8B=AC=EB=B3=BC?= =?UTF-8?q?=EB=A6=AD=20=EB=A7=81=ED=81=AC=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC=20=EC=9A=B0=ED=9A=8C=20=EC=B7=A8=EC=95=BD?= =?UTF-8?q?=EC=A0=90=20=EC=88=98=EC=A0=95=20(canonicalFile=20->=20absolute?= =?UTF-8?q?File)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 최상위 디렉토리 확인 시 `File.canonicalFile`을 사용하면 심볼릭 링크가 미리 해석되어 `NOFOLLOW_LINKS` 검사를 우회할 수 있는 취약점을 수정했습니다. `absoluteFile`을 사용하도록 변경하여 심볼릭 링크 원본 상태를 유지하고 검사가 정상 작동하도록 했습니다. --- .jules/sentinel.md | 5 +++++ src/main/kotlin/html4tree/main.kt | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 6c61284..4294951 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-04 - Path Traversal bypass via canonicalFile +**Vulnerability:** Bypass of `NOFOLLOW_LINKS` check for symbolic links during directory crawling top level check. +**Learning:** Using `File.canonicalFile` resolves symbolic links before any subsequent checks. If you then call `Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS)` on the canonicalized file, the symlink has already been followed and resolved to its target, meaning the `NOFOLLOW_LINKS` option fails to detect that it was originally a symlink. +**Prevention:** Use `File.absoluteFile` instead of `File.canonicalFile` when preparing files for symlink validation checks so that the original symlink is preserved and correctly rejected by `NOFOLLOW_LINKS`. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index 2e2809f..f6cab25 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -23,7 +23,10 @@ fun main(args: Array) = Html4tree().main(args) fun go(topDir: String, maxLevel: Int) { require(topDir.isNotBlank()) - val top_dir = File(topDir).canonicalFile + // SECURITY: Use absoluteFile instead of canonicalFile to avoid prematurely + // resolving symlinks, which would bypass the NOFOLLOW_LINKS check below + // and potentially allow path traversal vulnerabilities via symlinks. + val top_dir = File(topDir).absoluteFile require(Files.isDirectory(top_dir.toPath(), LinkOption.NOFOLLOW_LINKS)) { "Top directory must be an existing non-symlink directory" } val ll = LinkedList()