36 lines
3.8 KiB
Markdown
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"}
|
|
]
|
|
```
|