
Bloomberg Memray: хранимая XSS-уязвимость через неэкранированные метаданные командной строки
Bloomberg Memray: Stored XSS через неэкранированные метаданные командной строки
Я обнаружил эту проблему при проверке Memray, Python-профилировщика памяти от Bloomberg, с простым вопросом:
Могут ли контролируемые злоумышленником метаданные времени выполнения небезопасно попасть в отчет, отображаемый в браузере?
В данном случае ответ был да.
Ошибка находилась в пути генерации HTML-отчетов Memray, где метаданные командной строки выводились в отчет, открываемый в браузере, без экранирования. Это превратило операционное поле в исполняемый HTML-приемник и в конечном итоге привело к CVE-2026-32722.
Проект: Memray на GitHub
Уведомление: GHSA-r5pr-887v-m2w9 /CVE-2026-32722
attacker-controlled argv → metadata.command_line → HTML template sink without escaping → raw markup in generated report → browser-side JavaScript execution
Memray — это Python-профилировщик памяти.
Он инструментирует процесс Python, записывает поведение выделения памяти и создает отчеты, которые помогают разработчикам понять:
Некоторые из этих отчетов создаются в виде HTML и открываются в браузере.
Это делает генерацию отчетов реальной границей безопасности.
Важен не вопрос о том, является ли Memray «локальным инструментом».
Важен вопрос: могут ли контролируемые злоумышленником данные небезопасно попасть в вывод, отображаемый в браузере.
В данном случае — могли.
Многие недооценивают инструменты разработчика.
Это ошибка.
Как только инструмент:
он наследует те же риски, связанные с кодированием вывода, что и веб-приложение.
Вот в чем была суть проблемы.
Эта ошибка была не в логике профилирования. Не в отслеживании выделения памяти. Не в собственной работе с памятью.
Это был классический провал доверия границ:
Этого достаточно, чтобы создать реальную уязвимость.
Я не подходил к Memray с фаззингом случайных опций CLI или погоней за сбоями.
Более сильный подход — сначала определить наиболее вероятную поверхность безопасности.
Для Memray это была генерация HTML-отчетов.
Почему?
Потому что вывод HTML вводит браузерный приемник, а браузерные приемники превращают обычные ошибки метаданных в проблемы безопасности, если:
Именно это и произошло.
Ошибка сводится к двум строкам.
В:
def get_render_environment() -> jinja2.Environment:
loader = jinja2.PackageLoader("memray.reporters")
env = jinja2.Environment(loader=loader)
среда Jinja создается без автоматического экранирования.
Затем в:
Command line: <code>{{ metadata.command_line }}</code><br>
metadata.command_line выводится напрямую в HTML.
Это и есть вся уязвимость.
Потому что metadata.command_line находится под влиянием злоумышленника.
Memray записывает командную строку, использованную для запуска профилируемой программы.
Это означает, что контролируемые пользователем значения из argv сохраняются как метаданные и затем вставляются в отчет.
Таким образом, цепочка эксплуатации прямолинейна:
metadata.command_lineЭто превращает метаданные в исполняемое содержимое браузера.
Важное различие — выполнение.
Множество ошибок приводят к некорректному HTML. Этого недостаточно.
Здесь содержимое, управляемое злоумышленником, было не просто видно в исходном коде страницы. Оно интерпретировалось браузером как активный HTML и выполнялось как JavaScript.
Вот разница между:
Поэтому вопрос был не:
«Может ли HTML появиться в отчете?»
Настоящий вопрос был:
«Может ли HTML, управляемый злоумышленником, стать исполняемым при открытии отчета?»
Ответ был да.
Мой первоначальный репродуцирующий пример использовал явный скрипт и управляемый злоумышленником аргумент:
cat > victim.py <<'PY'
x = [b"A" * 1024 for _ in range(1000)]
print("done")
PY
python -m memray run -o poc.bin victim.py ''
python -m memray flamegraph -o poc.html poc.bin
Сгенерированный HTML содержал необработанную разметку, управляемую злоумышленником:
Command line: <code>~/memray/src/memray/__main__.py run -o poc.bin victim.py </code><br>
Открытие или обновление сгенерированного отчета вызывало выполнение JavaScript.
Это установило основное утверждение:
Позже, во время согласованного раскрытия, мейнтейнер упростил репродуцирующий пример:
python -m memray run -o poc.bin -c '# '
Эта версия лучше, потому что она более прямо изолирует уязвимую границу:
Пэйлоад был намеренно простым:
Речь не о броских пэйлоадах.
Это чистый зонд для выполнения, потому что:
Для такого класса ошибок этого достаточно.
Одного типа отчета уже было бы достаточно, чтобы обосновать проблему.
Но я хотел выяснить, была ли это изолированная или структурная проблема.
Я подтвердил такое же поведение в:
--no-webЭто было важно по двум причинам.
Это показало, что уязвимый приемник использовался повторно в нескольких HTML-выводах.
Это доказало, что ошибка не зависела от внешних CDN-ресурсов.
--no-web все равно воспроизводил проблему, что означает, что проблема была в собственном сгенерированном HTML и обработке шаблонов Memray, а не в удаленном JavaScript.
Это сделало аргумент гораздо сильнее.
Основной заботой мейнтейнера был практический контроль злоумышленника.
Это справедливо.
Это не та проблема, когда неаутентифицированный удаленный злоумышленник попадает на открытый HTTP-эндпоинт и получает мгновенный эффект.
Условие эксплуатации более узкое:
Поэтому реалистичная классификация — низкая серьезность.
Это не делает ошибку слабой.
Серьезность связана с условиями эксплуатации и вероятным воздействием. Валидность — с тем, реальна ли проблема.
Эта проблема была явно реальной:
Вот почему она все равно получила CVE.
Исправление было минимальным и корректным.
Мейнтейнер изменил:
{{ metadata.command_line }}
на:
{{ metadata.command_line|e }}
Это правильное исправление, потому что оно напрямую устраняет уязвимый приемник.
Вместо вывода необработанной разметки, такой как:
шаблон теперь выводит экранированный текст:
<img src=x onerror=alert(1)>
Это сохраняет информационную ценность поля командной строки, удаляя путь выполнения в браузере.
Мейнтейнер также проверил остальной контекст шаблона и пришел к выводу, что:
|tojson
Таким образом, проблема была правильно локализована в metadata.command_line.Это именно тот обзор исправления, который вы хотите видеть в реальном раскрытии.
Это было сообщено приватно через GitHub Security Advisories.
Мейнтейнеры:
Проблеме был присвоен: CVE-2026-32722
Ключевой урок здесь прост:
метаданные не являются автоматически доверенными только потому, что выглядят как операционные.
Ничто из этого не имеет значения, как только содержимое, управляемое злоумышленником, попадает в вывод, отображаемый в браузере, без экранирования.
Как только инструмент выдает HTML, к нему нужно относиться как к приложению, производящему HTML.
Вот настоящий вывод.
Эта уязвимость была не про хитрый пэйлоад.
Она была про выявление правильной границы.
Memray брал управляемые злоумышленником метаданные командной строки и выводил их в сгенерированный HTML без экранирования. Остальное сделал браузер.
Вот почему это стало CVE-2026-32722.
Исправлено в Memray 1.19.2.
