From 745634bd29e6049f5609d8e60dcd8a90bf6675e3 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 2 Jul 2026 21:11:55 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITIC?= =?UTF-8?q?AL]=20=EC=8B=AC=EB=B3=BC=EB=A6=AD=20=EB=A7=81=ED=81=AC=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=9A=B0=ED=9A=8C(=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=ED=83=90=EC=83=89)=20=EB=B3=B4=EC=95=88=20=EC=B7=A8=EC=95=BD?= =?UTF-8?q?=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 --- .jules/sentinel.md | 5 +++++ src/main/kotlin/html4tree/main.kt | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 6c61284..13ae207 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. + +## 2026-07-02 - [Fix Path Traversal/Symlink Bypass in File Checking] +**Vulnerability:** 심볼릭 링크 디렉토리인지 검증하는 과정에서 `File.canonicalFile`을 사용하면, JVM/OS가 심볼릭 링크를 대상 경로(실제 디렉토리)로 미리 해석(resolve)해 버립니다. 그 결과 `Files.isDirectory(..., LinkOption.NOFOLLOW_LINKS)`가 심볼릭 링크 자체가 아닌 실제 디렉토리를 검사하게 되어 심볼릭 링크 검증을 우회하는 보안 취약점이 발생했습니다. +**Learning:** `canonicalFile`은 모든 심볼릭 링크를 해석하고 정규화된 절대 경로를 반환합니다. 심볼릭 링크 자체의 속성을 검사해야 할 때(예: 심볼릭 링크를 허용하지 않거나, 경로 탐색을 방지해야 하는 경우) `canonicalFile`을 사용하면 검증 로직이 무효화될 수 있습니다. +**Prevention:** 심볼릭 링크 검증 시에는 경로의 상대성만 해결하고 심볼릭 링크를 해석하지 않는 `absoluteFile`을 사용해야 합니다. 그 후 `LinkOption.NOFOLLOW_LINKS`와 같은 옵션을 사용하여 안전하게 파일 시스템 속성을 검사해야 합니다. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index 2e2809f..dd92682 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -23,7 +23,8 @@ fun main(args: Array) = Html4tree().main(args) fun go(topDir: String, maxLevel: Int) { require(topDir.isNotBlank()) - val top_dir = File(topDir).canonicalFile + // 보안 취약점 수정: canonicalFile 대신 absoluteFile을 사용하여 심볼릭 링크를 미리 해석하지 않도록 함. (경로 탐색 취약점 방지) + 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() From 696f92a0695dcebc16866b1eecbe6541943043b6 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 3 Jul 2026 04:11:39 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITIC?= =?UTF-8?q?AL]=20=EC=8B=AC=EB=B3=BC=EB=A6=AD=20=EB=A7=81=ED=81=AC=20?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EC=9A=B0=ED=9A=8C(=EA=B2=BD=EB=A1=9C=20?= =?UTF-8?q?=ED=83=90=EC=83=89)=20=EB=B3=B4=EC=95=88=20=EC=B7=A8=EC=95=BD?= =?UTF-8?q?=EC=A0=90=20=EC=88=98=EC=A0=95=20(=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=ED=94=BC=EB=93=9C=EB=B0=B1=20=EB=B0=98=EC=98=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/sentinel.md | 2 +- src/main/kotlin/html4tree/main.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 13ae207..31d1379 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -26,4 +26,4 @@ ## 2026-07-02 - [Fix Path Traversal/Symlink Bypass in File Checking] **Vulnerability:** 심볼릭 링크 디렉토리인지 검증하는 과정에서 `File.canonicalFile`을 사용하면, JVM/OS가 심볼릭 링크를 대상 경로(실제 디렉토리)로 미리 해석(resolve)해 버립니다. 그 결과 `Files.isDirectory(..., LinkOption.NOFOLLOW_LINKS)`가 심볼릭 링크 자체가 아닌 실제 디렉토리를 검사하게 되어 심볼릭 링크 검증을 우회하는 보안 취약점이 발생했습니다. **Learning:** `canonicalFile`은 모든 심볼릭 링크를 해석하고 정규화된 절대 경로를 반환합니다. 심볼릭 링크 자체의 속성을 검사해야 할 때(예: 심볼릭 링크를 허용하지 않거나, 경로 탐색을 방지해야 하는 경우) `canonicalFile`을 사용하면 검증 로직이 무효화될 수 있습니다. -**Prevention:** 심볼릭 링크 검증 시에는 경로의 상대성만 해결하고 심볼릭 링크를 해석하지 않는 `absoluteFile`을 사용해야 합니다. 그 후 `LinkOption.NOFOLLOW_LINKS`와 같은 옵션을 사용하여 안전하게 파일 시스템 속성을 검사해야 합니다. +**Prevention:** 심볼릭 링크 검증 시에는 경로의 상대성만 해결하고 심볼릭 링크를 해석하지 않는 `Path.toAbsolutePath().normalize()`을 사용해야 합니다. 그 후 `LinkOption.NOFOLLOW_LINKS`와 같은 옵션을 사용하여 안전하게 파일 시스템 속성을 검사해야 합니다. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index dd92682..c76f043 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()) - // 보안 취약점 수정: canonicalFile 대신 absoluteFile을 사용하여 심볼릭 링크를 미리 해석하지 않도록 함. (경로 탐색 취약점 방지) + // 보안 취약점 수정: canonicalFile 대신 toPath().toAbsolutePath().normalize().toFile()을 사용하여 심볼릭 링크를 미리 해석하지 않도록 함. (경로 탐색 취약점 방지) 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" }