Невидимый текст, который ломает интернеты

 Публичный пост
16 апреля 2024  3111
ОХУЕННО ⨯2 Держи долор ⨯2 Я понял!

А вы знали, что есть невидимые символы шириной в 0 пикселей, и они влияют на работу многих систем - от поисковой выдачи до LLM и парсеров? Есть даже отдельные символы, чтобы текст отображался справа налево!

Сокращенную версию поста можно прочитать тут

Скопируйте эти цифры (1⁣⁠​2⁣⁣⁣​​3⁣⁣​4​​​​5) и пролистайте их: курсор не будет перемещаться между символами с каждым нажатием стрелки на клавиатуре - в тех местах и вставлены невидимые символы. Они влияют на парсинг и SEO, могут повредить ссылки и распознаются LLM.

В первом слове невидимый символ меняет токенизацию, а не просто добавляет еще один токен
В первом слове невидимый символ меняет токенизацию, а не просто добавляет еще один токен

Их можно использовать как водяные знаки: если кто-то разместит копию текста, будет очевидно, что он украден - невидимые отметки сохранятся при копировании. Также можно сделать несколько версий текста и закодировать id или имена пользователей, которым вы его отправляете.

Системы анти-спама или анти-фишинга, как правило, ищут совпадения со словами в базе. Если добавить, например, невидимые пробелы, то текст для читающего будет отображаться без видимых изменений, при этом он пройдет проверку на фишинг. А если разрешить ввод символов юникода в юзернеймах (например, чтобы можно было ввести иероглифы), то у вас могут появиться юзеры с невидимыми и некликабельными юзернеймами - привет дискорду и некоторым компьютерным играм. Убедитесь, что вы правильно обрабатываете такие символы!

Вот список символов, которые я знаю, они в кавычках, честно-честно:
"⁠" - Word Joiner
"​" - Zero Width Space
"‌" - Zero Width Non-joiner
"᠎" - Mongolian Vowel Separator
"‍" - Zero Width Joiner
"‎" - Left-to-right Mark
"‏" - Right-to-left Mark
"" - Zero Width No-break Space
"‪" - Left-to-Right Embedding
"‫ Right-to-Left Embedding - "
"‬" - Pop Directional Formatting
"‭" - Left-to-Right Override
"‮edirrevO tfeL-ot-thgiR - "
"⁢" - Invisible Times
"⁣" - Invisible Separator

Какие-то символы заставляют текст отображаться справа налево, а некоторые запрещают перенос символов - можно сделать так, что "км/ч" не перенесет "ч" отдельно, или чтобы "100 км/ч" не разбилось бы отдельно на число и единицы измерения.

Раньше ens, доменная система ethereum, разрешал регистрировать домены с невидимыми символами, из-за чего появились клоны известных адресов - vitalik.eth, visa.eth и другие.

А вот атака со сменой отображения расширения файла. Для этого в название testfdp.exe вставляется Right-to-Left Override, что заставляет текст после этого символа отображаться в обратном порядке.

А вот настоящее название файла c RTLO
А вот настоящее название файла c RTLO

Погодите, если можно сделать чтобы символы не разбивались при переносе, тогда почему мы все еще постим отсталый ascii art, у которого постоянно ломаются руки из-за переноса на другую строку?! Представляю вам неломабельный chad-art: ⁠¯⁠\⁠_⁠(⁠ツ⁠)⁠_⁠/⁠¯ ⁠⁠(⁠╯⁠°⁠□⁠°⁠)⁠╯⁠︵⁠ ⁠┻⁠━⁠┻

На страже мемов, мои чюваки  ⁠(⁠☞⁠゚⁠ヮ⁠゚⁠)⁠☞
На страже мемов, мои чюваки ⁠(⁠☞⁠゚⁠ヮ⁠゚⁠)⁠☞

А еще оказалось, что эти символы используются в эмодзи! Если поставить 🫱 и 🫲 подряд, а потом поставить между ними Zero Width Joiner, то вместо них отобразится 🫱‍🫲 ! Так работают многие эмозди: 👩‍🚀 (👩[ZWJ]🚀), 👨‍🍳 (👨 [ZWJ]🍳) и многие другие. Так же работает и смена цвета кожи, волос и остальные параметры.

Вернемся к чуть более скучным вещам. Оказывается, что существуют символы длиной в один символ (простите за тавтологию), которые кодируются LLM как несколько токенов, и они при этом невидимы! Mongolian Vowel Separator кодируется как целых 3 токена! И это происходит не только в tiktoken, но и в токенизаторе от Anthropic.

Из-за этого возможна атака скрытого перерасхода токенов: при размещении невидимых символов расходуется больше токенов, чем кажется. Невидимая строка длиной, казалось бы, в 0 символов (можно написать какое-нибудь слово или фразу для отвлечения внимания) может использовать максимальное количество входных токенов модели.

Но ведь никакого текста в поле для ввода нет!
Но ведь никакого текста в поле для ввода нет!

Всегда считайте токены перед отправкой данных в LLM, не смотрите "на глаз" - не пытайтесь считать их через подсчет символов. Используйте специальные библиотеки, например, tiktoken.

Компании, обучающие нейросети на текстовых данных, должны знать о существовании таких символов юникода и отсеивать poisoned данные и случайно попавшие в текст символы. В открытых датасетах они уже есть.

Я также уверен, что невидимые символы могут скрывать различные команды LLM, но мне пока не удалось надежно воспроизвести эту атаку. Идея состоит в том, чтобы написать запрос к LLM, добавить невидимые символы и заставить LLM сделать что-то совершенно другое. У некоторых моделей также ломается защита - они забывают, что нельзя отвечать на какие-то запрещенные запросы.

Upd: как подсказали в комментариях, невидимую атаку уже нашел инженер из Scale AI, который как раз занимается изучением атак на LLM.

Вот что увидела модель (темно-серые коды - те самые символы)
Вот что увидела модель (темно-серые коды - те самые символы)

Невидимые символы сломали ее защиту
Невидимые символы сломали ее защиту

А вот что должно происходить - в этом запросе невидимых символов нет
А вот что должно происходить - в этом запросе невидимых символов нет

И это нейронка от Mistral
И это нейронка от Mistral

А иногда они почему-то просто вставляют разные символы, которых в ответе быть не должно
А иногда они почему-то просто вставляют разные символы, которых в ответе быть не должно

Больше странного ойти вперемешку с новостями можно найти в моем телеграме. Спасибо за чтение!

17 комментариев 👇

Для кодирования текста в инъекции можно использовать символы из Tags блока юникода, PoC.

Сейчас ChatGPT/апи OpenAI это легко фильтруют, но другие модельки могут быть ещё уязвимы

@ilyaluk, блин, вот я такую уязвимость как раз и искал. Спасибо! А Гугл не показывает в поиске ничего на эту тему, забавно.

Отдельно интересно, что по ссылке на Твиттер rez0__ показываются его старые посты, если ты не залогинен, а если зайти в приложеньку - там совсем другие твиты на этой же странице.

  Развернуть 1 комментарий

@ibaikov, это сейчас на всех профилях в твиттере, если ты не залогинен. Ещё и по ссылкам на твиты реплаи не видны, только основной.

Маск совсем не щадит read-only людей без аккаунта)

  Развернуть 1 комментарий
Evgenii Kochanov Анализирую данные 16 апреля в 19:37

ЕБУЧИЙ ЮНИКОД
дополнительной чтение по теме — https://tonsky.me/blog/unicode/

  Развернуть 1 комментарий

@kochanoff, Вот как раз подумал про Тонского, когда начал читать.

  Развернуть 1 комментарий

А эти ваши невидимые символы они с нами в одной комнате?

  Развернуть 1 комментарий

  Развернуть 1 комментарий

Как-то давно работал над парсером текстов из книг epub и обнаружил там хитрый баг, что в некоторых словах количество символов явно не совпадало с тем, что я сам видел глазами.

Подумал, что кукушечка все и программировать больше не придется — а потом нашел в слове скрытые символы разбивки слов по слогам, которые используются для корректного переноса слов в читалках 🙀

  Развернуть 1 комментарий

Клипбоард винды кстати их распознает

  Развернуть 1 комментарий

@Destert, это полный рандом - половина редакторов распознает, другая половина - нет. И это еще и от шрифта зависит. Например, некоторые из них не показывает cat, vim даже с set list, codemirror и гит.

  Развернуть 1 комментарий

@Destert, стой, а ты копипастнул именно то что было в посте? Просто там по-другому все расставлено как раз)

  Развернуть 1 комментарий

@ibaikov, Действительно)

  Развернуть 1 комментарий

@ibaikov,
А Notepad++ видит это так:

  Развернуть 1 комментарий

Оставлю свою любимую статью на тему юникодовых пробелов

https://jkorpela.fi/chars/spaces.html

  Развернуть 1 комментарий

Это ж можно в качестве вотермарков оставить целую программу на whitespace (с маппингом символов)!

  Развернуть 1 комментарий
Никита Коптелов Senior Engineering Manager / Senior Gopher 23 апреля в 12:19

А если вы наоборот хотите от всех этих символов избавиться - очень хороший и портабельный скрипт можно найти тут https://www.datafix.com.au/BASHing/2021-12-08.html

А вообще есть Data Cleaner's Cookbook, советую его всем, кто часто перегоняет данные/интегрируется с левыми системами (😭😭😭):

https://www.datafix.com.au/cookbook/

  Развернуть 1 комментарий
Сергей Буянтуев golang разработчик, бывший 1Сник 23 апреля в 11:30

Телега кстати распознает текст из топика, показывает пробелы в сообщении.

  Развернуть 1 комментарий
Саша Орлов автоматизирую тесты 23 апреля в 12:49

😱 Комментарий удален его автором...

  Развернуть 1 комментарий

😎

Автор поста открыл его для большого интернета, но комментирование и движухи доступны только участникам Клуба

Что вообще здесь происходит?


Войти  или  Вступить в Клуб