
CVE-2026-74970, Firefox WebRender의 Fission 사이트 격리 우회
이 디렉터리에는 Firefox WebRender의 Fission 사이트 격리 인가 우회에 대한 정직한 재현 스캐폴드가 들어 있습니다. Fission에서는 각 콘텐츠 프로세스가 고유한 PipelineId 네임스페이스를 소유하지만, 컴포지터블 PipelineId를 등록하는 GPU 프로세스 코드는 해당 PipelineId의 네임스페이스가 전송한 프로세스에 속하는지 검사하지 않았습니다. 따라서 침해된 콘텐츠 프로세스는 다른 프로세스의 네임스페이스에 PipelineId를 등록하고, 공유 매니저에서 해당 오리진의 비동기 이미지 파이프라인을 덮어쓸 수 있습니다.
이곳의 모든 것은 합성 콘텐츠만을 사용하는 로컬 빌드 Firefox 트리를 대상으로 합니다. 어떤 라이브 또는 제3자 시스템도 공격, 접촉, 프로브, 참조하지 않습니다. 이는 원격 코드 실행도 메모리 손상도 아니며, 위협 모델은 이미 침해된 콘텐츠 프로세스입니다.
일치하는 PoC 저장소: https://github.com/defineid/Trespasser
Writeup: 이 포트폴리오의 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 프로세스 브리지는 네임스페이스가 전송한 프로세스에 속하지 않는 리소스를 거부해야 하므로, 한 콘텐츠 프로세스가 다른 프로세스의 렌더링 리소스를 주소 지정하거나 덮어쓸 수 없습니다.
GPU 프로세스에서 실행되는 WebRenderBridgeParent::AddPipelineIdForCompositable은 들어오는 파이프라인을 루트/WebRender 가드와 이 브리지 자체의 등록된 파이프라인 집합에 대해 검증했지만, PipelineId에 대해 MatchesNamespace를 호출하지 않았습니다. 같은 파일의 image-key, font-key, blob-key 경로는 모두 해당 MatchesNamespace 소유권 검사를 수행하지만, PipelineId 경로는 그렇지 않았습니다. RemovePipelineIdForCompositable도 마찬가지로 검사되지 않으므로, 제거 시에도 동일한 네임스페이스 소유권 허점이 존재합니다.
하위 단계에서 AsyncImagePipelineManager::AddAsyncImagePipeline은 MOZ_ASSERT로만 파이프라인의 고유성을 보호하는데, 이는 릴리스 빌드에서 no-op으로 컴파일됩니다. 따라서 위조된 교차 네임스페이스 PipelineId가 공유 AsyncImagePipelineManager에 도달하면, 매니저는 중복을 거부하지 않고 피해 오리진의 기존 비동기 이미지 파이프라인 항목을 조용히 덮어씁니다.
연쇄적으로, 침해된 콘텐츠 프로세스 A는 콘텐츠 프로세스 B(다른 오리진, Fission 하에서 별도 프로세스)의 네임스페이스에 속하는 PipelineId를 위조하고, 이를 컴포지터블 등록 경로로 제출하여 GPU 프로세스가 이를 수락하고 공유 매니저에서 B의 이미지 파이프라인을 덮어쓰게 할 수 있습니다.
Fission 하에서 이미 침해된 콘텐츠 프로세스입니다. 공격자는 이미 하나의 콘텐츠 프로세스에서 코드 실행 권한을 가지고 있으며(예: 별도의 콘텐츠 프로세스 버그를 통해), 공격자가 선택한 필드로 WebRender IPC 메시지를 보낼 수 있다고 가정합니다. 이 결함은 해당 프로세스가 사이트 격리 경계를 넘어 다른 오리진의 렌더링 리소스에 접근할 수 있게 하는 인가 누락입니다.
이는 메모리 손상이 아닌 Fission 사이트 격리 인가 우회입니다. 영향은 교차 오리진 렌더링 혼동과 교차 탭 서비스 거부입니다. 하위 소비자는 null 가드와 참조 카운팅으로 보호되므로 코드 실행으로 이어지지 않습니다. PoC는 코드 실행을 주장해서는 안 되며, 주장하지도 않습니다.
README.md — 이 파일.forge-namespace.patch — 로컬 Firefox 트리를 위한 연구용 패치. 콘텐츠 측에서는 XRE_IsContentProcess()와 환경 변수 MOZ_POC_FORGE_WR_NAMESPACE로 보호되며, 송신 PipelineId의 네임스페이스를 위조한다. GPU 프로세스 부모 측에서는 교차 네임스페이스 PipelineId가 등록될 때 ACCEPTED 진단을 출력하여, 누락된 검사가 이를 통과시켰음을 보여준다.poc.html — 콘텐츠 측의 기본 테스트 케이스: WebGL 캔버스(비동기 이미지 파이프라인이 생성되도록)와 교차 출처 아웃오브프로세스 iframe(Fission이 이를 별도의 콘텐츠 프로세스에 배치하도록)으로 구성된다. 일반 빌드에서는 정상적으로 렌더링되며 관찰 가능한 동작을 하지 않는다.victim.html — iframe이 로드하는 합성 두 번째 출처. 스크립트가 없는 단순한 페이지로, 그 유일한 역할은 활성 교차 출처 문서가 되는 것이며, Fission 하에서 자체 콘텐츠 프로세스와 자체 PipelineId 네임스페이스(위조된 등록이 대상으로 삼을 네임스페이스)에 배치된다.poc-render.png — 로컬 일반 Firefox 140.11.0esr에서 poc.html을 로드한 스크린샷. 테스트 페이지가 정상적으로 렌더링되는 모습을 보여준다: 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).
이 디렉터리를 서빙하여 poc.html의 프로세스 외 iframe이 실제로 다른 등록 가능 도메인에서 동반 victim.html을 로드하도록 하여, Fission이 iframe을 자체 콘텐츠 프로세스에 배치하게 합니다. 예를 들어 python3 -m http.server 8000 --bind ::를 실행하고 http://victim.localtest.me:8000/victim.html에서 iframe을 로드합니다. poc.html의 인라인 주석을 참조하세요.
forge 변수를 설정한 상태로 빌드를 실행하고 테스트 페이지를 로드합니다:
MOZ_POC_FORGE_WR_NAMESPACE=999999 ./mach run --temp-profile poc.html
999999은 실제 프로세스에 속하지 않도록 임의로 선택된 네임스페이스 값이며, 이를 통해 로그에서 위조된 교차 네임스페이스 등록이 명확히 드러난다.
패치가 적용된 취약한 빌드에서 GPU 프로세스 부모는 해당 프로세스에 속하지 않는 네임스페이스를 가진 PipelineId를 수락하고 등록하며, 다음과 같이 출력한다(이는 writeup에 표시된 정확한 형태이다):
[POC-2056558] ACCEPTED cross-namespace PipelineId:
sender-namespace=4 pipeline-namespace=999999 (should have been rejected)
sender-namespace는 송신 콘텐츠 프로세스가 정당하게 소유한 네임스페이스이고, pipeline-namespace는 위조된 값입니다. 두 값이 서로 다르다는 점, 그리고 등록이 수락되었다는 사실이 핵심입니다. 이를 거부했어야 할 소유권 검사가 누락되어 있기 때문입니다.
수정된 빌드(154 / ESR 153.1 이상)에서는 동일한 메시지가 IPC_FAIL과 함께 거부되며, 그러한 ACCEPTED 줄은 출력되지 않습니다. 이제 PipelineId 경로가 MatchesNamespace를 강제하기 때문입니다.
PipelineId 경로에서도 리소스 키 경로가 이미 사용하는 것과 동일한 네임스페이스 소유권 검사를 강제합니다:
if (!MatchesNamespace(aPipelineId)) {
return IPC_FAIL(this, "PipelineId namespace does not belong to the sending process");
}
AddPipelineIdForCompositable에 적용되며(RemovePipelineIdForCompositable에도 대칭적으로 적용됨), 네임스페이스가 송신 프로세스에 속하지 않는 모든 PipelineId를 거부하여 우회를 차단합니다.
poc.html을 로컬의 기본 Firefox 140.11.0esr에서 한 번 로드하여 poc-render.png로 캡처했습니다. 해당 스크린샷은 테스트 페이지가 정상적으로 렌더링되는 모습만 보여줍니다(WebGL 캔버스가 프레임을 그리고, 프로세스 외부 iframe이 victim.html을 로드함). 로컬 Firefox는 패치되지 않은 기본 빌드이므로, 스크린샷에는 위조된 등록도 없고 [POC-2056558] 로그 라인도 없습니다. 교차 네임스페이스 허용 출력을 캡처하려면, 위에서 설명한 대로 로컬의 취약한 빌드에 패치를 적용하고 직접 실행하십시오.이 스캐폴드는 누락된 권한 부여 검사가 교차 네임스페이스 PipelineId를 통과시키는 것을 입증하는 것 외에는 어떤 익스플로잇 프리미티브도 포함하지 않습니다. 코드 실행을 시도하지 않으며 메모리 손상도 발생시키지 않습니다.
이는 이미 보고되고 이미 패치된 CVE에 대한 분석 문서를 위해, 합성된 자체 작성 콘텐츠로 로컬에서 빌드한 Firefox 트리를 대상으로 합니다. 연구용 패치는 로컬 개발자 빌드에만 영향을 미치도록 보호되어 있으며, 분석 문서에서 설명하는 침해된 콘텐츠 프로세스 가정을 구현합니다. 원격 익스플로잇이 아닙니다. 여기서는 어떤 라이브 서비스나 제3자 서비스도 공격, 접촉, 프로빙하거나 공격을 참조하지 않습니다. 테스트 케이스의 프로세스 외부 iframe은 Fission 프로세스 분리를 재현하는 데 본질적이며 그렇게 문서화되어 있습니다. 최상위 페이지 자체에는 다른 네트워크 의존성이 없습니다.