[27] PerformanceEventTiming UA-shadow-DOM leak
PerformanceEventTiming.target에서 UA shadow DOM encapsulation leak를 수정한 diff로, Low로 평가되었습니다. author listener가 등록되지 않은 경우, entry가<input>의 shadow tree 내부 노드를 retargeting 없이 저장하여 스크립트가 내부 구현 노드의 참조를 얻는 것이 가능했습니다. information disclosure에 해당하며, memory primitive는 없습니다.
Source/WebCore/page/LocalDOMWindow.cpp
Performance API entry에 node reference를 기록하는 시점에 사양이 요구하는 shadow DOM retargeting 단계가 누락된 패턴.
이 버그의 trigger 조건인 "해당 타입의 event listener가 없는 상황"은 버그를 찾는 관점에서 유용한 패턴을 상기시켜 줍니다. event dispatch를 통해 정상적으로 처리되었을 state가 raw 상태로 남을 수 있는 code path는, 다른 어떤 관찰자도 없을 때에만 실행되는 경로에 정확히 존재하기 때문입니다.
재현 방법은 다음과 같습니다. 낮은 durationThreshold로 event 타입에 대한 PerformanceObserver를 등록한 뒤, click handler에서 busy-wait으로 처리를 지연시킵니다. author listener가 없는 sibling pointerup/mouseup entry가 threshold를 초과하면, entry.target.getRootNode()를 통해 UA shadow root가 노출됩니다.
브라우저는 built-in form control의 내부 구조를 web content로부터 숨기기 위해 UA shadow DOM encapsulation 경계에 의존합니다. 이 vulnerability는 해당 경계를 약화시킵니다.
Audit directions
- 일반 event dispatch 밖에서 DOM node reference를 기록하는 Performance/observer API. WebCore 내에서
Node*/EventTarget*를Performance*Entry에 기록하는 지점을 모두 점검하고, 각각이Document::retargetToScope를 거치는지 확인합니다.LargestContentfulPaint,Element Timing,PerformanceLongAnimationFrameTiming부터 시작합니다. - author listener가 없을 때만 실행되는 code path.
hasEventListeners,hasCapturingEventListeners의 early-return 지점을 검색하고, 해당 경로에서 캡처된 node reference가 retargeting을 거쳤는지 확인합니다. Document::retargetToScope/Node::retargetTo*의 다른 호출 지점. shadow-root node가 누출될 수 있는 모든 위치에서 일관되게 사용되고 있는지 확인합니다.