[Fable 5][P2] §19 redaction-дыры: мобильный 7XXXXXXXXXX без +/8 и ФИО капсом уходят в OpenAI нередактированными #1207

Closed
opened 2026-06-13 04:49:43 +00:00 by bot-backend · 0 comments
Collaborator

Из армейского ревью Claude Fable 5 (2026-06-11)

Confirmed by 2/2 адверсариальных верификатора, severity P2 (security), confidence 0.7.

Файл

backend/app/services/llm/redaction.py:74

Evidence (цитата кода)

_PHONE_RE = re.compile(r"(?:\+7|\b8)[\s\-(]*\d{3}[\s\-)]*\d{3}[\s-]*\d{2}[\s-]*\d{2}\b")
...
_FULLNAME_RE = re.compile(r"\b[А-ЯЁ][а-яё]+\s+[А-ЯЁ][а-яё]+\s+[А-ЯЁ][а-яё]+\b")

Why bug

Для свободного вопроса пользователя (SafePayload.text) regex-scrub — ЕДИНСТВЕННЫЙ барьер перед отправкой в OpenAI (аллоулист контролирует только fields). Проверено выполнением: «79221234567» (самая частая copy-paste форма мобильного — 11 цифр с 7 без +) не матчится ни phone (требует +7/8), ни ИНН (ровно 10/12 цифр) — уходит наружу как есть. «ИВАНОВ ИВАН ИВАНОВИЧ» (стандарт ЕГРН/паспортных выписок) не матчится _FULLNAME_RE (требует строчные после первой буквы). СНИЛС без разделителей (11 цифр) тоже проходит. При llm_enabled=True PII покидает РФ — нарушение §19/152-ФЗ.

Suggested fix

Расширить префикс телефона: (?:+?7|\b8) и/или матчить 11-значные последовательности, начинающиеся с 7/8 ((?<!\d)[78]\d{10}(?!\d)); в _FULLNAME_RE добавить капс-вариант слова ([А-ЯЁ][а-яё]+|[А-ЯЁ]{2,}); покрыть СНИЛС без разделителей.

Verify notes

  • [real/P2] Подтверждено выполнением: «79221234567» не матчится ни phone (нужен +7/\b8), ни INN (ровно 10/12 цифр, 11 мимо); «ИВАНОВ ИВАН ИВАНОВИЧ» не матчится fullname ([а-яё]+ требует строчные); СНИЛС «12345678901» без дефисов проходит. Трасса: orchestrator.py:140 message → SafePayload.text (safe_payload.py:77, без препроцессинга) → client.py:186 scrub → OpenAI. Для вопроса юзера scrub — единственный барьер. P2: вторичный слой, PII самозаявленный, allowlist/hard-block целы.
  • [real/P2] Проверено выполнением реальных regex: «79221234567» не матчит ни один из 6 паттернов (phone требует +7/\b8; ИНН — ровно 10/12 цифр, тут 11), «ИВАНОВ ИВАН ИВАНОВИЧ» не матчит _FULLNAME_RE, голый СНИЛС (11 цифр) проходит. Для chat-пути вопрос юзера уходит в SafePayload.text БЕЗ аллоулиста — scrub единственный барьер; апстрим лишь Field(min_length=1). Тесты не фиксируют это как accepted limitation; комментарий FIO декларирует «лучше лишний REDACTED». llm_enabled default False смягчает → P2.

Provenance

  • Finders: chat-llm
  • Confidence: 0.7
  • Originally batched at: main@d796027
## Из армейского ревью Claude Fable 5 (2026-06-11) Confirmed by 2/2 адверсариальных верификатора, severity **P2** (security), confidence 0.7. ## Файл [`backend/app/services/llm/redaction.py:74`](backend/app/services/llm/redaction.py:74) ## Evidence (цитата кода) ``` _PHONE_RE = re.compile(r"(?:\+7|\b8)[\s\-(]*\d{3}[\s\-)]*\d{3}[\s-]*\d{2}[\s-]*\d{2}\b") ... _FULLNAME_RE = re.compile(r"\b[А-ЯЁ][а-яё]+\s+[А-ЯЁ][а-яё]+\s+[А-ЯЁ][а-яё]+\b") ``` ## Why bug Для свободного вопроса пользователя (SafePayload.text) regex-scrub — ЕДИНСТВЕННЫЙ барьер перед отправкой в OpenAI (аллоулист контролирует только fields). Проверено выполнением: «79221234567» (самая частая copy-paste форма мобильного — 11 цифр с 7 без +) не матчится ни phone (требует +7/8), ни ИНН (ровно 10/12 цифр) — уходит наружу как есть. «ИВАНОВ ИВАН ИВАНОВИЧ» (стандарт ЕГРН/паспортных выписок) не матчится _FULLNAME_RE (требует строчные после первой буквы). СНИЛС без разделителей (11 цифр) тоже проходит. При llm_enabled=True PII покидает РФ — нарушение §19/152-ФЗ. ## Suggested fix Расширить префикс телефона: (?:\+?7|\b8) и/или матчить 11-значные последовательности, начинающиеся с 7/8 ((?<!\d)[78]\d{10}(?!\d)); в _FULLNAME_RE добавить капс-вариант слова ([А-ЯЁ][а-яё]+|[А-ЯЁ]{2,}); покрыть СНИЛС без разделителей. ## Verify notes - [real/P2] Подтверждено выполнением: «79221234567» не матчится ни phone (нужен +7/\b8), ни INN (ровно 10/12 цифр, 11 мимо); «ИВАНОВ ИВАН ИВАНОВИЧ» не матчится fullname ([а-яё]+ требует строчные); СНИЛС «12345678901» без дефисов проходит. Трасса: orchestrator.py:140 message → SafePayload.text (safe_payload.py:77, без препроцессинга) → client.py:186 scrub → OpenAI. Для вопроса юзера scrub — единственный барьер. P2: вторичный слой, PII самозаявленный, allowlist/hard-block целы. - [real/P2] Проверено выполнением реальных regex: «79221234567» не матчит ни один из 6 паттернов (phone требует +7/\b8; ИНН — ровно 10/12 цифр, тут 11), «ИВАНОВ ИВАН ИВАНОВИЧ» не матчит _FULLNAME_RE, голый СНИЛС (11 цифр) проходит. Для chat-пути вопрос юзера уходит в SafePayload.text БЕЗ аллоулиста — scrub единственный барьер; апстрим лишь Field(min_length=1). Тесты не фиксируют это как accepted limitation; комментарий FIO декларирует «лучше лишний REDACTED». llm_enabled default False смягчает → P2. ## Provenance - Finders: `chat-llm` - Confidence: 0.7 - Originally batched at: main@d796027
bot-backend added the
Fable 5 ревью
label 2026-06-13 04:49:43 +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#1207
No description provided.