diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 6c61284..88e0054 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 - Symlink Check Bypass via canonicalFile +**Vulnerability:** The application was vulnerable to directory traversal/symlink attacks because `File.canonicalFile` automatically resolves symbolic links, bypassing subsequent checks that look for symlinks using `LinkOption.NOFOLLOW_LINKS`. +**Learning:** When trying to determine if a given path is a symlink (or trying to forbid symlink resolution), using `canonicalFile` beforehand defeats the purpose because it resolves symlinks to their real paths. `LinkOption.NOFOLLOW_LINKS` with `Files.isDirectory` fails to detect the symlink if the path passed in has already been canonicalized. +**Prevention:** Always use `File.absoluteFile` instead of `File.canonicalFile` when you need a full path but want to preserve symlinks so that they can be checked or rejected properly using `Files.isSymbolicLink` or `LinkOption.NOFOLLOW_LINKS`. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..850f19e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# 변경 사항 + +- `html4tree/main.kt`의 루트 디렉터리(`topDir`) 심볼릭 링크 검사 우회 취약점 수정. `File.canonicalFile`이 심볼릭 링크를 자동 해석하여 `LinkOption.NOFOLLOW_LINKS` 검사가 무력화되는 문제를 방지하기 위해 `File.absoluteFile`로 변경. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index 2e2809f..013452c 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 require(Files.isDirectory(top_dir.toPath(), LinkOption.NOFOLLOW_LINKS)) { "Top directory must be an existing non-symlink directory" } val ll = LinkedList()