Читать 7 мин

Санитизация ANSI escape-последовательностей для безопасных терминалов

Санитизация ANSI escape-последовательностей убирает управляющие данные терминала, полезные нагрузки OSC и уловки с курсором из контекста AI-агента, сохраняя полезный результат команд.

Санитизация ANSI escape-последовательностей для безопасных терминалов

Вывод терминала - это входные данные. Как только агент получает возможность прочитать результат команды, каждый байт в этом результате может попытаться изменить то, что агент видит, или повлиять на работу расположенного рядом терминала. Нельзя считать stdout надёжным только потому, что его создала ваша команда. Часто команда лишь передаёт данные, которыми управлял кто-то другой.

Санитизация ANSI escape-последовательностей нужна на границе, где вывод инструмента превращается в контекст агента. Её следует выполнять до передачи текста модели, до открытия человеком живой расшифровки и до превращения журнала сеанса в данные, доступные для воспроизведения. Удаление цветовых кодов после того, как модель уже прочитала их, лишь убирает следы.

Это не призыв превращать каждый результат команды в бесполезный стерильный блок. Агентам нужна полезная диагностика. Задача состоит в том, чтобы сохранить смысл вывода, но не переносить через границу доверия инструкции терминала, перемещение курсора, запросы к буферу обмена, гиперссылки и другой управляющий трафик.

Расшифровка терминала - это недоверенные входные данные

Shell-команда не владеет своим выводом. git log печатает сообщения коммитов. Компилятор выводит пути и фрагменты исходного кода. Тестовый раннер может повторить содержимое фикстуры. SSH-клиент показывает баннер сервера ещё до приглашения. Менеджер пакетов получает имена, версии, метаданные и сообщения об ошибках от удалённых реестров. В каждом случае внешний участник может повлиять на текст, который позже попадёт агенту.

Типичная ошибка начинается с удобного решения: перехватить stdout и stderr, объединить их и добавить результат в диалог агента. Тогда у вывода появляются две роли. Он сообщает результат программы и одновременно становится инструкцией в контексте языковой модели. Управляющие последовательности делают первую роль менее надёжной, а текст, похожий на prompt, делает вторую опасной.

Представьте репозиторий, в котором имя файла содержит возврат каретки и escape-последовательность. Команда, перечисляющая файлы, может создать отображение, которое перезапишет собственный префикс. Рецензент увидит безобидный путь, а в исходном потоке байтов будет другое содержимое. Если инструмент превратит этот поток в сообщение агента без отображения границ байтов и политики обработки управляющих символов, агент получит неоднозначный артефакт.

Не ограничивайте модель угроз вредоносным участником репозитория. Через ту же границу проходят артефакты сборки, трассировки зависимостей, сетевые устройства, ошибки базы данных и вывод удалённых команд. Скомпрометированному серверу не нужен shell-доступ к хосту агента: достаточно вернуть баннер, созданный для загрязнения расшифровки.

Есть два разных риска:

  • Эмулятор терминала может выполнить управляющие инструкции, когда человек просматривает необработанный вывод.
  • Агент может воспринять видимый, скрытый или переставленный текст как указания, а не как данные.

Чистая расшифровка агента снижает второй риск. Просмотрщик, который никогда не интерпретирует управляющие последовательности терминала, снижает первый. При проверке перехваченного вывода людьми нужны оба средства.

Управляющие последовательности делают больше, чем добавляют цвет

Управляющие последовательности терминала могут перемещать курсор, стирать предыдущий текст, задавать заголовок окна, создавать кликабельную ссылку, помещать содержимое в буфер обмена, опрашивать терминал или передавать данные функции терминала. SGR, отвечающий за цвет, это лишь знакомая часть. Фильтр, удаляющий ESC[, за которым идут цифры и m, обрабатывает цвета, но оставляет множество более мощных последовательностей.

ECMA-48 определяет управляющие функции и общую форму последовательностей CSI. Обычно CSI начинается с ESC и [, затем идут байты параметров, промежуточные байты и завершающий байт. Стандарт также допускает однобайтовые формы C1 в диапазоне 0x80-0x9f. Поверх стандарта эмуляторы терминала добавляют собственное поведение. В документации xterm по управляющим последовательностям описаны строки OSC, DCS, APC, PM и SOS, включая терминаторы, отличающиеся от последовательностей CSI.

Эта грамматика важна, потому что управляющие данные не всегда приходят аккуратной строкой. Программа может записать ESC одним блоком, а [ - следующим. Псевдотерминал способен разделить вывод на любом байте. Инструмент может отправить строку OSC с BEL в качестве терминатора или двухбайтовую форму ST, ESC и обратный слеш. Компонент на границе должен сохранять состояние между чтениями.

Несколько примеров показывают, почему удаления цветов недостаточно:

  • ESC[2J просит терминал стереть экран.
  • ESC[H перемещает курсор в начало.
  • ESC]8;;URI ESC\\ начинает гиперссылку OSC 8 в поддерживающих её терминалах.
  • ESC]52;... BEL задаёт содержимое буфера обмена, что распознают многие эмуляторы терминала.
  • Возврат каретки возвращает курсор в нулевой столбец и может перезаписать предыдущую строку состояния.

Последовательность не обязана поддерживаться каждым терминалом, чтобы иметь значение. Сборщик вывода не может предугадать, каким терминалом инженер воспользуется через полгода, какой просмотрщик воспроизведёт журнал или какой парсер превратит управляющий байт в видимый токен. Убирайте неоднозначность во время сбора.

Внимания требуют и управляющие символы вне escape-последовательностей. Backspace, возврат каретки, перевод страницы, звонок и многие байты C1 могут менять отображение или сбивать построчный парсинг. Сохраняйте только те управляющие символы, которые нужны вашему контракту вывода, обычно перевод строки и, возможно, табуляцию. Оставляйте возврат каретки только при наличии явного и протестированного смысла в парсере.

Удаляйте управляющие данные до передачи текста модели

Самый безопасный вариант прост: собирайте байты, ограничивайте их размер, разбирайте управляющие последовательности терминала как байты, отбрасывайте управляющие инструкции, декодируйте оставшийся печатный текст по заданной политике обработки ошибок и отправляйте очищенный текст агенту. Не декодируйте данные заранее в надежде, что очистка Unicode найдёт опасные элементы. ESC - это ASCII-байт, управляющие символы C1 могут присутствовать напрямую, а повреждённые байтовые последовательности не должны позволять сборщику пропустить фильтрацию.

Практический путь вывода состоит из четырёх записей, даже если агенту вы показываете только одну. Храните исходный поток байтов в защищённом хранилище для расследований. Формируйте нормализованный обычный текст для контекста модели. Создавайте отчёт об удалениях для операторов и журналов. Сохраняйте метаданные: статус завершения, длительность, факт усечения, число байтов и криптографический дайджест исходного содержимого.

Отчёт об удалениях важен. Тихое удаление может скрыть проблему от человека, которому нужно её расследовать. Полезный отчёт может сообщать, что сборщик удалил две последовательности CSI, одну строку OSC, три возврата каретки и одну некорректную байтовую последовательность. Воспроизводить полезную нагрузку не нужно. Повторение полезной нагрузки OSC в отчёте может вернуть ту же угрозу.

Применяйте границу к stdout и stderr по отдельности до объединения. Программы перемежают потоки, и после объединения оболочкой исходный порядок может потеряться. Если агенту нужен единый рассказ, пометьте два очищенных потока и добавьте порядковый номер, назначенный сборщиком. Это сохраняет больше правды, чем искусственная расшифровка, заявляющая о точном порядке, которого система не наблюдала.

Ограничения размера должны находиться в том же компоненте. Атакующий может использовать незавершаемую строку OSC или бесконечный повторяющийся вывод, чтобы занять память и контекст. Установите жёсткий предел общего числа собранных байтов и меньший предел для управляющей строки, которая разбирается в данный момент. При достижении лимита закройте или дочитайте источник согласно политике процесса, отметьте результат как усечённый и не включайте неполный исходный артефакт в сообщение агента.

Не поручайте модели решать, безопасна ли escape-последовательность. Модели разбирают текст, а не байтовые протоколы, и их решение может зависеть от окружающего контекста. Это решение должен принимать детерминированный парсер до того, как агент увидит вывод.

Изоляция сохраняет доказательства, но не поведение

Удаление и изоляция решают разные задачи. Удаление создаёт полезный текст, убирая инструкции оформления. Изоляция оставляет исходные байты доступными человеку, у которого есть законная причина их проверить. Называть необработанный захват «санитизированным» только потому, что вы закодировали его в Base64, значит путать передачу с авторизацией.

Агенту обычно нужны первые несколько сотен строк неудачной сборки, а не побайтовое воспроизведение сеанса терминала. Передавайте ему нормализованный текст с явными маркерами усечения и удалений. Если требуется больше деталей, пусть он запросит небольшой очищенный фрагмент по диапазону строк или поисковому термину. Не вставляйте вместо этого необработанный захват в тот же контекст.

Когда следователю нужны оригинальные данные, открывайте их в просмотрщике, ориентированном на байты, который отображает управляющие байты явно и никогда не отправляет их в терминал. Хорошо подходят шестнадцатеричные дампы, поскольку они показывают границы байтов. Замена ESC на ^[ может помочь, но просмотрщик также должен корректно обрабатывать символы C1 и полезные нагрузки строк. Просмотрщик, который запускает cat для показа доказательств, не является криминалистическим инструментом.

Эта shell-команда создаёт пример файла, не отправляя управляющие символы в текущий терминал. Файл содержит SGR для красного текста, последовательность CSI для перемещения курсора вверх, гиперссылку OSC 8 и возврат каретки:

printf 'build: \033[31mFAIL\033[0m\nnotice\033[1A\033]8;;https://example.invalid\033\\open\033]8;;\033\\\rPASS\n' > terminal-sample.bin
od -An -tx1c terminal-sample.bin

В выводе od должны присутствовать 1b для ESC и 0d для возврата каретки. Он не должен заставить терминал перейти по ссылке или переместить курсор, потому что od печатает представление байтов, а не воспроизводит их.

Изоляции также нужен контроль доступа. Исходный артефакт может содержать секреты, которые команда по ошибке вывела на экран. Санитизация управляющих последовательностей не скрывает токены, пароли и персональные данные. Обнаружение и удаление секретов выполняйте отдельным этапом с собственной политикой ложных срабатываний. Не объединяйте эти задачи: пропустивший учётные данные редактирующий фильтр не должен одновременно решать, останется ли запрос OSC 52.

Регулярное выражение не заменяет парсер терминала

Оставьте шлюз на своём Mac
Используйте одно подписанное приложение для Mac в строке меню, которое отвечает за авторизацию, хранение учётных данных и записи действий.

Регулярные выражения популярны, потому что позволяют одной строкой убрать цветной вывод сборки. В качестве границы безопасности они ненадёжны: грамматика терминала потоковая и зависит от состояния. Многие шаблоны также плохо работают на длинных повреждённых входных данных, которые злоумышленник как раз и может отправить.

Используйте автомат состояний на уровне байтов с явным поведением для ESC, CSI и строковых управляющих последовательностей. Следующая функция Python намеренно ограничена. Она сохраняет табуляцию и перевод строки, превращает возврат каретки в видимый перевод строки согласно выбранной политике, удаляет остальные управляющие символы C0 и C1, а также ESC-последовательности, включая строки OSC, DCS, APC, PM и SOS. Она принимает блоки только после их объединения вызывающей стороной, поэтому рабочая версия должна сохранять поля состояния между чтениями.

def clean_terminal_bytes(data: bytes) -> tuple[str, dict[str, int]]:
    out = bytearray()
    counts = {"esc": 0, "csi": 0, "string": 0, "control": 0}
    i = 0

    while i < len(data):
        b = data[i]

        if b == 0x1b:  # ESC
            counts["esc"] += 1
            i += 1
            if i >= len(data):
                break
            nxt = data[i]

            if nxt == ord('['):  # CSI
                counts["csi"] += 1
                i += 1
                while i < len(data):
                    c = data[i]
                    i += 1
                    if 0x40 <= c <= 0x7e:
                        break
                continue

            if nxt in b']P_^X':  # OSC, DCS, APC, PM, SOS
                counts["string"] += 1
                i += 1
                while i < len(data):
                    c = data[i]
                    if c == 0x07:  # BEL
                        i += 1
                        break
                    if c == 0x1b and i + 1 < len(data) and data[i + 1] == ord('\\'):
                        i += 2
                        break
                    i += 1
                continue

            i += 1  # Two-byte ESC function or unknown ESC form
            continue

        if b == 0x9b:  # Single-byte C1 CSI
            counts["csi"] += 1
            i += 1
            while i < len(data):
                c = data[i]
                i += 1
                if 0x40 <= c <= 0x7e:
                    break
            continue

        if 0x80 <= b <= 0x9f or b < 0x20 and b not in (0x09, 0x0a):
            counts["control"] += 1
            i += 1
            continue

        out.append(b)
        i += 1

    return out.decode("utf-8", errors="replace"), counts

У этого примера есть ограничения. Он не моделирует каждую управляющую функцию ECMA-48 и считает неизвестные формы ESC удаляемыми. Для вывода, попадающего в контекст агента, такая осторожность уместна. Эмулятору терминала нужна широкая совместимость, а границе агента - небольшая разрешённая поверхность.

Не копируйте эту функцию и не объявляйте задачу выполненной. Добавьте максимальную длину параметров CSI и строковых управляющих последовательностей. Сохраняйте состояние парсера между границами чтения. Считайте повреждённые и незавершённые последовательности. Главное, пишите тесты, подтверждающие, что исходная полезная нагрузка никогда не появляется в очищенном результате. Для фильтра безопасности нужны отрицательные тесты, а не только красивые снимки «до и после».

Последовательности OSC требуют особого внимания

Строки OSC показывают, что вывод терминала может содержать нечто большее, чем оформление. В документации Xterm описаны команды OSC для заголовков окон, гиперссылок и других функций. Современные эмуляторы поддерживают разные подмножества, поэтому списки разрешений, основанные на сегодняшнем локальном терминале, быстро становятся плохим выбором.

Ссылки OSC 8 могут превратить безобидный на вид текст в кликабельный адрес. Видимая подпись может говорить build report, а цель вести в другое место. Человеку, читающему очищенную расшифровку агента, не нужна активная ссылка. Если вы можете безопасно разобрать её, сохраните подпись как обычный текст, либо удалите всю оболочку OSC и оставьте только следующие печатные байты. Не сохраняйте URI, если в продукте нет отдельной политики проверки и отображения URL.

OSC 52 может попросить терминал установить содержимое буфера обмена. Некоторые терминалы отключают эту возможность или требуют специальной настройки, но сборщик не должен на это рассчитывать. Если необработанный журнал воспроизвести в разрешающем терминале, команда сможет поместить выбранный атакующим текст в буфер оператора. Следующая вставка может попасть в shell, задачу, чат или поле для учётных данных.

Последовательности, задающие заголовок окна, создают менее заметную проблему. Они могут изменить заголовок, отображаемый в терминальном мультиплексоре, переключателе задач операционной системы или записи сеанса. Заголовок, похожий на запрос подтверждения или сообщение об успешном развёртывании, способен ввести в заблуждение оператора, который просматривает много окон. Удаление всего трафика OSC устраняет этот класс угроз без списка, который быстро устареет.

Не пытайтесь сохранять строки OSC ради понимания моделью. Агенту не нужно выполнять обновление заголовка терминала, нажимать ссылку или получать операцию с буфером обмена. Если результат команды содержит полезный URL, пусть команда напечатает его обычным текстом или извлеките его из структурированного ответа до попадания в терминальный поток.

То же правило относится к строкам управления устройствами и командам прикладных программ. Одни эмуляторы их игнорируют, другие со временем добавляют поддержку. Граница вывода должна работать по принципу безопасного отказа: распознав начало управляющей строки, потребите её до корректного терминатора или до заданного максимального размера, запишите аномалию и не помещайте полезную нагрузку в обычный контекст.

Определите контракт вывода для каждого инструмента

Отделите API-ключи от агентов
Пропускайте HTTP-запросы через хранилище, не помещая API-учётные данные в контекст агента.

Санитизатор не исправит интерфейс вывода, который пытается одновременно использовать расшифровку терминала как базу данных, отчёт и пользовательский интерфейс. Инструменты должны явно указывать, что они возвращают агенту: обычный текст UTF-8, структурированный JSON, созданный по нетерминальному каналу, или ссылку на изолированный артефакт. Пусть вывод, похожий на терминальный, будет исключением, а не форматом обмена по умолчанию.

Для собственных команд отключайте оформление, когда их вызывает агент. Многие программы предлагают флаг без цветов, машиночитаемый режим или настройку окружения. Структурированный вывод полезен, только если вы контролируете его схему и ограничиваете размер. В JSON тоже может находиться prompt injection в строковых полях, поэтому помечайте каждое поле как данные и отделяйте недоверенные описания от инструкций.

Для чужих команд используйте каналы, а не псевдотерминал, если только команде не требуется терминальное поведение. Псевдотерминал провоцирует индикаторы выполнения, перезапись курсора, управляющие последовательности заголовка и другие ветки кода. Каналы не делают вывод безопасным, но уменьшают объём терминального протокола, который нужно обрабатывать.

Записывайте происхождение результата. Агент и рецензент должны видеть запущенный исполняемый файл, рабочий каталог, код завершения, исходный поток, лимит захвата и информацию о том, удалил ли санитизатор содержимое. Не позволяйте выводу инструмента выдавать себя за эти поля. Помещайте созданные сборщиком метаданные в отдельную оболочку за пределами недоверенного текста.

Такая оболочка может выглядеть следующим образом:

{
  "command": "test-runner --report plain",
  "exit_code": 1,
  "stdout": "142 tests passed\n",
  "stderr": "fixture failed at tests/login.txt:18\n",
  "sanitizer": {"removed_controls": 4, "truncated": false},
  "raw_artifact": "restricted:sha256:..."
}

Поле raw_artifact должно содержать ссылку, которую обычный агент не может разыменовать. Если вы возвращаете содержимое по запросу без нового решения об авторизации, ссылка была лишь видимостью защиты.

Проверяйте вредоносный вывод за пределами повседневного shell

Санитизатор, прошедший тест с зелёным и красным цветом, только начал работу. Проверяйте байты, которые пересекают границы состояний парсера, неожиданно завершаются и взаимодействуют с управляющими элементами отображения. Прогоняйте набор через тот же путь захвата, которым пользуются агенты, включая запуск процессов, буферизацию, хранение журналов и отображение расшифровки.

Начните с небольшого набора, где байт ESC находится в конце одного блока, а [ - в начале следующего. Добавьте CSI с необычно длинными параметрами, строки OSC, завершённые BEL и ST, строку OSC без терминатора, однобайтовые C1 CSI, backspace, повторяющиеся возвраты каретки и некорректный UTF-8 рядом с escape-последовательностью. Проверьте, что текст для агента не содержит ESC, байтов диапазона C1 и полезной нагрузки удалённых строк.

Затем проверяйте смысл отображения. Передайте строку состояния working 10%\rworking 20%\rfailure через выбранную политику возврата каретки. Если сохранять её как перевод строки, агент увидит историю. Если имитировать перезапись, он увидит только failure. Подойдут оба варианта, но задокументируйте и протестируйте выбранный. Тихие изменения поведения при обновлении парсера затрудняют разбор инцидентов.

Здесь полезно фаззинг-тестирование: у грамматики escape-последовательностей мало состояний, но огромное пространство повреждённых входных данных. Генерируйте случайные потоки байтов, уделяя особое внимание ESC, BEL, обратному слешу, байтам C1 и длинным незавершённым строкам. Требования просты: фильтр завершается в пределах бюджета времени и памяти, не выдаёт исключений, а его результат не содержит запрещённых управляющих байтов.

Проверяйте и путь для человека. Страница журнала, уведомление рабочего стола, панель терминала и скопированная расшифровка могут интерпретировать содержимое по-разному. Показывайте исходный набор только в безопасном просмотрщике байтов. Очищенный текст отображайте во всех обычных интерфейсах. Если инженер во время обычного расследования может скопировать необработанную запись журнала в интерактивный терминал, в границе изоляции есть брешь.

Подтверждение человека не санитизирует расшифровку

Защитите действия хранилищем
Заблокированное хранилище отклоняет каждое действие, пока вы не откроете его с помощью Touch ID.

Запрос на подтверждение решает, может ли агент выполнить действие. Он не решает, безопасно ли отображать возвращённые байты или включать их в prompt модели. Разделяйте эти механизмы, иначе человек решит, что, подтвердив ssh host command, он также одобрил каждый баннер, имя файла и удалённую ошибку, которую вернёт хост.

Это особенно важно для шлюзов действий. Sallyport может не допустить передачу учётных данных агенту и потребовать подтверждения человека, но любой интеграции, отправляющей результаты действий агенту, всё равно нужна граница нормализации вывода. Хранение учётных данных и безопасность расшифровки отвечают на разные вопросы.

Не пытайтесь компенсировать слабую обработку вывода повторными подтверждениями. Человек, которого просят подтвердить каждое чтение, не станет проверять каждый символ длинного ответа, а ответ может прийти уже после подтверждения. Проверка каждого вызова полезна для чувствительных действий, но не превращает недоверенный вывод в надёжный контекст.

Храните запись решения рядом с очищенным результатом. Зафиксируйте, что оператор одобрил процесс или вызов, а затем запишите фактический результат команды как недоверенные данные инструмента вместе с отчётом санитизатора. Такое разделение помогает при расследовании отдельно ответить на два вопроса: кто разрешил операцию и какие данные она вернула?

Исходный захват должен оставаться вне обычного доступа агента

Распространённый обходной путь разрушает даже хорошую архитектуру: если очищенный результат кажется неполным, агент получает инструмент read_raw_output. Такой инструмент превращает границу безопасности в небольшое препятствие. Атакующему достаточно сделать очищенное резюме достаточно запутанным, чтобы агент запросил оригинал.

Используйте ограниченное извлечение. Пусть человек откроет артефакт в безопасном просмотрщике. Пусть отдельный экстрактор вернёт ограниченный диапазон в hex, сравнение дайджестов или печатный текст после применения того же парсера. Если рабочему процессу действительно нужен анализ исходного протокола, требуйте явного решения человека и используйте просмотрщик, который не выполняет управляющие последовательности терминала.

Храните исходные и очищенные данные по разным политикам. Исходному выводу может понадобиться более короткий срок хранения, поскольку он способен содержать секреты и вредоносную полезную нагрузку. Очищенные расшифровки могут оставаться полезными для анализа сеансов агента, но тоже содержат деловые данные. Хеши связывают две записи, не заставляя обычных пользователей получать исходные байты.

Первая задача внедрения - не правило prompt, которое велит агентам игнорировать инструкции терминала. Поставьте байтовый парсер между выводом процесса и каждой расшифровкой, доступной агенту, удаляйте неизвестный управляющий синтаксис и сохраняйте оригинал только там, откуда обычные агенты не могут его получить. Это устраняет целый класс неоднозначностей ещё до того, как модели, терминалу или уставшему оператору придётся с ним разбираться.

Вопросы и ответы

Достаточно ли удалить ANSI escape-последовательности, чтобы убрать все управляющие последовательности терминала?

Нет. ANSI обычно используют как общее обозначение управляющих последовательностей ECMA-48, но терминальные эмуляторы также поддерживают частные расширения. В список для проверки входят команды OSC, строки управления устройствами, управляющие символы C1 и специфичные для эмуляторов последовательности.

Можно ли сохранить цвета терминала и при этом защитить AI-агента?

Цвет можно оставить, если доверенный визуализатор применяет его после обработки обычного текста агентом. Не передавайте исходные последовательности SGR только ради сохранения оформления. Безопасный порядок такой: разобрать данные, удалить управляющие последовательности, затем при необходимости добавить ограниченный слой отображения для человека.

Безопасно ли давать агенту на проверку вывод команд в формате Base64?

Считайте такие данные небезопасными, пока парсер не нормализует их. Base64 не даёт терминалу интерпретировать байты во время передачи, но агент может декодировать их и воспроизвести исходный поток управления. Храните необработанные данные вне контекста агента, если только конкретное расследование не требует обратного.

Почему escape-последовательность важна, если у модели нет терминального эмулятора?

Терминальный эмулятор применяет управляющие последовательности, а агент может прочитать их как обычный текст, декодированные токены или очищенную расшифровку. Это разные потребители с разными сценариями отказа. Санитизация защищает контекст агента, а безопасный просмотрщик защищает терминал человека.

Когда вывод нужно удалять, а когда помещать в карантин?

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

Почему регулярного выражения недостаточно для удаления управляющих последовательностей терминала?

Большинство регулярных выражений не справляется с последовательностями, которые разделены между блоками, используют формы C1, содержат полезную нагрузку OSC или завершаются ST вместо BEL. Небольшой автомат состояний проще проверять: в нём явно указаны состояния и правила завершения. Подавайте ему байты, а не предварительно декодированный текст.

Может ли инъекция через терминал сохраниться в расшифровках сеансов или журналах?

Да. В общем контексте такая инъекция может ввести в заблуждение следующий процесс агента так же легко, как текущий. К журналам сеансов нужно применять те же правила нормализации, что и к активному выводу инструментов. Если следователям нужна точность до байта, храните отдельную защищённую исходную запись.

Защищают ли запросы на подтверждение человека от prompt injection через вывод терминала?

Подтверждение показывает, что человек разрешил действие, но не делает возвращённые байты достоверными. Одобренная команда всё ещё может прочитать вредоносное содержимое репозитория, баннер удалённого сервера, метаданные пакета или строки журнала. Обрабатывайте вывод после каждого одобренного действия.

Как хранить исходный вывод команд для криминалистического анализа?

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

Какие тесты должен включать санитизатор вывода терминала агента?

Проверяйте фрагментированные последовательности, ссылки OSC 8, запросы OSC 52 к буферу обмена, перезапись строк через возврат каретки, backspace, управляющие байты C1, некорректный UTF-8 и незавершённые строки. Прогоняйте один и тот же набор через каналы и псевдотерминалы, потому что инструменты часто меняют поведение при обнаружении TTY. Санитизатор, который умеет обрабатывать только цветной вывод компилятора, ещё не заслужил доверия.

Sallyport

Sallyport выполняет API-вызовы и SSH-команды за вашего ИИ-агента. Ключи остаются в локальном хранилище на вашем Mac; вы подтверждаете каждый запуск, и каждое действие попадает в запечатанный журнал.

© 2026 Sallyport · Открытый код по лицензии Apache-2.0 · Oleg Sotnikov