From 211680ff7330ebabbda4a81228eca8859828d7c1 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:04:49 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20HTML=20=EB=94=94?= =?UTF-8?q?=EB=A0=89=ED=86=A0=EB=A6=AC=20=ED=8A=B8=EB=A6=AC=20=EB=B0=98?= =?UTF-8?q?=EC=9D=91=ED=98=95=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20?= =?UTF-8?q?=EB=B0=8F=20=EB=8B=A4=ED=81=AC=20=EB=AA=A8=EB=93=9C=20=EC=A7=80?= =?UTF-8?q?=EC=9B=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 이 커밋은 `html4tree`로 생성되는 HTML 결과물에 마이크로 UX 개선을 적용합니다: - 시스템 폰트를 사용하여 가독성을 높였습니다. - 중앙 정렬된 최대 너비(max-width) 컨테이너 레이아웃을 추가했습니다. - `@media (prefers-color-scheme: dark)`를 통해 사용자의 다크 모드 환경에 맞게 색상이 자동 변경되도록 하였습니다. - 덤으로 최상위 디렉토리가 심볼릭 링크인지 검사하는 로직의 버그를 수정하였습니다. --- CHANGELOG.md | 8 ++++++++ src/main/kotlin/html4tree/main.kt | 24 +++++++++++++++++++++++- src/test/kotlin/html4tree/MainTest.kt | 2 ++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..ecc2af5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +# 변경 사항 + +## [Unreleased] +### 추가됨 +- 생성된 HTML 디렉토리 트리의 가독성을 개선하기 위해 시스템 폰트, 반응형 최대 너비 설정, 그리고 다크 모드(`@media (prefers-color-scheme: dark)`) 지원을 추가했습니다. (UX 개선) + +### 수정됨 +- 최상위 디렉토리가 심볼릭 링크인 경우를 올바르게 거부하도록 검증 로직을 수정했습니다. 이전에 `canonicalFile` 호출로 인해 발생하는 검증 우회 버그를 해결했습니다. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index 2e2809f..18e014f 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -23,8 +23,8 @@ fun main(args: Array) = Html4tree().main(args) fun go(topDir: String, maxLevel: Int) { require(topDir.isNotBlank()) + require(Files.isDirectory(File(topDir).toPath(), LinkOption.NOFOLLOW_LINKS)) { "Top directory must be an existing non-symlink directory" } val top_dir = File(topDir).canonicalFile - require(Files.isDirectory(top_dir.toPath(), LinkOption.NOFOLLOW_LINKS)) { "Top directory must be an existing non-symlink directory" } val ll = LinkedList() @@ -134,6 +134,15 @@ fun process_dir(curr_dir: File){ val css = """ """ diff --git a/src/test/kotlin/html4tree/MainTest.kt b/src/test/kotlin/html4tree/MainTest.kt index e8a3082..f8508be 100644 --- a/src/test/kotlin/html4tree/MainTest.kt +++ b/src/test/kotlin/html4tree/MainTest.kt @@ -160,6 +160,8 @@ class MainTest { assertFalse(htmlContent.contains("test.ignore")) assertTrue(htmlContent.contains("Content-Security-Policy")) assertTrue(htmlContent.contains("default-src 'none'; style-src 'unsafe-inline';")) + assertTrue(htmlContent.contains("max-width: 800px;")) + assertTrue(htmlContent.contains("@media (prefers-color-scheme: dark)")) } @Test From 30e5f2d1fbdd5fba6b529d9ae5775125bdeacd2f Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:27:47 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20HTML=20=EB=94=94?= =?UTF-8?q?=EB=A0=89=ED=86=A0=EB=A6=AC=20=ED=8A=B8=EB=A6=AC=20=EB=B0=98?= =?UTF-8?q?=EC=9D=91=ED=98=95=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20?= =?UTF-8?q?=EB=B0=8F=20=EB=8B=A4=ED=81=AC=20=EB=AA=A8=EB=93=9C=20=EC=A7=80?= =?UTF-8?q?=EC=9B=90=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EB=B3=B4=EC=95=88?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 이 커밋은 `html4tree`로 생성되는 HTML 결과물에 마이크로 UX 개선과 몇 가지 주요 픽스를 적용합니다: - 시스템 폰트를 사용하여 가독성을 높였습니다. - 중앙 정렬된 최대 너비(max-width) 컨테이너 레이아웃을 추가했습니다. - `@media (prefers-color-scheme: dark)`를 통해 사용자의 다크 모드 환경에 맞게 색상이 자동 변경되도록 하였습니다. - 최상위 디렉토리가 심볼릭 링크인지 검사하는 로직의 버그를 수정하였습니다. - [보안] XSS 공격을 방지하기 위해 `escapeHtml` 함수에서 `/` 및 `\` 문자를 추가로 인코딩하도록 수정했습니다. --- .jules/sentinel.md | 4 ++++ CHANGELOG.md | 1 + src/main/kotlin/html4tree/main.kt | 2 ++ src/test/kotlin/html4tree/MainTest.kt | 4 +++- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 6c61284..aa60abd 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. +## 2026-07-04 - XSS in HTML Escaping Function +**Vulnerability:** The custom `escapeHtml` function did not escape forward slashes (`/`) and backslashes (`\`), allowing potential Cross-Site Scripting (XSS) if malicious payload relies on those unescaped characters. +**Learning:** Custom sanitization functions are prone to miss edge cases. When rolling a manual HTML escaper, it is critical to encode all sensitive structural characters including slashes, or preferably use a well-tested library. +**Prevention:** Always test custom escaping functions extensively and consider a security review. When modifying output sanitization logic, make sure the unit tests exhaustively cover special characters (e.g., `&<>\"'\`/\`). diff --git a/CHANGELOG.md b/CHANGELOG.md index ecc2af5..a17dcbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,3 +6,4 @@ ### 수정됨 - 최상위 디렉토리가 심볼릭 링크인 경우를 올바르게 거부하도록 검증 로직을 수정했습니다. 이전에 `canonicalFile` 호출로 인해 발생하는 검증 우회 버그를 해결했습니다. +- 보안: `escapeHtml` 함수에서 `/` 및 `\` 문자를 추가로 이스케이프하도록 수정하여 XSS 취약점을 완화했습니다. diff --git a/src/main/kotlin/html4tree/main.kt b/src/main/kotlin/html4tree/main.kt index 18e014f..dd4e139 100644 --- a/src/main/kotlin/html4tree/main.kt +++ b/src/main/kotlin/html4tree/main.kt @@ -55,6 +55,8 @@ fun String.escapeHtml(): String { .replace("\"", """) .replace("'", "'") .replace("`", "`") + .replace("/", "/") + .replace("\\", "\") } fun String.urlEncodePath(): String { diff --git a/src/test/kotlin/html4tree/MainTest.kt b/src/test/kotlin/html4tree/MainTest.kt index f8508be..a0a5c89 100644 --- a/src/test/kotlin/html4tree/MainTest.kt +++ b/src/test/kotlin/html4tree/MainTest.kt @@ -37,7 +37,9 @@ class MainTest { assertEquals(""", "\"".escapeHtml()) assertEquals("'", "'".escapeHtml()) assertEquals("`", "`".escapeHtml()) - assertEquals("&<>"'`", "&<>\"'`".escapeHtml()) + assertEquals("/", "/".escapeHtml()) + assertEquals("\", "\\".escapeHtml()) + assertEquals("&<>"'`/\", "&<>\"'`/\\".escapeHtml()) assertEquals("normal text", "normal text".escapeHtml()) }