Files
brain/docs/superpowers/specs/2026-06-15-commit-msg-anchor-fix-spec.md
T

36 lines
3.8 KiB
Markdown

# Спека: якорь host-терминатора в commit-message lookahead (security-фикс)
**Дата:** 2026-06-15. Слой: движок (`tools/url-whitelist-rules.mjs`). Источник: автоматическое security-ревью (MEDIUM, Substring/Unanchored Allowlist Bypass).
## Цель
Закрыть обход allowlist в `buildCommitMessageUrlPattern`: negative-lookahead без host-терминатора пропускает subdomain-спуф (`https://liderra.ru.evil.com/exfil` не флагуется → канал утечки). Зеркалить уже-корректный `buildNavigateWhitelistPatterns`. Существующие allow/block-кейсы сохранить.
## Дефект {#D1}
Текущий возврат: `new RegExp('\\bhttps?:\\/\\/(?!' + frags.join('|') + ')\\S+', 'i')`. Фрагменты (`liderra\.ru`, `github\.com/liderra`, …) в lookahead не закрыты терминатором → `liderra.ru.evil.com` совпадает по префиксу `liderra\.ru` → lookahead гасится → URL НЕ флагуется (считается своим). Пре-существующий дефект (был в оригинальном `SUSPICIOUS_MESSAGE_PATTERNS[0]`), перенесён в билдер.
## Фикс {#D2}
Обернуть альтернацию и добавить общий host-терминатор после неё: `new RegExp('\\bhttps?:\\/\\/(?!(?:' + frags.join('|') + ')(?:[:/?#]|$))\\S+', 'i')`. Терминатор `(?:[:/?#]|$)` требует, чтобы за разрешённым доменом шёл порт/путь/запрос/фрагмент или конец — `.` (как в `…ru.evil.com`) и `-` (как в `…liderra-evil`) его не удовлетворяют → спуф флагуется. Зеркало границы `buildNavigateWhitelistPatterns`.
## Инвариант (backward-compat) {#D3}
Легитимные кейсы не меняются: `liderra.ru/x` (после домена `/``[:/?#]` → allow), `docs.anthropic.com/x` (allow), `evil.example.com/p` (нет фрагмента → flag/block). Меняется только спуф: `liderra.ru.evil.com` теперь флагуется (block) — это и есть цель. Существующие тесты `commit-message-scanner.test.mjs` (anthropic/liderra allow, external block, hex/base64/script) остаются GREEN.
## Крайние случаи {#D4}
Спуф-варианты режутся терминатором: `liderra.ru.evil.com` (`.` после `ru`), `liderra-evil.com` (нет фрагмента вовсе). Path-домен `github.com/liderra` + терминатор: `github.com/liderra/repo``/` ∈ → allow; `github.com/liderra-evil``-` ∉ → flag. fail-CLOSED не затронут: пустой whitelist → проектных фрагментов нет → `liderra.ru` любой формы флагуется.
## Критерий {#D5}
Новый тест: `buildCommitMessageUrlPattern(['liderra.ru','github.com/liderra'])``.test('see https://liderra.ru.evil.com/x')` === `true` (флагуется). Существующие билдер-тесты (`liderra.ru/x` false, `docs.anthropic.com/x` false, `evil.example.com/p` true, empty→liderra true) — GREEN. Целевой тест-файл `url-whitelist-rules.test.mjs` GREEN; полный `tools/`-свод — терминал владельца.
```verified-context-json
[
{"id":"fx1","kind":"EXTRACTED","ref":"tools/url-whitelist-rules.mjs","anchor":"buildCommitMessageUrlPattern"},
{"id":"fx2","kind":"EXTRACTED","ref":"tools/url-whitelist-rules.mjs","anchor":"buildNavigateWhitelistPatterns"},
{"id":"fx3","kind":"EXTRACTED","ref":"tools/url-whitelist-rules.mjs","anchor":"BASE_COMMIT_MSG_FRAGS"}
]
```