Skip to content

fix(datasource): store Excel uploads under a sanitised name #1448 - #1449

Merged
XiaJunjie2020 merged 4 commits into
dataease:mainfrom
borealisalastor-byte:fix/1448-upload-file-name
Nov 9, 2026
Merged

XiaJunjie2020 merged 4 commits into
dataease:mainfrom
borealisalastor-byte:fix/1448-upload-file-name

Conversation

@borealisalastor-byte

Copy link
Copy Markdown
Contributor

Cause

/datasource/parseExcel and the deprecated /datasource/uploadExcel derive the stored file name from the multipart file.filename:

  • parse_excel split the name on / and dropped everything before the first dot, so a Windows-style name kept its directory part (..\..\evil.xlsx -> ..\evil_<hash>.xlsx) and a drive-relative one kept its drive (C:evil.xlsx -> C:evil_<hash>.xlsx);
  • upload_excel used the raw name and took the extension from split('.')[1], which also raised IndexError for names without a dot;
  • neither route resolved the write target, so on a Windows host the file could leave settings.EXCEL_PATH;
  • upload_excel matched bare suffixes ({"xlsx", "xls", "csv"}), so evil.txlsx passed as well.

This is the write side of the same class that #1434 / #1435 fixed for importToDb; apps/terminology/api/terminology.py and apps/data_training/api/data_training.py already strip the client path before writing.

Fix

  • new common.utils.utils.safe_upload_name: keeps the last path component of a client-supplied name after treating both / and \ as separators, and rejects names that would still address another location (empty, ., .., a drive-relative or alternate-stream :, an embedded NUL);
  • both Excel upload routes answer 400 for such a name, build the stored name with os.path.splitext (so a.b.xlsx keeps its stem) and resolve it through one shared helper that requires the result to stay inside EXCEL_PATH (os.path.realpath + os.path.commonpath);
  • upload_excel now matches dotted suffixes, which removes the IndexError path for dot-less names.

Tests

  • backend/tests/test_upload_file_name.py: unit contract of safe_upload_name for POSIX, Windows, mixed and drive-relative names, plus the set that must be rejected;
  • backend/tests/test_datasource_upload_path_traversal.py: reuses the offline harness of the existing import-traversal guard, posts real multipart bodies to both routes and asserts that the stored name is a single component inside the upload directory (or that the request is refused) and that nothing is written outside it.

Verification

  • python -m pytest -q tests/test_upload_file_name.py -> 31 passed, run in backend/ on a checkout of main at a0b6145;
  • the endpoint source was additionally driven through the same offline function loading the guards use, with hostile names: before the change nested\..\..\evil.xlsx resolved outside the upload directory and C:\Users\me\orders.xlsx to an absolute path, after the change every accepted name is a single component inside the directory and C:evil.xlsx is refused with 400;
  • ruff check and ruff format --check pass on the touched files.

Not covered here

  • backend/tests/test_datasource_upload_path_traversal.py imports the published sqlbot-xpack wheel and the database drivers, so it runs in CI rather than in the sandbox where the change was prepared;
  • the full uv run pytest -q suite was not run in that sandbox;
  • the deprecated route continues into the import engine, which the tests stub out.

Fixes #1448

…aease#1448

Adds safe_upload_name: a client-supplied upload name is reduced to a single path component (both separators count) and names that would still address another location are rejected.
…1448

parseExcel and the deprecated uploadExcel now drop every path component from the client name, refuse drive-relative names, match dotted extensions and resolve the write path with realpath plus commonpath.
Unit contract for safe_upload_name across POSIX, Windows and drive-relative names.
Reuses the offline harness of the import-traversal guard and posts multipart bodies with hostile file names.
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.

[BUG] parseExcel/uploadExcel 用客户端文件名落盘,Windows 下可越出上传目录 (CWE-22)

2 participants