Skip to content

security(ignore): preserve all-or-nothing ignore policy on read failure - #595

Draft
seonghobae wants to merge 3 commits into
masterfrom
sentinel/fix-toctou-ioexception-html4ignore-716293609380063460
Draft

security(ignore): preserve all-or-nothing ignore policy on read failure#595
seonghobae wants to merge 3 commits into
masterfrom
sentinel/fix-toctou-ioexception-html4ignore-716293609380063460

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Valid finding retained, canonical owner moved to #594

This PR remains open as Draft because its useful semantic delta is being retired only through verified succession, not by duplicate cleanup.

Current branch head: 16239da7c52097426e36a64fb1c9ba1006a34978.
Canonical repair lane: #594 @ e7722b203ff9cbfc5217f7cd4ff2ef12d8295ba1.

Valid delta and current successor state

The useful contract in this branch is all-or-nothing user-policy loading. If the reader yields a valid pattern and then fails, previously parsed matchers from that failed read must be discarded rather than applied as a partial policy.

#594 now carries both sides of that contract. Its deterministic IgnoreFilePartialReadFailureTest.kt injects a BufferedReader that returns *.secret and then throws IOException; its new production descendant accumulates matchers in a local list and publishes them only after the complete bounded read returns successfully. Any IOException yields an empty user matcher list while mandatory defaults remain active.

Why this branch is not canonical

This branch changes the public process_ignore_file signature to inject a Sequence<String> reader, contains a timing-dependent background mutation loop, and includes generated journal text with a literal shell $(date ...). None is required for the product invariant. #594 has the narrower package-internal point-of-use opener seam, NOFOLLOW_LINKS, deterministic validation→open race evidence, ordinary-file positive behavior, narrow IOException containment, and now the transactional matcher-publication GREEN.

Successor acceptance

Do not close this PR yet. The semantic/test succession is now implemented in #594, but verified closure additionally requires #594 exact head e7722b203... to pass focused tests/JaCoCo plus CI/Security/SAST/OSV/Scorecard and current review/thread admission. Those exact-head hosted runs are currently non-terminal.

After that fresh verification, close this PR as a verified successor rather than merging its broader public-signature/timing/journal changes.

Do not carry the public-signature change, broad policy generalization, timing race, shell-templated journal text, force rewrite, no-op retrigger, or gate weakening into the successor.

🚨 Severity: MEDIUM
💡 Vulnerability: .html4ignore 파일을 파싱할 때 canRead()로 사전 검사 후 useLines()로 읽어들이는 사이 파일 시스템 상태가 변경(삭제 혹은 권한 박탈)될 수 있는 TOCTOU 취약점.
🎯 Impact: 해당 조건에서 발생하는 처리되지 않은 java.io.IOException으로 인해 전체 디렉토리 크롤러가 충돌하여 서비스 거부(DoS)가 발생할 수 있습니다.
🔧 Fix: useLines() 블록을 try-catch 구문으로 감싸 IOException을 잡아내고, 파일 접근 불가 시 남은 크롤링 작업을 안전하게 계속 진행(Fail Securely)하도록 수정했습니다.
✅ Verification: 코드 리뷰 확인 및 자동화된 테스트 커버리지를 통과.
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 48 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 056baebb-ff96-4645-af19-67a08348a546

📥 Commits

Reviewing files that changed from the base of the PR and between de82f99 and 16239da.

📒 Files selected for processing (3)
  • .jules/sentinel.md
  • src/main/kotlin/html4tree/main.kt
  • src/test/kotlin/html4tree/MainTest.kt

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note

This report is out of date. Scroll down for Devin Review's latest report on this PR.

Devin Review found 2 potential issues.

Devin Review

Comment on lines +648 to +659
var covered = false
val start = System.currentTimeMillis()
val t = kotlin.concurrent.thread {
while (!covered && !Thread.currentThread().isInterrupted) {
ignoreFile.writeText("pattern")
ignoreFile.setReadable(false)
ignoreFile.delete()
}
}
while (!covered && System.currentTimeMillis() - start < 1000) {
process_ignore_file(testDir)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Exception coverage remains timing-dependent

covered never changes, so the test passes without exercising the new catch handler. The mandatory 100% coverage gate now depends on winning a filesystem race.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread src/main/kotlin/html4tree/main.kt
🚨 Severity: MEDIUM
💡 Vulnerability: .html4ignore 파일을 파싱할 때 canRead()로 사전 검사 후 useLines()로 읽어들이는 사이 파일 시스템 상태가 변경(삭제 혹은 권한 박탈)될 수 있는 TOCTOU 취약점.
🎯 Impact: 해당 조건에서 발생하는 처리되지 않은 java.io.IOException으로 인해 전체 디렉토리 크롤러가 충돌하여 서비스 거부(DoS)가 발생할 수 있습니다.
🔧 Fix: useLines() 블록을 try-catch 구문으로 감싸 IOException을 잡아내고, 파일 접근 불가 시 남은 크롤링 작업을 안전하게 계속 진행(Fail Securely)하도록 수정했습니다.
✅ Verification: 코드 리뷰 확인 및 자동화된 테스트 커버리지를 통과.
🚨 Severity: MEDIUM
💡 Vulnerability: .html4ignore 파일을 파싱할 때 canRead()로 사전 검사 후 useLines()로 읽어들이는 사이 파일 시스템 상태가 변경(삭제 혹은 권한 박탈)될 수 있는 TOCTOU 취약점.
🎯 Impact: 해당 조건에서 발생하는 처리되지 않은 java.io.IOException으로 인해 전체 디렉토리 크롤러가 충돌하여 서비스 거부(DoS)가 발생할 수 있으며, 읽기 실패 시 이전에 파싱된 규칙이 적용되어 파일이 노출될 수 있습니다.
🔧 Fix: useLines() 블록을 try-catch 구문으로 감싸 IOException을 잡아내고, 예외 발생 시 적용 중이던 matchers를 초기화하여 Fail Securely 하도록 수정했습니다.
✅ Verification: 의존성 주입을 통한 테스트 추가 및 자동화된 테스트 커버리지를 통과.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

Devin Review

}
t.interrupt()
t.join(1000)
testDir.deleteRecursively()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Test bypasses fixture ownership

The test deletes the shared tempDir directly although class teardown owns it. Remove this cleanup to preserve the test fixture lifecycle.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

}

fun process_ignore_file(curr_dir: File, dirFilesNames: Array<String>? = null): Set<String> {
fun process_ignore_file(curr_dir: File, dirFilesNames: Array<String>? = null, readIgnoreFile: (File) -> Sequence<String> = { it.useLines { lines -> lines.toList().asSequence() } }): Set<String> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟨 Ignore-file limits apply too late

When an ignore file grows after validation, readIgnoreFile reads it fully before enforcing the 1,000-line limit. Crawling can exhaust memory or hang.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@seonghobae seonghobae added priority: medium Normal-priority or P2 work status: needs-review Open pull request requiring current-head review or checks type: bug Defect or incorrect behavior labels Sep 2, 2026 — with ChatGPT Codex Connector
@seonghobae
seonghobae marked this pull request as draft September 4, 2026 02:33
@seonghobae seonghobae changed the title 🛡️ Sentinel: [MEDIUM] .html4ignore 처리 중 TOCTOU IOException 방어 security(ignore): preserve all-or-nothing ignore policy on read failure Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: medium Normal-priority or P2 work status: needs-review Open pull request requiring current-head review or checks type: bug Defect or incorrect behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant