Skip to content

Sanitize Content-Disposition filename to a safe basename - #334

Open
Flerpharos wants to merge 1 commit into
mainfrom
fix/326-content-disposition-filename-sanitize
Open

Sanitize Content-Disposition filename to a safe basename#334
Flerpharos wants to merge 1 commit into
mainfrom
fix/326-content-disposition-filename-sanitize

Conversation

@Flerpharos

Copy link
Copy Markdown
Collaborator

Fixes #326

src/labapi/entry/entries/attachment.py used the server-supplied Content-Disposition filename (msg.get_filename()) verbatim, while the S3-fallback path (_s3_filename_from_url) already reduced its filename to a sanitized basename. A download response with a Content-Disposition filename such as ../../x could therefore leave Attachment.filename carrying path-traversal sequences.

Fix

  • Factored the sanitization logic out of _s3_filename_from_url into a shared _safe_basename() helper: reduces to PurePosixPath(name).name, rejects None/empty/./.., and normalizes backslashes to forward slashes first so Windows-style traversal sequences (..\..\x) are also handled.
  • _ensure_attachment now applies _safe_basename() to msg.get_filename() before it becomes Attachment.filename.
  • The page-listing filename (self._filename, supplied at upload time) is left as-is — unrelated to this server-response parsing path, and already covered by an existing test asserting it takes precedence unchanged.

Tests

Added test_attachment_entry_sanitizes_content_disposition_filename (parametrized) in tests/entry/entries/test_attachment.py covering:

  • ../../xx
  • ..\..\x (backslash variant) → x
  • a normal filename (report.pdf) is unchanged

Verification

  • uv run pytest --ignore=tests/test_integration.py -q — 433 passed, 1 skipped
  • uv run ruff check . — all checks passed
  • uv run ruff format --check . — all files formatted

The direct-API attachment path stored msg.get_filename() verbatim,
while the S3-fallback path already reduced its filename to a
sanitized basename. A server response with a Content-Disposition
filename like "../../x" could therefore leave Attachment.filename
carrying path-traversal sequences.

Factor the sanitization into a shared _safe_basename() helper (used
by both _s3_filename_from_url and the Content-Disposition path) that
also normalizes backslashes before reducing to a basename, so
Windows-style traversal sequences are handled too.

Fixes #326

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Content-Disposition filename not sanitized on the direct-API attachment path

1 participant