Files
drhider/History/sonnet/2026-08-24-code-review-sonnet.md
T

50 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Код-ревью DrHider — ответ Соннета (2026-08-24)
_sonnet. Промпт: `docs/code-review-sonnet.md` (12 файлов кода, 8 вопросов)._
_Ревью по v0.0.72. Ничего не исправлено — только задокументировано._
## 🔴 Критичные
| Баг | Файл | ~строка | Суть | Фикс |
|---|---|---|---|---|
| **SSRF** | `api_bp.py` `upload_refs` | ~93 | `url` из клиентского JSON без валидации → `httpx.stream("GET", url)` + `follow_redirects=True`. Доступ к metadata/kube-apiserver | валидировать URL-prefix == `VM_UPLOAD_URL` до запроса |
| **Path traversal / zip slip** | `api_bp.py` + `builder.py` | ~88, ~55 | `name = ref.get("name")` без санитизации → `../../evil.md` в выходном ZIP | `name = os.path.basename(ref.get("name",""))` |
## 🟠 Средние
| Баг | Файл | ~строка | Суть |
|---|---|---|---|
| Серверная ошибка не отображается | `api_bp.py` + `index.html` | ~388, ~840 | сервер шлёт `event: error` — это встроенное имя EventSource; клиент не слушает кастомное → «SSE connection failed» вместо реального msg. Переименовать в `proc_error` |
| idx-мисматч при `expand_zips` на бэке | `obfuscator.py` + `index.html` | ~90, sendIdx | фронт фильтрует zip по `.pdf/.doc/.docx/.txt/.md`, бэк расширяет ВСЕ файлы → число/порядок не совпадает → `sendIdx[idx]=undefined` |
| Слабый SID (48 бит) | `session.py` | 85 | `uuid4().hex[:12]`; убрать `[:12]` → 128 бит |
| ZIP-бомба: обход через поддельный `file_size` | `extractor.py` | ~240 | лимит проверяется по `info.file_size` (central dir, подделывается) ДО чтения; проверять ПОСЛЕ `zf.read()` |
| Неатомарность pull при ошибке | `api_bp.py` `upload_refs` | ~115 | при исчерпании ретраев 502 БЕЗ `session_id`; частичная сессия-сирота до TTL |
## 🟡 Мелкие
| Баг | Файл | ~строка | Суть |
|---|---|---|---|
| Отмена не работает в extract-фазе | `obfuscator.py` | ~130 | в extract-цикле нет `cancel_event.is_set()`; .doc (liberta 120с) → отмена ждёт все извлечения |
| TOCTOU: сессия между check и pause_ttl | `api_bp.py` | ~165-171 | `get_files` (lock снят) → `pause_ttl`; маловероятно |
| `fileTimers` не заполняется | `index.html` | ~792 | мёртвый код, fallback всегда 0.0с |
| Self-XSS: `f.name` в innerHTML | `index.html` | ~280, ~380 | имя файла без escaping → `textContent`/`escapeHtml()` |
| ZIP с non-doc расширениями → мусор | `extractor.py` | ~257 | фильтровать расширения в `expand_zips` |
| Сессия не чистится после `/download` | `api_bp.py` | ~430 | 500МБ висит 30 мин → OOM; `cleanup(sid)` |
| LLM-таймаут тихо обнуляет чанк | `llm_client.py` + `scanner.py` | ~70, ~220 | `except → return []`, PII не найден без предупреждения |
| Debug-эндпоинт `session_files` | `api_bp.py` | ~139 | список файлов любой сессии по SID без токена |
| LLM prompt injection | `scanner.py` | ~200 | текст документа дословно в prompt → подавление NER |
## Подтверждено корректным (Соннет)
- Различимость «сессия не найдена» vs «лимит» ✓
- Гонок на `cancel_event`/`queue` нет (thread-safe) ✓
- Утечек httpx/zipfile/EventSource/таймеров нет ✓
- Пустой txt, битый pdf, 0 файлов/все сверх лимита — обрабатываются ✓
## Что уже исправлено ранее (до этого ревью)
- Ретраи pull (v0.0.72) — Соннет отметил остаточную неатомарность.
- Разделение статусов «пропущен (лимит)» / «не извлечён» (v0.0.71).
- Счётчик дедупа (v0.0.72).
## TODO-связь
- Открытый баг кнопки «Обфусцировать» при 0 файлов — `docs/WhatTODO.md` (не покрыт ревью Соннета).