[3] HTMLPlugInElement skips content extensions for embed/object loads
Severity: Medium | Component: WebCore HTML plugin elements | 7d28e39
Rated Medium because the diff fixes a deterministic content-blocker bypass reachable from any page that can author <embed>/<object> markup; impact is policy-evasion (tracker/malware/ad loads escaping user-installed rules), not memory corruption.
Plugin content loaded via <embed> and <object> elements was not checked against content extension rules. The fix adds a content-extension check in HTMLPlugInElement::canLoadURL so blocked URLs are rejected before the wouldLoadAsPlugIn deferral in updateWidget.
Source/WebCore/html/HTMLPlugInElement.cpp
+#if ENABLE(CONTENT_EXTENSIONS)
+#include "ContentExtensionsBackend.h"
+#include "ResourceLoadInfo.h"
+#include "UserContentProvider.h"
+#endif
...
bool HTMLPlugInElement::canLoadURL(const URL& completeURL) const
{
+#if ENABLE(CONTENT_EXTENSIONS)
+ if (completeURL.isValid()) {
+ RefPtr page = document().page();
+ RefPtr frame = document().frame();
+ RefPtr documentLoader = frame ? frame->loader().documentLoader() : nullptr;
+ RefPtr userContentProvider = frame ? frame->userContentProvider() : nullptr;
+ if (page && documentLoader && userContentProvider) {
+ auto results = userContentProvider->processContentRuleListsForLoad(*page, completeURL, ContentExtensions::ResourceType::Other, *documentLoader);
+ if (results.shouldBlock())
+ return false;
+ }
+ }
+#endif
return !isProhibitedSelfReference(completeURL);
}
LayoutTests/http/tests/contentextensions/block-embed-element.html
+<embed src="http://127.0.0.1:8000/contentextensions/resources/should-load.html?should-be-blocked" type="text/html" width="100" height="100"></embed>
+<embed src="http://127.0.0.1:8000/media/resources/test.pdf?should-be-blocked" type="application/pdf" width="100" height="100"></embed>
Patch Details
When ENABLE(CONTENT_EXTENSIONS) is on and the URL is valid, canLoadURL now obtains the document's Page, DocumentLoader, and UserContentProvider, then calls UserContentProvider::processContentRuleListsForLoad(page, completeURL, ContentExtensions::ResourceType::Other, documentLoader). If the aggregated result's shouldBlock() is true, canLoadURL returns false so the caller skips loading the plugin resource. Regression tests load <embed> and <object> resources matching a .*should-be-blocked URL filter and assert the standard 'Content blocker prevented frame...' console message fires.
Missing content-policy consultation on a resource-load path, allowing the plugin element class to bypass a filter applied uniformly to other element types.
Background
Content Extensions (also called content blockers) expose a declarative rule-list API to WebKit extensions and managed configurations. Each rule pairs a trigger (URL pattern, resource type, load context) with an action (block, block-cookies, css-display-none, make-https). UserContentProvider::processContentRuleListsForLoad is the engine entry point that evaluates all active rule lists for a load and returns aggregated actions; callers inspect results.shouldBlock() to decide whether to abort the load. HTMLPlugInElement is the C++ base class for <embed>, <object>, and legacy <applet>; its canLoadURL is the single funnel both subclasses consult before updateWidget asks the SubframeLoader to instantiate the plugin or subframe widget. Content-extension hooks on <iframe>, <img>, <script>, and XHR/fetch loads live in their respective loader paths.
Analysis
HTMLPlugInElement::canLoadURL validated the URL against self-reference checks but never consulted the content-extension engine. The rule-list evaluation path that exists for <img>, <script>, <iframe>, XHR, and other resource types was simply not wired into the plugin element class.
Aa Aaaaaaaa Aaaaaaaaa Aa Aaaaaaaaa Aaaa Aaaaaa Aa Aaaaaaa Aaaaaaaaaaaaaaaaaaa Aa Aaaaaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa a Aaa Aaaa Aaa Aaaaaa Aaaaaaaaa Aaaaaaa Aaaaaaa Aaaaa Aaaaaaaaa Aaaaaaa Aaaaaaaa Aaa Aaaa Aaaaaaaaa a a Aaaaaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaaa Aaaaaaa Aa Aaa Aa a Aaaaaa Aaa Aaaa Aaaaaaa Aaaaaaaa Aaaaaa Aaa Aaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaa Aaaaaaa Aaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaa Aaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaa Aaaaa Aaaaaaa Aaaaa Aaaaa Aa Aaa Aaaa Aaaaa Aaaaa Aaaa Aa Aaaaaaaaaaaaaaaaa Aaa Aaaa Aaaaa Aaaaaaaa Aaaaa Aaaaaaaaa Aaa Aaaaaaaaaa Aaaaaa Aaaaaaa a Aaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaa Aaaaaaaaaaa Aaa Aaa Aaaa Aaaaaaaa Aaa Aaaaaaaa Aaaaaaa Aaaaaaaaa Aaaaaaaaa Aaaaaaa Aaaaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaaa Aaa Aaaaaaaaaaaaaaa Aaaaa Aaaaaaaa Aaaa Aaaaa Aaa Aaaaaaaaaaaaaa Aaaaaa Aaaa Aa Aa Aaaaaaa Aaaaaaaa Aaaa Aaaa Aaaaaaa Aaaaaa a Aaaaa Aaa Aaaa Aaaaaaaaaaaaaaaaa Aaaaa Aaaaaaa Aaaaa Aaaaaaaaaaa Aaaa a Aaaaaaaaa Aaaaaa Aaaaaaa Aaaaa a Aa Aaaaaaaaa Aaaaaaa Aaa Aaaaaa Aaaa Aaaaaa Aaaaaa Aaa Aaa Aaaa Aaaaaaaaa Aaa Aaaaaaaa Aaa Aaaaaaaaa Aaa Aaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aa Aaaaaa Aa Aaa Aaaaaaaaaaa Aa a Aaaaaa Aaaa Aaaa a Aa Aa Aaaaaaaaaa Aaaaaa Aaaa Aaaaaaaaaaaaaa Aaaaa Aaaa Aaaaaaaaa a Aaaaaaa Aaaaaa Aaaaa Aaaaa Aaaaaaaa Aaaa a Aaaaaaaaa Aaaaaaaa
🔒How content-policy enforcement is distributed across WebKit's resource-loading classes, and what this commit reveals about coverage gaps in user-installed filters
Subscribe to read more
Audit directions
a Aaaaaa Aaaaaaa Aaaaaaa Aaaa Aaaaaaaa Aaaaaaaa Aaaaa Aaaaaaa Aaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaa Aaaaaaaaa Aaaaa Aaaaa Aaaaaaaaaaaaaa Aaaa Aaa Aaa Aaaaaaaaaa Aa Aaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaa Aaaaaa Aa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaa Aaaaaa Aaaaaaaaaaaaaa Aaa Aaaaaaa Aaaaaa a Aaaaaa Aaaaaaaaaaaaaaa Aaaaa a Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaaa Aaaaaaaa Aaaa Aaaaa Aaa Aaaaaaa Aaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaa
a Aaaaaaaa Aaaaaa Aaa Aaaaaaaaaaaaaa Aaaaaaaaaaaaaaaa Aaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaaa Aa Aaaa Aaaa Aaaa a a Aaaa Aaaaaa Aa Aaa Aaaaa Aaaaaa Aaa Aaaaa Aaa Aaa Aa Aaa Aaaa Aaaaaa Aaaaaa Aaaa Aaaaaa Aaaaaa Aaa Aaaaaaa Aaaaaaaaaa Aaaaaaaa Aaaaaa Aaa Aaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaa Aaa Aaa Aaaaaaa Aaaaa
a Aaaaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaaaaaa Aaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaaa Aaaaaaaaaaaaa Aaaa Aa Aaa Aaaaaa Aaaaaaaa Aaaaa Aaaaaaa Aaaa Aaaaaaaaa Aaa Aaa Aaaaaa Aa Aaaaaaaaaaaaa a Aaaaa Aaaaaaa Aa Aaa Aaaa Aa Aaaa Aaaa Aa Aaaaa Aaaaa Aa Aa Aaaa
a Aaaaaa Aaa Aaa Aaaaa Aaaaa Aaaaaa Aaaaaaaa Aaaaaaaa Aaaaaa Aaaa Aaaaaa Aaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aa Aaaaaaa Aaaaa Aa Aa Aaaaaa Aaaaaaaaaaaaa Aaaa Aaaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaa Aaaaa Aaaaaa Aaa Aaaaaaa Aaaaaaaaaa Aaaa Aaaaaaaa Aaaaaaa Aaaaaaaaaaaaa Aaa Aaaaaaaaaaaaaaaaa Aaaaaaa
🔒Several reusable audit patterns identified for finding sibling bypasses in other element and loader classes, with concrete starting points
Subscribe to read more