fix(security)- refuse srcdoc in generic attribute writers and route d… - #57
Merged
Conversation
…ynamic html attributes through the shared policy
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Two attribute-security gaps found after the framework-wide hardening pass in #56.
srcdocwas treated as an inert attribute. The shared policy sorted attributes into event handlers, URLs,srcset,style, and "everything else, whichsetAttributestores as inert text". That last claim is false for exactly one attribute: the browser decodes<iframe srcdoc>and parses it as a complete nested HTML document, and without a sandbox its scripts run with the embedding page's origin.Escaping is not a weaker defence here — it is the wrong layer.
srcdoc="<script>…"is correctly escaped as an attribute value and still becomes<script>…once parsed as a document, because the escaping is undone before the parse by design. So the generic writers refuse the attribute outright, and — as withon*— remove any pre-existing value rather than merely declining to add one. Taking the slot means governing it, so server markup or a third-party widget cannot leave a live document behind.The rule lives in one place (
isHtmlContentAttribute()) and is consulted by the tag factory,bindAttribute/bindDynamic,bindAttrs,enhance().attr(),svgElement, thehtmltemplate, and all four SSR attribute serializers.Three things deliberately not done: arbitrary HTML is not sanitized (a much larger problem, and doing it badly is worse than refusing);
TrustedHTMLdoes not unlock it, because that type is a compile-time brand —trustHTML()returns the same string through a cast — with no runtime identity; andsandboxdoes not unlock it either, since making security depend on an attribute later code can remove is not a guarantee.Dynamic
htmlattributes bypassed the shared policy. The tagged-template executor carried its own rules —srcset, then URL attributes, then write. That list was the shared policy minusstyle, sohtml`<div style=${untrusted}>`never reached the declaration-list sanitizer, contradicting the sanitizer's own documented invariant, and would have missed the newsrcdocrule too.A duplicated policy is a policy that drifts, so there is now one. Both dynamic forms commit through the shared primitive — a single expression, and a mixed attribute after concatenating statics and expressions. Sanitizing the assembled string is what catches attacks split across the boundary, like
href="java${x}:…". Fully static template text is unchanged: an attribute the developer typed into their own source stays developer-controlled, at the same trust level as hand-written markup.Related Issue
Closes #
Type of Change
Breaking: applications that set
srcdocthrough any generic SibuJS attribute API will find the attribute refused and removed. There is no opt-in — a trusted-document API would need a runtime-verifiable wrapper or browser Trusted Types, and is not part of this change.Checklist