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
5 changes: 5 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,8 @@
**Vulnerability:** The `_safe_upload_filename` function used `filename.replace`, `PurePosixPath`, and `re.sub` on unbounded client input, making it vulnerable to ReDoS or CPU/memory exhaustion (DoS) when fed extremely long strings.
**Learning:** Even fast standard library functions like `PurePosixPath` and string replacements can cause significant lag when chained on strings in the megabytes. String processing operations should always bound their inputs first if the input is untrusted and can be arbitrarily large.
**Prevention:** Cap the length of client-provided filename strings early by slicing them (e.g. `filename = filename[-512:]`) before doing more complex string parsing or regex replacements, especially when only the basename suffix is relevant.

## 2025-03-10 - ꡬ쑰 검증 μ‹œ μ˜ˆμ™Έ 처리 λˆ„λ½μœΌλ‘œ μΈν•œ DoS 취약점 λ°©μ§€
**Vulnerability:** 파일 νŒŒμ‹± μ—”λ“œν¬μΈνŠΈμ—μ„œ `PdfReader` λ“±μ˜ ꡬ쑰 검증 λΌμ΄λΈŒλŸ¬λ¦¬κ°€ μ†μƒλœ νŒŒμΌμ— λŒ€ν•΄ μ˜ˆμƒμΉ˜ λͺ»ν•œ μ˜ˆμ™Έ(`MemoryError`, `TypeError` λ“±)λ₯Ό λ°œμƒμ‹œν‚¬ 경우 μ„œλ²„κ°€ 500 μ—λŸ¬λ₯Ό λ±‰μœΌλ©° DoS μƒνƒœμ— 빠질 수 μžˆλŠ” 취약점을 λ°œκ²¬ν•¨.
**Learning:** νŒŒμ‹± κ³Όμ • 쀑 λ°œμƒν•  수 μžˆλŠ” λͺ¨λ“  μ˜ˆμ™Έλ₯Ό λͺ…μ‹œμ μœΌλ‘œ λ‚˜μ—΄ν•˜λŠ” 것은 ν˜„μ‹€μ μœΌλ‘œ λΆˆκ°€λŠ₯ν•˜λ©°, μ˜ˆμƒ μ™Έμ˜ μ˜ˆμ™Έ λ°œμƒ μ‹œ μ„œλΉ„μŠ€ μž₯μ• λ‘œ μ΄μ–΄μ§€λŠ” μœ„ν—˜μ΄ 있음.
**Prevention:** ꡬ쑰 검증 ν˜ΈμΆœλΆ€λ₯Ό 포괄적인 `except Exception:` λΈ”λ‘μœΌλ‘œ 감싸 500 μ—λŸ¬ λŒ€μ‹  415 μƒνƒœ μ½”λ“œλ‘œ μ•ˆμ „ν•˜κ²Œ λŒ€μ‘ν•˜κ³ , μ‹œμŠ€ν…œ 문제λ₯Ό νŒŒμ•…ν•˜κΈ° μœ„ν•΄ μ‹€μ œ μ˜ˆμ™ΈλŠ” λ‘œκΉ…ν•˜λ„λ‘ κ°œμ„ ν•¨.
6 changes: 4 additions & 2 deletions src/newsdom_api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from fastapi.responses import JSONResponse
from fastapi.security import HTTPBearer
from pypdf import PdfReader
from pypdf.errors import PdfReadError

from .config import (
AuthenticationMode,
Expand Down Expand Up @@ -193,7 +192,10 @@ def _validate_pdf_structure(file_path: Path) -> None:
reader = PdfReader(file_path, strict=True)
if len(reader.pages) < 1:
raise ValueError("PDF has no pages")
except (PdfReadError, RecursionError, ValueError, OverflowError):
except Exception as exc:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

πŸŸ₯ Memory exhaustion bypasses validation handler

A crafted PDF that makes PdfReader raise MemoryError bypasses except Exception. The request can still crash a worker instead of returning 415.

Devin Review

Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

LOGGER.error(
"Unhandled exception during PDF structure validation", exc_info=exc
)
raise HTTPException(
status_code=415,
detail=UNSUPPORTED_MEDIA_DETAIL,
Expand Down
17 changes: 17 additions & 0 deletions tests/test_parse_endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,23 @@ def test_validate_pdf_structure_rejects_invalid_magic_bytes(tmp_path):

assert exc_info.value.status_code == 415
assert exc_info.value.detail == "Unsupported Media Type"


def test_validate_pdf_structure_rejects_unhandled_exceptions(
monkeypatch, tmp_path, caplog
):
def reject_pdf(_stream, *, strict):
raise TypeError("malformed object")

monkeypatch.setattr("newsdom_api.main.PdfReader", reject_pdf)

with pytest.raises(HTTPException) as exc_info:
(tmp_path / "test.pdf").write_bytes(b"%PDF-1.4\n%%EOF")
_validate_pdf_structure(tmp_path / "test.pdf")

assert exc_info.value.status_code == 415
assert exc_info.value.detail == "Unsupported Media Type"
assert "Unhandled exception during PDF structure validation" in caplog.text
assert exc_info.value.__cause__ is None


Expand Down
Loading