← All issues

[6] Content served as video/mp2t can be loaded as html

Severity: Medium | Component: WebCore DOMImplementation / MIME registry | 59efb64

Medium으로 평가된 근거는 세 가지입니다. 첫째, 관측 가능한 영향이 response origin 내 MIME confusion 기반 script 실행 primitive에 해당합니다. 둘째, regression test에서 data:video/mp2t,... iframe을 통한 재현이 확인되었습니다. 셋째, 실제 배포 환경에서의 영향 범위는 memory safety 문제가 아니라 attacker가 response Content-Type을 제어할 수 있는지에 따라 결정됩니다.

Source/WebCore/dom/DOMImplementation.cpp

#if ENABLE(VIDEO)
- MediaEngineSupportParameters parameters;
- parameters.type = ContentType { contentType };
- parameters.url = url;
- if (MediaPlayer::supportsType(parameters) != MediaPlayer::SupportsType::IsNotSupported)
+ if (MIMETypeRegistry::isSupportedMediaMIMEType(contentType))
return MediaDocument::create(frame, settings, url);
#endif

Source/WebCore/platform/MIMETypeRegistry.cpp

bool MIMETypeRegistry::isSupportedMediaMIMEType(const String& mimeType)
{
if (mimeType.isEmpty())
return false;
+ auto lowercaseType = mimeType.convertToASCIILowercase();
+ if (!lowercaseType.startsWith("video/"_s) && !lowercaseType.startsWith("audio/"_s) && !lowercaseType.startsWith("application/"_s))
+ return false;
return supportedMediaMIMETypes().contains(mimeType);
}

Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm

void MediaPlayerPrivateMediaSourceAVFObjC::getSupportedTypes(HashSet<String>& types)
{
- types = AVStreamDataParserMIMETypeCache::singleton().supportedTypes();
+ types.clear();
}

세 가지 변경이 함께 적용되었습니다.

먼저 DOMImplementation::createDocument는 더 이상 MediaPlayer::supportsType()을 통해 MediaDocument 생성 여부를 판단하지 않습니다. 이제는 MIMETypeRegistry::isSupportedMediaMIMEType(contentType)을 직접 조회합니다.

다음으로 isSupportedMediaMIMEType에 최상위 allowlist가 추가되었습니다. video/, audio/, application/으로 시작하지 않는 MIME은 모두 거부됩니다.

마지막으로 MediaPlayerPrivateMediaSourceAVFObjC::getSupportedTypestypes.clear()로 변경되었습니다. MSE 전용 AVFoundation 엔진이 더 이상 전역 supported-media 캐시를 오염시키지 않게 되었습니다.

MIME type 기반의 document class 분기가 사전 canShowMIMEType 허용 검사와 서로 다른 판단 기준을 참조하고 있었기 때문에, renderable로 허용된 media MIME이 HTML default path로 fall-through되는 상황이 발생했습니다.

Frame load가 발생하면 FrameLoaderMIMETypeRegistry::canShowMIMEType(type)을 호출해 inline 렌더링 여부를 결정합니다. 이 검사를 통과한 type만 DOMImplementation::createDocument로 전달됩니다.

createDocument는 Content-Type을 Document 서브클래스에 매핑하는 연쇄 if/return 구조입니다. text/htmlHTMLDocument, image MIME은 ImageDocument, 지원되는 media MIME은 MediaDocument로 분기되며, 어디에도 해당하지 않으면 최종적으로 HTMLDocument가 반환됩니다.

Media MIME 레지스트리는 각 MediaPlayerFactorygetSupportedTypes callback에서 type을 수집해 집계합니다. MSE(Media Source Extensions)는 JS 기반 스트리밍 파이프라인입니다. MediaPlayerPrivateMediaSourceAVFObjC::supportsTypeAndCodecs는 호출자가 platformType == PlatformMediaDecodingType::MediaSource를 전달하지 않는 한 IsNotSupported를 반환합니다. 결과적으로 video/mp2t와 같은 MSE 전용 type은 MSE 엔진에 등록되어 있지만, bare-URL 로드 방식으로는 재생이 불가능합니다.

canShowMIMEType(레지스트리 기반)와 createDocument(MediaPlayer::supportsType 실시간 조회)는 개념적으로 동일한 판단을 서로 다른 기준에 따라 수행하고 있었습니다.

MSE 엔진은 video/mp2tsupportedMediaMIMETypes()에 등록해 두었기 때문에, canShowMIMEType("video/mp2t")는 true를 반환했고 로드가 진행되었습니다. 이어서 createDocument가 MSE가 아닌 platformType(bare-URL 로드)으로 MediaPlayer::supportsType(parameters)를 조회하면, MSE 엔진은 거부하고 다른 어떤 엔진도 video/mp2t를 처리하지 않습니다. 결국 MediaDocument, ImageDocument, PDFDocument 분기를 모두 통과한 뒤 기본 HTMLDocument 경로로 떨어지게 됩니다.

🔒

Two MIME oracles, one decision — and when they disagreed the fall-through path led somewhere unexpected. Full mechanism, attacker model, and registry-pollution analysis inside.

더 확인하려면 구독해 주세요

🔒

Four reusable audit patterns covering document-factory dispatch, MIME-registry hygiene, predicate validation, and a data-URI amplifier — each with concrete grep starting points.

더 확인하려면 구독해 주세요