Skip to content

SVG script element: HTML and SVG 2 point at each other, and HTML links to SVG Tiny 1.2 #13149

Open

Description

@karlcow

About #902

While looking at how an external script in an inline SVG gets fetched, I followed the references between HTML and SVG 2 and they send you back and forth.

HTML, in the parser, for a script end tag in foreign content:

If the active speculative HTML parser is null and the user agent supports SVG, then Process the SVG script element according to the SVG rules.

The link on "Process the SVG script element" goes to SVG Tiny 1.2.

SVG 2, script element processing:

A script element must be processed as an HTML script element is, following prepare the script element [HTML], with its href attribute in place of the HTML src attribute.

So HTML says to look at SVG, and SVG says to look at HTML. But "prepare the script element" only talks about the HTML element and reads src directly. A few places where I can't tell what an SVG script element is supposed to do:

HTML already treats the SVG element as a script element elsewhere (document.currentScript, HTMLOrSVGScriptElement, setHTML). Only the processing is missing.

I suggest

  1. to fix the link to point to SVG 2,
  2. and to add a short note in "prepare the script element" saying that for an SVG script element href is used in place of src and the attributes it does not have are ignored.

SVG 2 already defers to HTML for the rest.
If you would rather have SVG 2 list the steps it overrides, I can write that side.

Activity

  1. karlcow commented on Oct 26, 2026

    @karlcow
    MemberAuthor

    Let's check what browsers do today. Each case is a small HTML page in its own iframe, with an SVG script element in an inline SVG. The script is a data: URL that posts a message to the page, so I can tell whether it ran. The examples below are shortened: the real script also sends document.readyState and whether the last paragraph of the page exists yet, which is what cases 8 and 9 are judged on.

    Cases 4 to 6 add a Content Security Policy first, set with a meta element. script-src data: blocks inline scripts and allows the data: URL.

    <!-- 1 -->
    <svg><script href="data:text/javascript,parent.postMessage('ran','*')"/></svg>
    
    <!-- 2 -->
    <svg><script xlink:href="data:text/javascript,parent.postMessage('ran','*')"/></svg>
    
    <!-- 3: two different scripts, to see which one is used -->
    <svg><script href="data:text/javascript,parent.postMessage('href','*')"
                 xlink:href="data:text/javascript,parent.postMessage('xlink','*')"/></svg>
    
    <!-- cases 4 to 6 start with this -->
    <meta http-equiv="Content-Security-Policy" content="script-src data:">
    
    <!-- 4 -->
    <svg><script href="data:text/javascript,parent.postMessage('ran','*')"/></svg>
    
    <!-- 5 -->
    <svg><script xlink:href="data:text/javascript,parent.postMessage('ran','*')"/></svg>
    
    <!-- 6, control: inline text -->
    <svg><script>parent.postMessage('ran','*')</script></svg>
    
    <!-- 7 -->
    <svg><script nomodule href="data:text/javascript,parent.postMessage('ran','*')"/></svg>
    
    <!-- 8 -->
    <svg><script async href="data:text/javascript,parent.postMessage('ran','*')"/></svg>
    
    <!-- 9 -->
    <svg><script defer href="data:text/javascript,parent.postMessage('ran','*')"/></svg>
    
    <!-- every case ends with -->
    <p id="after">after</p>
    Case Safari 27.0 Chrome 158.0.0.0 Firefox 160.0
    1 href runs runs runs
    2 xlink:href runs runs runs
    3 both href used href used href used
    4 href, with the policy runs runs runs
    5 xlink:href, with the policy runs runs runs
    6 inline text, with the policy (control) blocked blocked blocked
    7 nomodule runs runs runs
    8 async async async async
    9 defer not deferred not deferred deferred

    The bold rows are the ones that decide anything.

    To remind what the HTML spec says, for a script like case 4, which has an href and nothing written inside the element:

    No engine does that. All three use href as the source, and a policy that blocks inline scripts does not block it. The text is what is unclear here, not the behavior.

    The only difference is defer. SVG 2 does not list a defer attribute for script, and Firefox honors it anyway.

    For Safari 27.0, Firefox 160.0 and Chrome 158.0.0.0, at least, all browsers engines agree on everything else in the table.

  2. annevk commented on Oct 26, 2026

    @annevk
    Member

    If HTML needs to actually define the full processing model we might need a bit more language than a note, but it seems like a reasonable direction to me.

  3. karlcow commented on Oct 28, 2026

    @karlcow
    MemberAuthor

    another idea.

    • href is used for the script element in SVG because of the history of xlink:href. xlink:href is being deprecated.
    • I wonder if we could move SVG script element to the src attribute but as an alias of href to take into account sanitizers, and other subtleties.
  4. annevk commented on Oct 28, 2026

    @annevk
    Member

    The sanitizer already accounts for all the spellings of the attribute. It might have been a good change when the alternative to xlink:href was introduced, but having three attributes to do the same thing doesn't seem great.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions