From df2f4f327a0edd1d98ba3195358c558dab45a8f5 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 1 Jul 2026 03:33:50 +0000 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]?= =?UTF-8?q?=20=EC=8B=AC=EB=B3=BC=EB=A6=AD=20=EB=A7=81=ED=81=AC=EB=A5=BC=20?= =?UTF-8?q?=ED=86=B5=ED=95=9C=20=EA=B2=BD=EB=A1=9C=20=ED=83=90=EC=83=89(Pa?= =?UTF-8?q?th=20Traversal)=20=EC=B7=A8=EC=95=BD=EC=A0=90=20=EC=88=98?= =?UTF-8?q?=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 | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 6c61284..5bd7439 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-24 - File Path Resolution leading to Path Traversal bypassing NOFOLLOW_LINKS +**Vulnerability:** Symlink path traversal via `File.canonicalFile` bypassing subsequent `NOFOLLOW_LINKS` checks. +**Learning:** In Java/Kotlin, resolving a `File` path using `.canonicalFile` inherently follows symlinks to return the final target location. When this resolved target is then passed to a function that supposedly restricts symlinks (like `Files.isDirectory(..., LinkOption.NOFOLLOW_LINKS)`), the check evaluates the target, not the original symlink. This entirely bypasses the intended security control. +**Prevention:** When intending to prevent following symlinks or strictly operate on the actual path provided without resolving targets, avoid using `File.canonicalFile`. Instead, normalize the path string logically using `.absoluteFile.toPath().normalize().toFile()`. This resolves `.` and `..` without implicitly following any symbolic links in the path. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index 2e2809f..2dcbfd2 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).absoluteFile.toPath().normalize().toFile() require(Files.isDirectory(top_dir.toPath(), LinkOption.NOFOLLOW_LINKS)) { "Top directory must be an existing non-symlink directory" } val ll = LinkedList() From 9bd5c671272f63109390949763a54dd9c312488d Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 1 Jul 2026 03:38:40 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]?= =?UTF-8?q?=20=EC=8B=AC=EB=B3=BC=EB=A6=AD=20=EB=A7=81=ED=81=AC=EB=A5=BC=20?= =?UTF-8?q?=ED=86=B5=ED=95=9C=20=EA=B2=BD=EB=A1=9C=20=ED=83=90=EC=83=89(Pa?= =?UTF-8?q?th=20Traversal)=20=EC=B7=A8=EC=95=BD=EC=A0=90=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From d1bcb99ba1bf1bb08d8ab42474a0656228491dbb Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 1 Jul 2026 03:42:13 +0000 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]?= =?UTF-8?q?=20=EC=8B=AC=EB=B3=BC=EB=A6=AD=20=EB=A7=81=ED=81=AC=EB=A5=BC=20?= =?UTF-8?q?=ED=86=B5=ED=95=9C=20=EA=B2=BD=EB=A1=9C=20=ED=83=90=EC=83=89=20?= =?UTF-8?q?Path=20Traversal=20=EC=B7=A8=EC=95=BD=EC=A0=90=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 53e0257aed919216361e698741c520887445367b Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Wed, 1 Jul 2026 03:52:50 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]?= =?UTF-8?q?=20=EC=8B=AC=EB=B3=BC=EB=A6=AD=20=EB=A7=81=ED=81=AC=EB=A5=BC=20?= =?UTF-8?q?=ED=86=B5=ED=95=9C=20=EA=B2=BD=EB=A1=9C=20=ED=83=90=EC=83=89(Pa?= =?UTF-8?q?th=20Traversal)=20=EC=B7=A8=EC=95=BD=EC=A0=90=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8225e99 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +# Changelog + +## Unreleased +- πŸ›‘οΈ Sentinel: [HIGH] `File.canonicalFile` λŒ€μ‹  `.absoluteFile.toPath().normalize().toFile()`을 μ‚¬μš©ν•˜μ—¬ 심볼릭 링크λ₯Ό 톡해 μ˜λ„ν•˜μ§€ μ•Šμ€ λ””λ ‰ν† λ¦¬λ‘œ μ΄λ™ν•˜λŠ” 경둜 탐색(Path Traversal) 취약점을 μˆ˜μ •ν–ˆμŠ΅λ‹ˆλ‹€.