
Уведомление: CVE-2026-38360 — обход пути (CWE-22) в dash-uploader (Python/PyPI)
Неаутентифицированный обход пути в fohrloop/dash-uploader (Python, PyPI), позволяющий произвольную запись файлов и приводящий, помимо прочего, к удалённому выполнению кода (RCE), перезаписи исходного кода приложения, хранимому XSS и установке постоянного бэкдора.
Репозиторий был архивирован 2025-07-19, активного мейнтейнера нет. Все опубликованные версии (с 0.1.0 по 0.7.0a2) уязвимы и останутся таковыми. Пакет по-прежнему скачивается примерно 28 000 раз в месяц.
Каждому, кто использует dash-uploader в продакшене, необходимо самостоятельно применить меры по смягчению уязвимости. Рекомендуемое решение — перейти на встроенный компонент dcc.Upload из Plotly Dash. Полный список вариантов см. в разделе Меры по смягчению.
| Идентификатор CVE | CVE-2026-38360 (NVD) |
| Уязвимость | Обход пути (CWE-22) |
| CVSS 3.1 | 9.8 / Критический (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| Продукт | dash-uploader |
| Затронутые версии | 0.1.0 – 0.7.0a2 (все 18 релизов) |
| Исправленная версия | отсутствует (проект архивирован 2025-07-19) |
| Вектор атаки | Удалённый, без аутентификации |
| Обнаружил | Muhammad Fitri Bin Mohd Sultan |
| Присвоен | MITRE, 2026-05-07 |
| Связанные | CVE-2026-38361 (DoS в той же библиотеке) |
Три управляемых пользователем параметра из request.form.get() в dash_uploader/httprequesthandler.py передаются напрямую в os.path.join() и os.makedirs() без какой-либо очистки или проверки:
upload_id (строки 57 → 161, BaseHttpRequestHandler.get_temp_root): управляет целевым каталогом. Атакующий может отправить upload_id=../../../../usr/local/lib/python3.10/site-packages, и файлы будут записаны в каталог пакетов Python.
resumableFilename (строки 51 → 108, BaseHttpRequestHandler._post): управляет итоговым именем файла. Атакующий может выйти за пределы каталога загрузки через имя файла даже при легитимном upload_id.
resumableIdentifier (строки 54 → 64, BaseHttpRequestHandler._post): используется с os.makedirs() для создания временного каталога. Атакующий может создавать произвольные каталоги в любом месте файловой системы.
Конечная точка загрузки (по умолчанию /API/dash-uploader) не требует аутентификации. Хук http_request_handler, добавленный в v0.5.0, позволяет выполнять проверки перед запросом через post_before(), но уязвимый метод _post() читает все параметры напрямую из request.form после возврата из хука. Хук не может очистить параметры до того, как библиотека их обработает. Разработчик, добавивший аутентификацию через хук, по-прежнему уязвим к обходу пути со стороны аутентифицированного пользователя.
# dash_uploader/httprequesthandler.py
def _post(self):
resumableFilename = request.form.get("resumableFilename", default="error", type=str)
resumableIdentifier = request.form.get("resumableIdentifier", default="error", type=str)
upload_id = request.form.get("upload_id", default="", type=str)
...
temp_root = self.get_temp_root(upload_id) # upload_id flows in here
temp_dir = os.path.join(temp_root, resumableIdentifier) # raw user input -> os.path.join
if not os.path.isdir(temp_dir):
os.makedirs(temp_dir) # raw user input -> os.makedirs
def get_temp_root(self, upload_id):
return os.path.join(self.upload_folder, upload_id) # no sanitization: ../../ escapes upload_folder
Три независимых небезопасных места (sink) имеют одну и ту же первопричину: значения формы достигают os.path.join и os.makedirs без проверки.
Неаутентифицированный удалённый атакующий отправляет HTTP POST multipart-запрос на конечную точку загрузки. Внедряя последовательности обхода пути (../) в параметр формы upload_id, атакующий получает контроль над целевым каталогом для загружаемого файла. Например, upload_id=../../../../usr/local/lib/python3.10/site-packages записывает файлы в каталог пакетов Python, что позволяет выполнить код (RCE) при следующем запуске интерпретатора за счёт автоматического выполнения .pth.
Ни аутентификация, ни сессионный токен, ни CSRF-токен не требуются. Два дополнительных параметра (resumableFilename и resumableIdentifier) предоставляют независимые векторы обхода через ту же конечную точку. Конфигурация библиотеки по умолчанию, показанная в официальной документации quickstart, эксплуатируется одной командой curl.
Произвольная запись файлов в любой каталог, доступный для записи процессу сервера. Это приводит к удалённому выполнению кода (RCE) с помощью нескольких хорошо известных примитивов:
Примитивы RCE
.pth, записанный в site-packages. Выполняет код, предоставленный атакующим, при следующем запуске интерпретатора.sitecustomize.py или usercustomize.py. Выполняется при каждом запуске Python.app.wsgi, wsgi.py). Выполняется при следующей перезагрузке воркера./etc/cron.d/, /etc/cron.hourly/, пользовательский crontab-spool) при наличии у процесса необходимых привилегий. Выполнение по расписанию./etc/systemd/system/, ~/.config/systemd/user/). Выполняется при следующем запуске службы или перезагрузке./etc/ld.so.preload, если процесс запущен от root. Предзагружает код атакующего при каждом последующем выполнении бинарных файлов.~/.bashrc, ~/.profile, ~/.bash_profile). Выполняется при следующем интерактивном входе пользователя приложения.~/.ssh/authorized_keys. Предоставляет постоянный SSH-доступ к хосту от имени пользователя приложения.Воздействие на веб-уровень
site-packages). Затрагивает каждого пользователя при каждой загрузке страницы до перезапуска приложения.