From 74fe99f2542d218499fa53aab58fbc4b1ba36f7e Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 4 Jul 2026 03:41:58 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[HIGH]=20?= =?UTF-8?q?=EC=8B=AC=EB=B3=BC=EB=A6=AD=20=EB=A7=81=ED=81=AC=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EC=9A=B0=ED=9A=8C=20=EC=B7=A8=EC=95=BD=EC=A0=90=20?= =?UTF-8?q?=ED=8C=A8=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - canonicalFile 대신 absoluteFile.normalize를 사용하여 심볼릭 링크 제한(NOFOLLOW_LINKS)을 우회할 수 없도록 수정함. --- .jules/sentinel.md | 4 ++++ src/main/kotlin/html4tree/main.kt | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 6c61284..e5be189 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -22,3 +22,7 @@ **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 - [Symbolic Link Validation Bypass] +**Vulnerability:** 파일 경로를 검증할 때 `canonicalFile`을 사용하면 해당 경로가 심볼릭 링크인지 확인하기도 전에 실제 물리적 경로로 분석(resolving)되어버려, 이후 `LinkOption.NOFOLLOW_LINKS`를 이용한 심볼릭 링크 제한 로직이 우회되는 논리적 보안 취약점이 있었습니다. +**Learning:** `canonicalFile`은 운영 체제의 파일 시스템을 참고하여 모든 심볼릭 링크를 원본 경로로 치환합니다. 따라서 심볼릭 링크 여부를 검사하거나 링크 자체의 경로를 검증해야 할 때는 이를 사용하면 안 되며, 파일 시스템 조회 없이 경로 문자열만 정규화하는 `absoluteFile.toPath().normalize().toFile()` 방식을 사용해야 합니다. +**Prevention:** 심볼릭 링크에 대한 제약 조건(예: 디렉토리 탐색 금지)을 강제할 때는 경로를 해석(resolve)하는 함수(예: canonicalFile, realPath) 대신 단순 정규화 함수(normalize)를 사용하여 원본 경로 형태를 유지한 채 검증을 수행해야 합니다. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index 2e2809f..0f9dea3 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -23,7 +23,9 @@ fun main(args: Array) = Html4tree().main(args) fun go(topDir: String, maxLevel: Int) { require(topDir.isNotBlank()) - val top_dir = File(topDir).canonicalFile + // 보안 향상: canonicalFile은 심볼릭 링크를 미리 해석하여 검증을 무력화하므로, + // absoluteFile과 normalize()를 사용하여 심볼릭 링크 검증 우회를 방지합니다. + 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()