18 KiB
name, description
| name | description |
|---|---|
| fix-finding | Исправление и верификация конкретной security-находки в проекте НЕОН (site/crm/db). Использовать, когда пользователь явно просит исправить, закрыть или залечить уязвимость или finding из аудита — «исправь F-3», «закрой находку из AUDIT/FINDINGS.md», «почини IDOR из аудита и проверь». НЕ использовать для обычных багов, рефакторинга, ревью кода/дизайна, полного аудита (полный аудит делает скилл security-audit — он только документирует) или деплоя. |
Fix Finding — минимальный проверенный фикс security-находки в НЕОН
Превратить текущую security-находку в минимальный, проверенный на живом стенде
код-фикс. Если код уже безопасен — доказать это и вернуть no_change.
Аудит (поиск и документирование) делает скилл security-audit; этот скилл —
вторая стадия над его результатами.
Источник находки
Найди ID и контекст в одном из мест:
AUDIT/FINDINGS.md— вывод аудит-скиллаsecurity-audit;АУДИТ-ПЕРЕД-РЕЛИЗОМ.md— предрелизный аудит, нумерация 1–38 (пункт с пометкой «вопрос к владельцу» — не фикси, этоblocked);- F-N — сквозная нумерация security-фиксов в комментариях кода
(
docker-compose.yml,crm/server.py) и вcrm/_security_smoke.mjs; - прямое описание от пользователя (файл/эндпоинт + путь атаки).
Если в находке нет файла/эндпоинта — сначала локализуй путь атаки по коду. Фиксить можно только явно запрошенную находку; соседние находки — доложить, не чинить.
Порядок свойств результата
Оценивай результат в этом порядке; более раннее никогда не меняется на более позднее. «Минимальный» = наименьшее проектно-нативное изменение, закрывающее все более ранние свойства, а не наименьшее число строк:
- текущее состояние корректно классифицировано: уязвимо / уже безопасно / недоказано
- фикс полностью закрывает нарушенную security-границу
- легитимное поведение и совместимость сохранены
- проверки проекта (см. гейты ниже) пройдены
- реализация следует конвенциям проекта
- патч содержит только необходимый охват
Карта проекта
crm/— Python 3, stdlib + psycopg, без фреймворков.server.py— HTTP + REST + роли;notes_api.py— доски заметок (примешан в Handler);storage.py— PostgreSQL (боевой),storage_sqlite.py— dev-двойник (ограничен: игры/доски/брони/миксы сайта/сброс нумерации → 501);js/app.js+index.html+css/— панель персонала;seed/*.json— каталог;migrate/notes_boards.sql— канонический DDL досок.site/— React + Vite + Tailwind, собирается в статику под nginx.nginx.conf— edge: лимитPOST /api/orders(10/мин с IP), real_ip из X-Forwarded-For,/media/отдаёт фото CRM;src/lib/crm.ts— мост к API.docker-compose.yml— site (наружу127.0.0.1:8080), crm (127.0.0.1:47613), db (PostgreSQL 17, не публикуется). Секреты только из.env.- Роли CRM: владелец / администратор / официант / кальянщик — матрица в README; пять слоёв защиты заказов (nginx-лимит → лимит на гостя → дедупликация → глобальный тормоз → honeypot).
- Git в проекте НЕТ: перед правкой делай снимок (см. ниже), diff собирай по снимкам.
Фикс может жить на любом из трёх слоёв (nginx → server.py → storage).
Логика storage продублирована в двух бэкендах: фикс в storage.py почти
всегда должен зеркалиться в storage_sqlite.py (и наоборот) — аудит не раз
писал «в обоих бэкендах». Учитывай и панель (crm/js/app.js): что она
ожидает от изменённого эндпоинта.
Патч-контракт (до правки)
Изучи саму реализацию, её прямых вызователей, соседние хелперы и разметку роль×эндпоинт в README. Установи из кода, а не из находки:
- атакующий вход и конкретный путь источник → sink (или сломанный контроль);
- security-инвариант и узкую общую границу, где его enforce;
- легитимное поведение, API-контракты, семантику ошибок, совместимость;
- ближайшие прецеденты в этом же коде (экранирование
esc()в панели, параметризованный SQL%s, whitelist статики, лимитеры).
Находка — задача о потоке данных и границе, а не о примере входа из отчёта. Проверь эквивалентные кодировки, alternate-формы парсера, алиасы, всех вызователей, оба бэкенда и каждую копию security-чувствительного состояния, которая может обойти фикс. Небезопасное состояние обрабатывай явно — не принимай, не обрезай и не переинтерпретируй его молча.
Предпатчевое расследование
До правки запусти один свежий read-only субагент (Agent tool, general-purpose, с инструкцией не менять файлы). Если делегирование недоступно — сделай тот же проход сам отдельно, свежим взглядом:
- Исследователь границы и совместимости: независимо трассирует путь источник → sink, находит общую границу enforcement, затронутые входы, альтернативные представления и состояния, переходы валидация → использование, конкретные sibling-пути и обходы. Фиксирует легитимные сценарии и публичное поведение, которые обязаны остаться, и проверяет вызователей, режимы, ошибки, побочные эффекты, конвенции, готовые хелперы и применимые команды проверки.
Расследование требует ссылок на файлы/строки проекта и разделения фактов, выводов и открытых вопросов. По завершении сверь с собственной трассировкой и выбери границу фикса.
Снимки вместо git
Перед первым изменением скопируй оригиналы изменяемых файлов в
AUDIT/FIXES/.snapshots/<ID>/ (создай каталог). По снимкам собери diff для
ревью и отчёта (PowerShell Compare-Object, fc или git diff --no-index,
если git есть на хосте). Не оставляй временных файлов-двойников вида .bak
в рабочем дереве после завершения.
Реализация
- Протрассируй путь и верни
no_change, если код уже безопасен — без спекулятивных правок. - Где возможно, прогони через границу минимальный высокосигнальный repro и один легитимный контрольный запрос по тому же пути (живой стенд ниже).
- Сделай наименьший фикс на общей границе. Предпочитай соседние хелперы и установленные API. Не расширяйся на редизайн, уборку и соседние находки.
- До верификации атакуй свой патч, а не защищай: проверь каждого прямого вызователя изменённого хелпера и обе ветки каждого изменённого условия. Найди (а) один sibling-путь, представление или копию, которые всё ещё доходят до sink, (б) один обычный/дефолтный вход, который патч начал отвергать или переинтерпретировать. Если хоть одно есть — переделай.
- Верифицируй по гейтам (порядок обязателен).
Гейты верификации
- Синтаксис/сборка — только изменённое:
- Python:
python -m py_compile crm\server.py crm\storage.py crm\storage_sqlite.py crm\notes_api.py(в crm/); - сайт (если тронут
site/): изsite/—npx tsc --noEmit, затемnpm run build; - движок миксов (если тронут
site/srcмиксы/стоп-лист):npm run test:engine.
- Python:
- Security-триггер — repro находки на живом стенде больше не воспроизводится + один альтернативный класс вредоносного входа.
- Легитимный контроль — обычный сценарий по тому же пути работает; соседние роли не сломаны (токены owner/admin/waiter — матрица в README).
Живой стенд
- Postgres-стек (нужен для игр, досок, броней, миксов, сброса нумерации —
в sqlite это 501):
docker compose up -d --build, CRM на127.0.0.1:47613, сайт на127.0.0.1:8080. - SQLite-стенд без Docker:
start-crm.bat(CRM_DB=sqlite,CRM_ALLOW_DEFAULT_PASSWORDS=1, порт 47613). - Сайт-дев: в
site/npm run dev; если docker уже держит 8080 —npm run dev -- --port 8090 --strictPort. - Перед стартом проверь, кто слушает порт (
netstat -ano | findstr :47613): 8080/47613 держит docker-стек, 8081 — чужой процесс, его не трогать. - Доступы стенда — из
.env(SMOKE_* нет в .env — задавай при запуске скрипта).
Регрессионный артефакт
Проект верифицирует фиксы smoke-скриптами по образцу crm/_security_smoke.mjs:
fetch против 127.0.0.1:47613, PASS/FAIL, ненулевой exit при провале,
пароли через env (SMOKE_OWNER_PW, SMOKE_WAITER_PW). Добавь проверки
фикса в _security_smoke.mjs или создай сфокусированный crm/_fix_<ID>.mjs
по тому же образцу. Помни побочные эффекты: lockout-тест закрывает
waiter.mark на 15 минут (порядок проверок важен), тест смены пароля обязан
возвращать пароль обратно.
Ревью кандидата
После реализации и фокусных проверок запусти одного свежего read-only субагента (Agent tool; инструкции не редактировать и не делегировать). Дай ему только находку, корень проекта, авторизованный объём, конвенции и текущий diff кандидата — без обоснований, отчёта исследователя и заявлений, что тесты прошли. Если делегирование недоступно — сделай этот проход сам, отдельно, до финальной верификации:
- Ревьюер обходов и регрессий: реконструирует инвариант и ищет конкретный выживший маршрут через затронутые входы, эквивалентные представления, границы парсеров, алиасы, оба бэкенда, слой nginx и щели валидация → использование; трассирует изменённые условия и вызователей на предмет конкретной поломки легитимных входов, контрактов, ошибок, побочных эффектов и конвенций.
Находки ревьюера — гипотезы: подтверждай их по коду или фокусным запуском, правь только подтверждённые в рамках находки и совместимости. Затем прогони затронутые гейты заново и убедись, что временных и посторонних изменений не осталось. Только один цикл ревью.
Верни blocked, если находка может быть реальной, но не хватает существенных
данных, инструментария, доступа или это продуктовое решение владельца
(пример: №38 «waiter вне смены видит телефоны» из предрелизного аудита) —
тогда безопасный фикс невозможно завершить или проверить.
Отчёт
Напиши AUDIT/FIXES/<ID>.md и проставь в источнике находки (AUDIT/FINDINGS.md
или АУДИТ-ПЕРЕД-РЕЛИЗОМ.md) статус фикса со ссылкой на отчёт. В финальном
ответе в чате обязательно:
- outcome:
fixed/no_change/blocked - конкретный уязвимый путь, security-инвариант и легитимное поведение, которое обязано было сохраниться
- выбранная стратегия и почему это самый узкий полный вариант (либо — какое
решение владельца отсутствует при
blocked) - изменённые файлы и добавленные тесты/артефакты
- команды по гейтам с результатами pass/fail/unknown
- как показано, что исходная находка больше не воспроизводится
- как показано, что легитимное поведение сохранилось
- оставшиеся пробелы и пропущенные проверки, если есть
Жёсткие правила
- Не докладывай
fixed, пока не пройдены все гейты по порядку. Проверку можно пропустить только с обоснованием по коду; недоступная существенная проверка =blockedи явное указание, чего не хватило. - Не полагайся только на чтение кода, когда возможен фокусный repro на стенде.
- Не расширяй патч на уборку, соседние находки и редизайн без доказательства, что без этого граница не закрывается.
- Не удаляй и не затирай правки пользователя — git нет, снимки единственная
страховка; не трогай
crm/data/,crm/media/,.envиsite/dist. - Не ослабляй авторизацию, ролевую матрицу, пять слоёв защиты заказов, валидацию входа, fail-fast на дефолтных паролях и лимитеры ради зелёных проверок.
- Не деплой на прод (
docker compose up -d --build site crm) без явной команды владельца — верификация идёт на локальном стенде. - Не прячь пробелы доказательств: если среда не дала проверить — назови команду и чего не хватает.