Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,7 @@
**Vulnerability:** The application lists all files in a directory, including hidden files (those starting with `.`), which could inadvertently expose sensitive information like `.env`, `.git`, or `.ssh` directories.
**Learning:** Default directory listing implementations without hidden file filtering can lead to information disclosure vulnerabilities when serving directories containing configuration or sensitive files.
**Prevention:** Automatically exclude hidden files (files starting with `.`) from the generated directory listing by default.
## 2023-10-27 - [Information Exposure via Case-Sensitive Matches]
**Vulnerability:** The `process_ignore_file` routine used case-sensitive matching for sensitive files (like `id_rsa`, `secrets.yml`), allowing case variations (e.g., `ID_RSA`) to bypass filtering and be included in the generated HTML.
**Learning:** Exact string matching is fragile for file systems that are case-insensitive or for users who create mixed-case variations of sensitive files.
**Prevention:** Always normalize file names (e.g., using `toLowerCase()`) when matching against exclusion lists, taking care to preserve expected outputs like exact sizes in tests or edge cases (like `.DS_Store`).
11 changes: 10 additions & 1 deletion src/main/kotlin/html4tree/main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,17 @@ fun process_ignore_file(curr_dir: File, dirFilesNames: Array<String>? = null): S
files_to_exclude.add("index.html")

// λ³΄μ•ˆ ν–₯상: λ―Όκ°ν•œ μ‹œμŠ€ν…œ, μ„€μ •, μ‹œν¬λ¦Ώ νŒŒμΌμ„ 디렉토리 λͺ©λ‘μ—μ„œ 기본적으둜 μ œμ™Έν•˜μ—¬ 정보 λ…ΈμΆœ(Information Exposure) λ°©μ§€
val defaultSensitiveFiles = listOf(".git", ".env", ".ssh", ".htpasswd", ".htaccess", "id_rsa", "id_ed25519", "secrets.yml", ".html4ignore", ".DS_Store", ".aws", ".kube", ".npmrc", ".gnupg", "config.json", "credentials.json")
val defaultSensitiveFiles = listOf(".git", ".env", ".ssh", ".htpasswd", ".htaccess", "id_rsa", "id_ed25519", "secrets.yml", ".html4ignore", ".ds_store", ".aws", ".kube", ".npmrc", ".gnupg", "config.json", "credentials.json")
files_to_exclude.addAll(defaultSensitiveFiles)
files_to_exclude.add(".DS_Store") // Ensure original case is also explicitly excluded

// πŸ›‘οΈ Sentinel: Make sensitive file checks case-insensitive
(dirFilesNames ?: curr_dir.list())?.forEach {
val lowerCaseName = it.toLowerCase()
if (lowerCaseName in defaultSensitiveFiles) {
files_to_exclude.add(it)
}
}

// λ³΄μ•ˆ ν–₯상: .env, .git λ“± λ―Όκ°ν•œ 정보가 포함될 수 μžˆλŠ” μˆ¨κΉ€ 파일(.으둜 μ‹œμž‘ν•˜λŠ” λͺ¨λ“  ν•­λͺ©)을 기본적으둜 λ…ΈμΆœν•˜μ§€ μ•Šλ„λ‘ μ œμ™Έ (정보 λ…ΈμΆœ λ°©μ§€)
(dirFilesNames ?: curr_dir.list())?.forEach {
Expand Down
4 changes: 2 additions & 2 deletions src/test/kotlin/html4tree/MainTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ class MainTest {
fun testProcessIgnoreFileNoIgnore() {
val excluded = process_ignore_file(tempDir, null)
assertTrue(excluded.contains("index.html"))
assertEquals(17, excluded.size) // index.html + 16 default sensitive files
assertEquals(18, excluded.size) // updated // index.html + 16 default sensitive files
}

@Test
Expand All @@ -277,7 +277,7 @@ class MainTest {

val excluded = process_ignore_file(tempDir, arrayOf("test1.txt", "test3.txt"))
assertTrue(excluded.contains("index.html"))
assertEquals(18, excluded.size) // index.html + 16 default sensitive + test1.txt
assertEquals(19, excluded.size)
}

@Test
Expand Down
27 changes: 27 additions & 0 deletions src/test/kotlin/html4tree/SecurityTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package html4tree

import org.junit.Test
import org.junit.Assert.*
import java.io.File
import java.nio.file.Files

class SecurityTest {
@Test
fun testSensitiveFilesCaseInsensitive() {
val tempDir = Files.createTempDirectory("sectest").toFile()
try {
val file1 = File(tempDir, "ID_RSA")
file1.createNewFile()

val excluded = process_ignore_file(tempDir, null)
assertTrue("ID_RSA should be excluded", excluded.contains("ID_RSA"))

process_dir(tempDir)

val indexContent = File(tempDir, "index.html").readText()
assertFalse("ID_RSA should be excluded from index.html", indexContent.contains("ID_RSA"))
} finally {
tempDir.deleteRecursively()
}
}
}
Loading