# v0.0.73 — фиксы по код-ревью Соннета (безопасность + явные баги) (2026-08-24) _code-fixes. По ревью `History/sonnet/2026-08-24-code-review-sonnet.md` (промпт `docs/code-review-sonnet.md`)._ _Критично перепроверены в коде; спорные пункты — отклонены/отложены (см. ниже)._ ## Исправлено (6 фиксов) 1. **SSRF** (`api_bp.py::upload_refs`) — добавлена валидация `url.startswith(VM_UPLOAD_PREFIX)`; недоверенный URL пропускается. Константа `VM_UPLOAD_PREFIX = "https://contracts.kube5s.ru/drhider-upload/"`. 2. **Path traversal / zip slip** (`api_bp.py`) — функция `_safe_name()`: нормализует слэши, отбрасывает `..` и абсолютные пути, сохраняя подпапки (`Подпапка/Акт.txt` → как есть, `../../evil.pdf` → ""). Применена в `upload` и `upload_refs`. Unit-тест 8 кейсов — все OK. 3. **Слабый SID** (`session.py`) — `uuid.uuid4().hex[:12]` → `uuid.uuid4().hex` (128 бит). 4. **Серверная ошибка не отображалась** — серверное событие `event: error` (конфликт с встроенным EventSource) → `event: proc_error`; добавлен клиентский `addEventListener('proc_error', …)` с показом сообщения. 5. **ZIP-бомба: обход через поддельный `file_size`** (`extractor.py`) — добавлена проверка `total_uncompressed > MAX_UNCOMPRESSED` ПОСЛЕ `zf.read()` с `break` (ранний выход). 6. **Self-XSS через имя файла** (`index.html`) — добавлена `esc()` и применена к `f.name` в `rr()` и `procRow()`. ## Отклонено (критично к Соннету) - **«cleanup(sid) после /download»** — НЕ сделано: ZIP и CSV скачиваются РАЗДЕЛЬНЫМИ запросами; удаление сессии после отдачи ZIP сломало бы скачивание CSV. Сессия и так чистится по TTL (30 мин). ## Отложено (требуют решения/риск) - idx-мисматч при `expand_zips` (фильтр расширений на бэке) — связано с фичей v0.0.69 (zip без документов «как есть»), требует решения по поведению. - Отмена не проверяется в extract-фазе (.doc liberta 120с) — отдельный фикс. - LLM-таймаут тихо обнуляет чанк — логирование/статус. - Debug-эндпоинт `session_files` — ограничить/закрыть. - LLM prompt injection — задокументировать (класс риска, не фикс кода). ## Проверка - `py_compile` (app.py, api_bp.py, session.py, extractor.py) — OK; `node --check` — OK. - `_safe_name` unit-тест — 8/8 OK. - `create_app()` стартует (VERSION 0.0.73). - Версия 0.0.72 → 0.0.73. ## Проверка на проде (редеплой 20:00, v0.0.73) - SSRF: `POST /api/upload_refs` с `url=http://169.254.169.254/...` → `{"count":0,"ok":true}` (URL отклонён). - Path traversal: `name="../../evil.txt"` → `{"count":0,"ok":true}` (имя отклонено). - SID теперь полный 32 hex (128 бит) — виден в ответе. - Регресс: папка с подпапкой + кириллицей → «Обработано 2 файлов: 4.3с», в ZIP `Подпапка/Договор_1.md` + `Акт.md` (пути сохранены, `_safe_name` не сломал подпапки).