Отрицательный query-param limit на 7 GET-эндпоинтах admin_scrape → 'LIMIT -N' → необработанный 500 вместо 422 #1563

Closed
opened 2026-06-16 17:05:33 +00:00 by bot-backend · 0 comments
Collaborator

Severity: low · Категория: input-validation/error-leak · Файл: backend/app/api/v1/admin_scrape.py:271-275, 317-322, 486-501, 970-987, 1090-1098, 1148-1152, 1419-1432

Файл admin_scrape.py: list_failures(:271), list_logs(:317), list_objective_runs(:486), list_geo_jobs(:970), list_all_runs(:1090), list_all_logs(:1148), list_runs(:1419). Все объявляют limit: int = N без нижней границы (нет ge= и нет fastapi.Query(ge=0)) и клампят только сверху через min(limit, 200|1000|100) — например :275 {'lim': min(limit, 200)}, :322 min(limit, 1000), :501/:1432 min(limit, 100), :1098 min(limit, 200), :1152 min(limit, 1000). min() не отсекает отрицательное: min(-5, 200)==-5. Значение биндится в SQL 'LIMIT :lim' (:288, :338, :498, :1112, :1168, :1429 + geo/jobs). ИМПАКТ: GET /api/v1/admin/scrape/runs?limit=-1 (и аналоги для остальных 6) → PostgreSQL 'ERROR: LIMIT must not be negative' → psycopg DataError протекает наружу как 500 Internal Server Error вместо корректного 422 Validation Error; UI-полл дашборда падает. Порчи данных нет, эндпоинты админ-only. ФИКС: добавить нижнюю границу через FastAPI Query — limit: int = Query(default=N, ge=1, le=MAX) (le заодно заменит ручной min()), либо как минимум кламп max(1, min(limit, MAX)). Применить ко всем 7 эндпоинтам единообразно.

Почему баг: Запрос GET /api/v1/admin/scrape/runs?limit=-1 (и аналоги) даёт psycopg DataError, который протекает наружу как 500 Internal Server Error вместо 422 Validation Error. Фокус-зона задачи прямо называет валидацию входа (min>max). Severity low: эндпоинты админские, это краш hot-path только в смысле UI-полла, не порча данных. FastAPI clamp сверху есть, нижней границы нет.

Как чинить: Объявить лимиты как limit: Annotated[int, Query(ge=1, le=<max>)] = N (или Field(ge=1)) — тогда отрицательные/нулевые значения отсекаются на уровне валидации 422, а верхняя граница задаётся через le, что заодно убирает ручной min().


deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.88 · unit B03

**Severity:** low · **Категория:** input-validation/error-leak · **Файл:** `backend/app/api/v1/admin_scrape.py:271-275, 317-322, 486-501, 970-987, 1090-1098, 1148-1152, 1419-1432` Файл admin_scrape.py: list_failures(:271), list_logs(:317), list_objective_runs(:486), list_geo_jobs(:970), list_all_runs(:1090), list_all_logs(:1148), list_runs(:1419). Все объявляют limit: int = N без нижней границы (нет ge= и нет fastapi.Query(ge=0)) и клампят только сверху через min(limit, 200|1000|100) — например :275 {'lim': min(limit, 200)}, :322 min(limit, 1000), :501/:1432 min(limit, 100), :1098 min(limit, 200), :1152 min(limit, 1000). min() не отсекает отрицательное: min(-5, 200)==-5. Значение биндится в SQL 'LIMIT :lim' (:288, :338, :498, :1112, :1168, :1429 + geo/jobs). ИМПАКТ: GET /api/v1/admin/scrape/runs?limit=-1 (и аналоги для остальных 6) → PostgreSQL 'ERROR: LIMIT must not be negative' → psycopg DataError протекает наружу как 500 Internal Server Error вместо корректного 422 Validation Error; UI-полл дашборда падает. Порчи данных нет, эндпоинты админ-only. ФИКС: добавить нижнюю границу через FastAPI Query — limit: int = Query(default=N, ge=1, le=MAX) (le заодно заменит ручной min()), либо как минимум кламп max(1, min(limit, MAX)). Применить ко всем 7 эндпоинтам единообразно. **Почему баг:** Запрос `GET /api/v1/admin/scrape/runs?limit=-1` (и аналоги) даёт psycopg DataError, который протекает наружу как 500 Internal Server Error вместо 422 Validation Error. Фокус-зона задачи прямо называет валидацию входа (min>max). Severity low: эндпоинты админские, это краш hot-path только в смысле UI-полла, не порча данных. FastAPI clamp сверху есть, нижней границы нет. **Как чинить:** Объявить лимиты как `limit: Annotated[int, Query(ge=1, le=<max>)] = N` (или Field(ge=1)) — тогда отрицательные/нулевые значения отсекаются на уровне валидации 422, а верхняя граница задаётся через le, что заодно убирает ручной min(). --- <sub>deep-audit backend v2 (после PR #1543) · verify+harden, confidence 0.88 · unit B03</sub>
bot-backend added the
week ревью 1
label 2026-06-16 17:05:33 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1563
No description provided.