Временные файлы инструментов агента: как найти и удалить следы секретов
Временные файлы инструментов агента могут хранить API-запросы, вывод и журналы отладки. Узнайте, как находить, локализовать, проверять и удалять чувствительные остатки в macOS.

Временные файлы инструментов агента заслуживают такого же внимания, как репозиторий с исходным кодом. Агент для программирования может создать тело запроса, выполнить команду, повторить ее с подробным журналированием, скопировать вывод в кэш и оставить исходный рабочий каталог чистым на вид. Чувствительные данные все равно останутся на компьютере, часто в местах, которые никто не включил в проверку.
Ошибочно считать, что секрет утекает только тогда, когда агент показывает его в переписке. На практике гораздо чаще учетные данные оказываются в временном файле запроса, чтобы вспомогательный процесс мог его отправить, или в журнале неудачной команды, потому что кто-то включил режим отладки еще на прошлой неделе. Очистка важна, но еще важнее профилактика: не передавайте агенту исходные учетные данные, если действие может выполнить другой процесс.
Инструменты агента создают копии за пределами рабочего дерева
Даже если в каталоге проекта нет очевидных следов, запуск агента может оставить данные на нескольких уровнях. Рабочее дерево лишь одно из мест записи, а разработчики часто проверяют именно его, потому что оно знакомо. У агента, его среды выполнения, shell, менеджера пакетов, редактора, терминала и операционной системы есть собственные места для записи.
Сначала разделите данные на три категории. Файлы полезной нагрузки содержат то, что агент собирался отправить: тела JSON-запросов, пакеты SQL, экспортированные запросы к модели, файлы патчей или конфигурацию SSH. Файлы вывода содержат ответы удаленной системы: ответы API, вывод команд, выгрузки баз данных и страницы с ошибками. Диагностические материалы содержат сопутствующие сведения: аргументы команд, данные об окружении, трассировки стека, повторные попытки и трассировки.
Все три категории могут содержать чувствительные данные. В полезную нагрузку токен может попасть, если скрипт добавил его перед отправкой. В выводе может оказаться запись клиента или секрет развертывания. Диагностика может записать оба вида данных в одной строке, поэтому журнал отладки часто наносит больший ущерб, чем сама неудачная команда.
Полезный перечень мест включает:
- Временный каталог процесса и
/private/tmpв macOS. - Каталоги поддержки приложений, кэша и журналов в
~/Library. - Историю shell, экспорт прокрутки терминала и оболочки-обертки команд.
- Локальные папки проекта, например
.cache,tmp,logs,.agentи каталоги тестовых данных. - Доступные для записи слои контейнеров, подключенные тома, рабочие пространства CI и загруженные артефакты сборки.
Не думайте, что агент всегда использует один предсказуемый каталог. Разные версии, плагины, языковые среды выполнения и ветки обработки ошибок выбирают разные места. Инструмент может использовать каталог из TMPDIR, вызванный им помощник может использовать /tmp, а библиотека может разместить кэш в текущем проекте. Надежный ответ дает только наблюдение за собственным запуском.
То же относится к выводу команд. Перенаправление shell вроде command > result.txt заметно сразу. Менее очевидны журналы мультиплексора терминала, отладочные архивы менеджера пакетов, файлы трассировки HTTP-клиента и файлы восстановления редактора, созданные после изменения документа агентом. Если агент может вызывать несколько инструментов, считайте, что у каждого есть собственная привычка хранить данные, пока не проверите это.
Сначала определите реальные места записи
Нельзя очистить путь, который вы угадали неправильно. Запустите агента с безвредным уникальным маркером, а затем найдите этот маркер во всех местах, куда мог записать запуск. Используйте фиктивные данные, похожие на настоящие настолько, чтобы пройти через те же участки кода, но никогда не берите для такого теста рабочий токен.
В macOS сначала запишите временный каталог, который shell получает при запуске агента:
echo "TMPDIR=$TMPDIR"
ls -ld "$TMPDIR" /private/tmp /tmp
Обычно macOS выделяет каждому пользователю каталог внутри /var/folders, а /tmp указывает на /private/tmp. Точный сгенерированный путь не является границей безопасности и может измениться. Запишите его значение, а не зашивайте путь в скрипт очистки.
Создайте легко обнаружимый маркер, а затем попросите агента выполнить типичное действие, которое передаст его в тело запроса, аргумент команды и вывод команды. В этом примере намеренно используется не секретная строка:
export AGENT_TRACE_MARKER='TEMP-PAYLOAD-CANARY-9f2a7c'
printf '%s\n' "$AGENT_TRACE_MARKER" > /tmp/agent-canary.txt
После запуска проверьте вероятные пользовательские каталоги. grep может столкнуться с двоичными файлами и ошибками доступа, поэтому используйте его для поиска, а не как доказательство отсутствия данных.
grep -RIl --exclude='*.sqlite*' \
'TEMP-PAYLOAD-CANARY-9f2a7c' \
"$TMPDIR" /private/tmp \
"$HOME/Library/Caches" \
"$HOME/Library/Logs" \
"$HOME/Library/Application Support" 2>/dev/null
Результатом должен быть список путей к файлам. Для каждого пути ответьте на четыре вопроса: какой процесс его создал, какую категорию данных он содержит, кто может его читать и когда он исчезает. Если вы не можете связать файл с процессом, проверьте время изменения и повторите тест с новым маркером. Не удаляйте сначала необъяснимые файлы. Вместе с ними можно стереть подсказку о том, какой компонент нужно перенастроить.
Используйте fs_usage, если файл появляется лишь на короткое время. Утилита может показать активность файловой системы процесса во время работы агента:
sudo fs_usage -w -f filesystem | grep -iE 'agent|tmp|cache|log'
Команда выводит много лишнего. Запустите ее на коротком тесте, сохраните найденные пути за пределами общего каталога проекта и остановите после этого. Процесс может создать и удалить файл за секунду. Позднее его уже не будет в списке каталогов, но содержимое могло попасть в резервную копию, к наблюдателю файловой системы или в другой сборщик журналов.
Утечки учетных данных обычно происходят при создании запроса
Самый опасный временный файл часто создается еще до сетевого вызова. Многие скрипты собирают запрос в файле, потому что экранировать JSON в shell неудобно. Сначала файл безвреден, но затем кто-то добавляет поле Authorization, cookie или полную строку подключения, чтобы запрос заработал. Так файл случайно превращается в постоянное хранилище секрета.
Избегайте такого шаблона:
cat > /tmp/request.json <<'EOF'
{"endpoint":"https://api.example.invalid/export","token":"$PRODUCTION_TOKEN"}
EOF
В приведенном примере heredoc с одинарными кавычками не раскрывает переменную, что может показаться безопасным. Позже кто-то часто меняет разделитель или использует другой способ создания файла. Важнее другое: сама схема приучает помещать учетные данные в артефакт запроса. Отладочная запись готового запроса их раскроет.
Если протокол позволяет, передавайте учетные данные на уровне транспорта и убедитесь, что транспорт не записывает заголовки. Заголовки авторизации HTTP предпочтительнее токена в строке запроса, но сами по себе безопасными не становятся. Подробное журналирование клиента, настройки прокси, обработчики исключений и собственный код повторных попыток все равно могут их сохранить.
Спецификация HTTP Semantics, RFC 9110, рекомендует пользовательским агентам не отправлять URI с чувствительной информацией в заголовке Referer. Это предупреждение отражает более общий факт: URL распространяются дальше, чем ожидают люди. Они попадают в журналы доступа, историю браузера, скопированные команды терминала, обращения в поддержку и аналитические системы. Не помещайте в URL токены доступа, подписанные URL с широкими полномочиями, пароли или строки подключения к базам данных, если протокол не оставляет другого варианта, а срок действия учетных данных не очень короткий.
С аргументами shell нужно обращаться так же осторожно. В Unix-подобных системах другой локальный процесс при определенных правах и настройках платформы может видеть аргументы. Они также попадают в историю shell, если человек копирует команду, в журнал средства запуска задач и в расшифровку инструментов агента. Переменные окружения сокращают одни пути утечки, но создают другие, включая дочерние процессы и диагностические отчеты. Ни один из этих вариантов не является надежным сейфом.
Граница должна быть простой: агент запрашивает операцию, называя место назначения и несекретные входные данные. Отдельный держатель учетных данных добавляет аутентификацию непосредственно перед вызовом. Агент получает ответ или очищенную от секретов ошибку, но не учетные данные, с помощью которых был выполнен вызов.
Sallyport придерживается этой границы для HTTP- и SSH-действий: учетные данные остаются в зашифрованном хранилище, а агент просит локальное приложение выполнить операцию. Это убирает исходный секрет из контекста агента, но не делает безвредными тела ответов или созданные агентом отладочные файлы. Нужно по-прежнему контролировать, что возвращает действие и куда агент это записывает.
Режим отладки превращает обычные сбои в записи секретов
Подробное журналирование помогает найти причину неисправной интеграции. Одновременно оно специально сохраняет свидетельства, которые обычный журнал не записывает. Обычно это заголовки, полные тела запросов и ответов, командные строки, настройки из окружения, состояние повторных попыток и трассировки стека.
Ошибка состоит в том, что широкий флаг отладки остается включенным после разовой проблемы. Через несколько недель этот флаг применяется к другой задаче, когда кто-то выполняет экспорт или развертывание с реальными полномочиями. Получившийся файл может лежать в каталоге кэша, о принадлежности которого инструменту никто не знает.
Считайте диагностику отдельным классом данных с коротким, явно заданным сроком жизни. Перед включением трассировки решите, на какой вопрос она должна ответить. Если нужно проверить DNS, сохраните вывод резолвера. Если сервер отклоняет поле JSON, запишите код состояния и очищенный от секретов фрагмент ответа. Полное журналирование сетевого обмена должно быть исключением, потому что оно сохраняет данные, которые не требовались для решения проблемы.
Встраивайте очистку в компонент, который пишет данные, а не пытайтесь исправить все потом. Задание очистки, ищущее в журналах Authorization:, пропустит собственные заголовки, поля JSON, параметры URL, многострочные значения, блоки base64 и секреты в содержимом ответа. После того как сборщик журналов или резервная служба скопирует неочищенный файл, последующая обработка оригинала мало что меняет.
Безопасная диагностическая оболочка использует список разрешенных полей. Например, можно записывать HTTP-метод, хост, путь без параметров запроса, код состояния, длительность, размер ответа в байтах и идентификатор запроса. Не записывайте каждый заголовок в надежде замаскировать опасные. Форматы учетных данных меняются быстрее, чем скрипты очистки.
Это различие важно для инструментов, которые показывают команду перед запуском. Отображение команды не равно журналированию фактического окружения команды, а оба варианта отличаются от трассировки пакетов. Проверьте, какое представление сохраняет инструмент. Он может скрывать секреты на экране, но оставлять подробный журнал нетронутым.
Намеренно проверяйте ветки ошибок. Отмените запрос на полпути. Отправьте некорректный JSON. Вызовите ошибку аутентификации с синтетическими учетными данными. Создайте тайм-аут, чтобы проверить повторные попытки. Такие сценарии создают временные файлы запросов и исключения, которых может не быть при успешных вызовах. Именно их злоумышленник может спровоцировать, чтобы система раскрыла больше обычного.
В macOS удаление требует локализации, а не магического уничтожения
В современных системах хранения macOS безопасное удаление не означает многократную перезапись имени файла. Выравнивание износа SSD, копирование при записи, снимки, синхронизация с облаком и резервные копии не позволяют программам надежно обещать, что перезапись затронула каждый физический остаток. Старая привычка запускать утилиту shred создает ощущение завершенной работы, но не решает проблему важных копий.
Удаляйте доступные рабочие файлы. Ограничивайте места появления чувствительных данных заранее. Если есть подозрение на раскрытие, шифруйте данные и меняйте учетные данные.
Для отдельного временного каталога агента задайте ограниченные права до запуска и удалите его после завершения:
run_dir="$(mktemp -d "${TMPDIR%/}/agent-run.XXXXXX")" || exit 1
chmod 700 "$run_dir"
trap 'rm -rf "$run_dir"' EXIT HUP INT TERM
export TMPDIR="$run_dir"
# launch the agent from this same shell
# agent-command
Так запуск получает известную рабочую область, а обычные пути завершения удаляют ее. Это не заставляет каждую зависимость подчиняться TMPDIR и не удаляет данные, скопированные в другой каталог. Поэтому сначала нужно провести поиск.
Не используйте rm -rf /tmp/* и похожие широкие команды очистки. Они могут остановить другие процессы, удалить материалы, необходимые для расследования, и создать ложное ощущение, что проверять нужно было только /tmp. Удаляйте каталоги, созданные вашим средством запуска, и имена, которыми код очистки действительно владеет.
Если секрет мог утечь, отзовите или замените его до начала долгой очистки. Скопированный в неизвестный журнал действующий API-токен остается путем доступа. Имя файла менее важно, чем полномочия, которые он дает. Затем найдите копии в резервных системах, общих дисках, артефактах CI, агрегаторах журналов и системах поиска на конечных устройствах. Удаление оригинала без работы с копиями не устраняет утечку.
Зашифрованное локальное хранилище снижает риск при потере устройства, но не защищает от другого процесса, работающего под той же разблокированной учетной записью. Права на файлы по-прежнему важны. Режим каталога 700 говорит, что другие локальные учетные записи не должны просматривать его. Он не останавливает процесс агента, который уже работает от вашего имени, и не мешает разрешенному вами клиенту синхронизации читать ваш домашний каталог.
Граница учетных данных убирает самые опасные полезные нагрузки
У очистки есть предел. Если агент получает рабочий токен в запросе к модели, переменной окружения, конфигурационном файле или выводе команды, он может поместить этот токен в любой доступный для записи файл. Последствия можно уменьшить, но такую архитектуру нельзя сделать безопасной одной аккуратной уборкой.
Владелец секретов должен находиться за пределами процесса агента. Агент должен выражать намерение, например «отправить этот запрос развертывания на этот разрешенный адрес» или «выполнить эту SSH-команду с этим именованным соединением». Локальный держатель учетных данных должен решить, разрешена ли операция, добавить учетные данные, выполнить ее и записать результат. Если агенту не нужен сам токен, ему не нужен даже токен-заглушка.
Это также делает проверку временных файлов конкретной. Можно искать в рабочих каталогах агента пользовательские данные, созданный код и возвращенные сведения. Не придется считать, что каждый файл может содержать любой рабочий секрет, доступный агенту.
Фиксированная модель подтверждений удобнее набора специальных правил. Ее можно объяснить во время инцидента. Sallyport держит хранилище заблокированным до локальной аутентификации, запрашивает разрешение, когда новый процесс агента впервые выполняет действие, и может требовать подтверждение каждого использования выбранных учетных данных. Это понятный контроль полномочий, а не попытка угадать, выглядит ли сгенерированная команда подозрительно.
Не путайте разрешение действия с минимизацией данных. Одобренный вызов может вернуть чувствительное тело ответа, а агент способен записать его в файл проекта, кэш или расшифровку. Проектируйте ответы так, чтобы они содержали минимально полезный объем данных. Если задаче нужны только идентификатор развертывания и статус, не возвращайте весь документ конфигурации. При наличии серверной фильтрации используйте ее.
SSH требует особого внимания, потому что вывод удаленной команды ничем не ограничен. Команда может прочитать файл конфигурации, вывести переменные окружения после ошибки или запустить подробную утилиту развертывания, отправив секреты обратно агенту. Считайте вывод SSH данными, для которых нужны место назначения, срок хранения и правило проверки. Учетные данные могут быть защищены, пока возвращенный вывод остается опасным.
Для каждого запуска нужны владелец, каталог и срок действия
Политика очистки работает, когда связывает файлы с конкретным запуском. Универсальный ночной скрипт не знает, принадлежит ли временный каталог активному процессу, неудачной задаче, которую нужно изучить, или постороннему приложению. Средство запуска агента это знает.
Используйте идентификатор запуска в имени рабочей папки, записывайте время начала и храните за ее пределами небольшой манифест только с несекретными метаданными. В манифесте должны быть указаны созданный средством запуска каталог, владеющий им процесс, срок удаления и признак завершения запуска. Не помещайте туда аргументы команд, тела запросов или значения окружения.
Практический жизненный цикл состоит из четырех действий:
- Создайте закрытый рабочий каталог до запуска агента.
- Задайте переменные временных путей для агента и контролируемых вами помощников.
- Удалите каталог при обычном завершении и отметьте манифест как завершенный.
- Пусть планировщик помечает заброшенные каталоги, которые существуют дольше заданного порога, для проверки человеком.
Планировщик должен помечать, а не автоматически удалять каталоги незавершенных запусков. Процесс еще может записывать данные. Неудачному развертыванию могут требоваться свидетельства. После того как человек подтвердит, что каталог заброшен и не нужен для инцидента, удалите его по тому же правилу владения.
Не помещайте рабочий каталог в репозиторий. Поиск по проекту, команды контроля версий, индексация IDE, наблюдатели файлов и клиенты резервного копирования обращают внимание на репозитории. Соседний каталог в управляемом пользователем временном месте обычно проще исключить из инструментов разработки и удалить целиком.
Осторожно относитесь к автоматической очистке, которую запускает сам агент. Агент, способный выбирать произвольные пути очистки, может удалить исходные файлы или свидетельства. Средство запуска должно само строить путь, хранить его в своем состоянии и удалять только пути, совпадающие с созданным им шаблоном имен после канонизации. Ошибок из-за интерполяции shell в коде очистки и без того достаточно, не стоит добавлять к ним самостоятельную генерацию текста.
Цель не в том, чтобы ничего не хранить. Должно оставаться достаточно операционных сведений, чтобы понять, какой запуск создал запрос и был ли он успешным. Храните эту запись отдельно от исходных данных и полного вывода, а ее поля делайте намеренно скучными.
Для журналов и резервных копий нужен срок хранения
Временный файл превращается в сохраненную запись в тот момент, когда другая система копирует его. Резервное ПО, облачные папки синхронизации, средства защиты конечных устройств, сборщики отчетов о сбоях, загрузка артефактов CI и централизованное журналирование могут продлить его жизнь. Исходный путь исчезнет, а полезная копия останется где-то еще.
Составьте список всех процессов, которые могут читать каталоги запусков агента. На компьютере разработчика это часто клиент резервного копирования, индексатор редактора, интерфейс системы контроля версий, средство записи терминала и сканер вредоносных программ. Некоторые копии нужны. Важно выбрать их и задать срок хранения, а не обнаружить их после появления токена в архиве восстановления.
Храните необработанный отладочный вывод вне каталогов, которые синхронизируются автоматически. Это касается папок рабочего стола, общих каталогов проектов и любых рабочих пространств, которые клиент CI упаковывает в артефакт. Если инструменту нужно создать большой ответ для проверки, сохраните его в закрытом каталоге с ограниченными правами, задайте срок удаления и исключите его из обычной синхронизации, если инструменты поддерживают такие исключения.
Аудит с цепочкой хешей отличается от отладочной выгрузки. Аудит должен отвечать, кто запросил действие, когда оно выполнялось и к какой категории относится результат, не дублируя секреты. Sallyport формирует журналы Sessions и Activity из зашифрованного аудита, а sp audit verify может автономно проверить цепочку хешей без ключа хранилища. Так можно сохранять свидетельства активности агента, не превращая каждую необработанную полезную нагрузку в обязательную часть аудита.
Срок хранения должен учитывать исключения. Во время инцидента не позволяйте обычному таймеру очистки уничтожить данные, необходимые для понимания произошедшего. Ограничьте доступ, намеренно сохраните нужные файлы и запишите их местонахождение. Затем замените затронутые учетные данные и удалите сохраненные материалы, когда процесс расследования больше не будет в них нуждаться. Хранение данных для инцидента не оправдывает отправку всего обычного вывода агента в постоянное хранилище.
После изменения политики проверьте и резервные копии. Новое исключение для рабочего каталога влияет только на будущие запуски резервного копирования. Старые снимки могут содержать прежние данные, пока не истечет срок хранения у провайдера. Зафиксируйте это в ответе на утечку, не делая вид, что команда rm переписала историю.
Проверяйте очистку глазами любопытного локального злоумышленника
Политика очистки, которая ни разу не проходила поисковую проверку, остается обещанием, а не средством контроля. Тестируйте ее с помощью фиктивного маркера, похожего на строки, которые вы боитесь потерять, а затем осматривайте компьютер так, будто другой локальный процесс хочет его найти.
Сначала проведите тест в обычных условиях. Поместите маркер во входной файл, поле запроса и имитированный вывод команды. Дождитесь завершения агента и срабатывания очистки, затем проверьте рабочий каталог, кэши, журналы, каталог проекта, историю shell и вероятные каталоги поддержки. Запишите каждое совпадение и объясните его.
Затем проверьте неудобные сценарии. Принудительно завершите процесс. Отмените его во время сетевого запроса. Включите самый подробный поддерживаемый режим журналирования. Запустите агент из IDE, а не из терминала. Используйте контейнер с подключенным каталогом хоста. Каждый вариант может направить вывод в другое место.
Ищите по маркеру, а не по имени файла. Скопированная полезная нагрузка может получить случайное имя, попасть в базу SQLite или оказаться сжатой в архиве. Если двоичный файл или база содержит маркер, определите создавший ее процесс и решите, нужны ли ему настройка, исключение, очистка или другая граница выполнения.
Храните небольшую запись теста с версией агента, версией операционной системы, включенными плагинами, проверенными командами, найденными путями и результатом очистки. Обновляйте ее после добавления инструмента, способного выполнять команды или отправлять запросы. Это скучная работа, но она обнаруживает регрессии, которые не заметит проверка исходного кода.
Проведите первый тест с безвредным маркером уже сегодня. Если он появится там, где вы не ожидали, сначала исправьте компонент, который записывает данные, а уже потом создавайте сложный скрипт удаления. Самый чистый временный файл тот, в который изначально не попали учетные данные или чувствительный ответ.
Вопросы и ответы
Где AI-агенты для программирования оставляют временные файлы?
Инструменты агента могут записывать чувствительные данные во временные каталоги, журналы отладки, историю shell, резервные копии редактора, кэши, отчеты о сбоях и слои контейнеров. URL запроса, заголовок авторизации, вывод команды, путь к закрытому ключу или загруженное тело ответа могут остаться там после завершения работы агента.
Безопасно ли удаление временного файла удаляет его полностью?
Нет. rm удаляет запись о каталоге, но не доказывает, что все копии исчезли из снимков, резервных копий, журналов, открытых файлов или синхронизируемых папок. В системах с SSD перезапись и утилиты безопасного удаления тоже не дают той гарантии, которую от них ожидают.
Как найти временные файлы, созданные инструментом агента в macOS?
Начните с echo "$TMPDIR", затем проверьте недавно измененные файлы в этом каталоге, /private/tmp, папках поддержки приложений и кэшах. Сначала ищите известные тестовые маркеры, а затем осторожно проверяйте названия полей запросов, например Authorization, Bearer, token и password.
Безопасно ли помещать API-токены в URL запросов?
Их не следует использовать. Ключ API в URL может попасть в историю браузера, записи прокси, журналы команд, отладочный вывод и отчеты об ошибках. Передавайте учетные данные в заголовке авторизации или используйте шлюз действий, который хранит их отдельно от процесса агента.
Может ли AI-агент безопасно запускать команды с переменными окружения?
Иногда, но только если конечная точка принимает короткоживущие учетные данные, а вывод не может содержать секреты. Команда, которая раскрывает долгоживущий токен в аргументах, плохо подходит как стандартный вариант: его могут записать списки процессов, история shell, журналы и отчеты об ошибках.
Безопасно ли хранить журналы отладки после устранения проблемы?
Считайте отладочный журнал чувствительным, пока не проверите его формат. Режим отладки часто записывает полные запросы, заголовки, тела ответов, аргументы команд и трассировки стека, потому что именно эти данные нужны разработчикам при поиске причины проблемы.
Как не дать агенту прочитать API-ключи?
Хорошая схема отделяет полномочия от генерации текста. Агент может запросить действие, но другой локальный компонент хранит учетные данные, выполняет HTTP- или SSH-операцию и возвращает только нужный результат.
Защищают ли контейнеры от утечки чувствительных временных файлов?
Очистка контейнера помогает, но не охватывает подключенные тома, каталоги агента на хосте, экспорт кэша сборки, артефакты CI и скопированные журналы. Проверяйте хост и каждый каталог с артефактами, а не только файловую систему внутри контейнера.
Как долго хранить журналы и временные файлы агента?
В обычной работе удаляйте временные данные сразу после запуска, а на определенный срок сохраняйте только проверенную операционную запись. Во время инцидента остановите автоматическое удаление нужных свидетельств, сохраните их с ограниченным доступом и смените раскрытые учетные данные до начала подробного анализа.
Как проверить, работает ли очистка агента?
Создайте заведомо фиктивный маркер, поместите его в типичный запрос и вывод команды, запустите агента, а затем найдите эту строку во всех предполагаемых местах хранения. Повторите тест с включенным отладочным журналированием, неудачным запросом и отмененным запуском, потому что именно ветки ошибок часто оставляют больше всего данных.