Контекст
Аудит 2026-07-08 отметил defense-in-depth риск в локальном web UI: клиентский esc() экранирует HTML-текстовый контекст, но не кавычки для атрибутов. Сейчас источник g.url внутренний и риск низкий, но WEB MVP будет расширять action/error cards, поэтому лучше закрыть это до роста поверхности.
Проблема
В src/stepik_grader/web.py значение g.url вставляется в href="...". Если значение содержит кавычку или иной атрибутный спецсимвол, текущий escaper может не защитить атрибутный контекст. Это не выглядит как срочная XSS-уязвимость в текущей локальной модели, но является слабым местом при развитии WEB MVP.
Scope
src/stepik_grader/web.py
- клиентский
esc() / отдельный attribute escaper / безопасная сборка ссылок
- тесты web-слоя на URL или поля с кавычками
Non-goals
- НЕ вводить frontend framework.
- НЕ менять контракт
/api/grade.
- НЕ реализовывать весь WEB MVP.
- НЕ менять формат glossary entries без необходимости.
Acceptance criteria
Ветка
fix/web-attr-escape
Источник
Deep audit 2026-07-08: P2 defense-in-depth finding.
Контекст
Аудит 2026-07-08 отметил defense-in-depth риск в локальном web UI: клиентский
esc()экранирует HTML-текстовый контекст, но не кавычки для атрибутов. Сейчас источникg.urlвнутренний и риск низкий, но WEB MVP будет расширять action/error cards, поэтому лучше закрыть это до роста поверхности.Проблема
В
src/stepik_grader/web.pyзначениеg.urlвставляется вhref="...". Если значение содержит кавычку или иной атрибутный спецсимвол, текущий escaper может не защитить атрибутный контекст. Это не выглядит как срочная XSS-уязвимость в текущей локальной модели, но является слабым местом при развитии WEB MVP.Scope
src/stepik_grader/web.pyesc()/ отдельный attribute escaper / безопасная сборка ссылокNon-goals
/api/grade.Acceptance criteria
hrefили другие HTML-атрибуты, не могут разорвать атрибут кавычкой.pytest tests/ -x -q --tb=short,ruff check .,ruff format --check .,mypy src/stepik_grader --ignore-missing-importsзелёные.Ветка
fix/web-attr-escapeИсточник
Deep audit 2026-07-08: P2 defense-in-depth finding.