
CVE-2026-74970, обход изоляции сайтов Fission в Firefox WebRender
В этом каталоге находится честный каркас для воспроизведения обхода авторизации изоляции сайтов Fission в Firefox WebRender. В рамках Fission каждый контентный процесс владеет отдельным пространством имён PipelineId, но код GPU-процесса, регистрирующий композитируемый PipelineId, никогда не проверял, что пространство имён PipelineId принадлежит отправляющему процессу. Скомпрометированный контентный процесс может поэтому зарегистрировать PipelineId в пространстве имён другого процесса и перезаписать асинхронный образный конвейер этого origin в общем менеджере.
Всё здесь нацелено на локально собранное дерево Firefox и содержит только синтетический контент. Оно никогда не атакует, не связывается, не зондирует и не ссылается на какую-либо живую или стороннюю систему. Это не удалённое выполнение кода и не повреждение памяти; модель угроз предполагает уже скомпрометированный контентный процесс.
Соответствующий репозиторий PoC: https://github.com/defineid/Trespasser
Разбор: writeup-webrender-pipelineid.html в этом портфолио.
| Поле | Значение |
|---|---|
| CVE | CVE-2026-74970 |
| Компонент | Core / Graphics: WebRender |
| Класс | Обход изоляции сайтов |
| CWE | 862 (Отсутствие авторизации) · 284 (Некорректный контроль доступа) |
| Исправлено в | Firefox 154 · ESR 153.1 |
| Баг | https://bugzilla.mozilla.org/show_bug.cgi?id=2056558 |
| Репозиторий PoC | https://github.com/defineid/Trespasser |
В рамках Fission WebRender назначает каждому контентному процессу собственное пространство имён PipelineId. Мост GPU-процесса должен отклонять любой ресурс, пространство имён которого не принадлежит отправившему его процессу, чтобы один контентный процесс не мог адресовать или перезаписывать ресурсы рендеринга другого.
WebRenderBridgeParent::AddPipelineIdForCompositable, выполняющийся в GPU-
процессе, проверял входящий конвейер относительно защиты root/WebRender и
относительно собственного набора зарегистрированных конвейеров этого моста, но
никогда не вызывал MatchesNamespace для PipelineId. Пути image-key, font-key
и blob-key в том же файле все выполняют эту проверку принадлежности
MatchesNamespace; путь PipelineId просто её не выполнял.
RemovePipelineIdForCompositable также не проверяется, поэтому та же дыра в
принадлежности пространства имён существует и при удалении.
Ниже по потоку AsyncImagePipelineManager::AddAsyncImagePipeline защищает
уникальность конвейера только с помощью MOZ_ASSERT, который в релизных
сборках компилируется в пустую операцию. Поэтому, когда поддельный PipelineId
из чужого пространства имён достигает общего AsyncImagePipelineManager,
менеджер не отклоняет дубликат: он молча перезаписывает существующую запись
асинхронного образного конвейера origin-жертвы.
Объединённые вместе, эти шаги позволяют скомпрометированному контентному процессу A подделать PipelineId, пространство имён которого принадлежит контентному процессу B (другой origin, в отдельном процессе в рамках Fission), отправить его по пути регистрации композитируемого ресурса и добиться того, чтобы GPU-процесс принял его и затёр образный конвейер B в общем менеджере.
Уже скомпрометированный контентный процесс в рамках Fission. Предполагается, что у атакующего уже есть выполнение кода в одном контентном процессе (например, через отдельный баг контентного процесса) и возможность отправлять IPC-сообщения WebRender с полями, выбранными атакующим. Этот дефект — та самая отсутствующая авторизация, которая позволяет этому процессу проникнуть через границу изоляции сайтов в ресурсы рендеринга другого origin.
Это обход авторизации изоляции сайтов Fission, а не повреждение памяти. Влияние — межorigin-путаница рендеринга и отказ в обслуживании между вкладками. Нижестоящие потребители защищены проверками на null и подсчётом ссылок, поэтому это не приводит к выполнению кода. PoC не должен и не заявляет о выполнении кода.
README.md — этот файл.forge-namespace.patch — исследовательский патч для локального дерева Firefox. На стороне контента, под защитой XRE_IsContentProcess() и переменной окружения MOZ_POC_FORGE_WR_NAMESPACE, он подделывает пространство имён исходящего PipelineId. На родительской стороне GPU-процесса он выводит диагностику ACCEPTED, когда регистрируется PipelineId из другого пространства имён, демонстрируя, что отсутствующая проверка пропустила его.poc.html — минимальный тестовый случай на стороне контента: WebGL-канвас (чтобы создавался асинхронный конвейер изображений) плюс кросс-доменный внепроцессный iframe (чтобы Fission разместил его в отдельном контентном процессе). На стандартной сборке он отрисовывается нормально и не производит наблюдаемых действий.victim.html — синтетический второй origin, который загружает iframe. Это тривиальная страница без скриптов, единственная задача которой — быть живым кросс-доменным документом, чтобы под Fission она попадала в собственный контентный процесс со своим пространством имён PipelineId (то пространство имён, на которое была бы нацелена поддельная регистрация).poc-render.png — скриншот poc.html, загруженного в локальном стандартном Firefox 140.11.0esr. Он показывает нормальную отрисовку тестовой страницы: WebGL-канвас рисует свой кадр, а внепроцессный iframe загружает victim.html. Он показывает только безобидную отрисовку. Сам обход требует исследовательского патча и уязвимой сборки и не был здесь вызван (см. статус проверки).Эти шаги предназначены для выполнения автором на локальной копии исходников Firefox. Ничего из этого не выполнялось против Firefox в данной среде (см. статус проверки ниже).
Получите уязвимое дерево исходников Firefox (до 154 / до ESR 153.1) и убедитесь, что Fission включён (fission.autostart = true, значение по умолчанию в последних сборках).
Примените исследовательский патч из корня дерева исходников:
patch -p1 < forge-namespace.patch
Патч затрагивает gfx/layers/wr/WebRenderBridgeChild.cpp (сторона контента, подделывает пространство имён) и gfx/layers/wr/WebRenderBridgeParent.cpp (сторона GPU-процесса, выводит диагностику ACCEPTED). Оба изменения инертны, если не выполнены условия защиты.
Соберите обычным образом (./mach build).
Раздайте этот каталог так, чтобы внепроцессный iframe из poc.html загружал сопутствующий victim.html с действительно другого регистрируемого домена, чтобы Fission поместил iframe в отдельный процесс контента. Например, python3 -m http.server 8000 --bind :: и загрузите iframe с http://victim.localtest.me:8000/victim.html. См. встроенный комментарий в poc.html.
Запустите сборку с установленной переменной forge и загрузите тестовую страницу:
MOZ_POC_FORGE_WR_NAMESPACE=999999 ./mach run --temp-profile poc.html
999999 — это произвольное значение пространства имён, выбранное так, чтобы оно не принадлежало ни одному реальному процессу; оно делает поддельную регистрацию из чужого пространства имён очевидной в журнале.
На уязвимой сборке с применённым патчем родительский процесс GPU принимает и регистрирует PipelineId, пространство имён которого не принадлежит ни одному такому процессу, и выводит (это точная форма, показанная в отчёте):
[POC-2056558] ACCEPTED cross-namespace PipelineId:
sender-namespace=4 pipeline-namespace=999999 (should have been rejected)
sender-namespace — это пространство имён, законно принадлежащее отправляющему процессу контента; pipeline-namespace — поддельное значение. Эти два различающихся значения, а также тот факт, что регистрация была принята, и есть суть проблемы: проверка владения, которая должна была её отклонить, отсутствует.