Skip to content

Attributes: Don't stringify values as it breaks Trusted Types #4948

Closed

Description

@mgol

Originally posted by @koto in #4409 (comment)

I noticed one violation still in jQuery.attr, where the value of the attribute is stringified before calling setAttribute:

const policy = trustedTypes.createPolicy('a', {createScriptURL: s=>s})
jQuery(aScript, policy.createScriptURL('foo'));

Uncaught TypeError: Failed to execute 'setAttribute' on 'Element': This document requires 'TrustedScriptURL' assignment.
    at attr (jquery.js:6997)
    at access (jquery.js:3467)
    at jQuery.fn.init.attr (jquery.js:6955)
    at <anonymous>:1:6

There is a workaround via .attr hooks, but it might be worth addressing nonetheless.

It seems like this was introduced in ff75767, I suspect to workaround an IE <= 9 bug, which incorrectly stringified objects passed to setAttribute.

I'm not sure what the most elegant solution would be here, I guess it depends on whether jQuery 4 aims to support IE9. If not, it's safe not to stringify values (browser API would). If yes, then there's only a less-than-ideal option of testing for the bug? IIRC this would be a good test:

with (document.createElement('div')) {
  setAttribute('title', {toString:()=>''}); 
  getAttribute('title') === ''
}

Activity

  1. mgol commented on Oct 7, 2021

    @mgol
    MemberAuthor

    jQuery 4.x will only support IE 11 so if this was just to please IE <=9 we should be good to remove the manual stringification.

  2. added this to the 4.0.0 milestone on Oct 7, 2021
  3. self-assigned this
    on Oct 7, 2021
  4. added a commit that references this issue on Oct 7, 2021
    5965d0b
  5. mgol commented on Oct 7, 2021

    @mgol
    MemberAuthor

    A draft PR: #4949. Setting the attribute now works but the script will still be blocked. This is because in domManip scripts are not inserted directly but instead first disabled and then their src attributes are read and inserted in fresh scripts.

    There's probably not much we can do when the scripts are deep inside of the inserted HTML string - natively scripts would not fire then but jQuery does execute them which will not work here. However, we could at least make .append(scriptElem) work by forking the code path and treating such top-level scripts independently.

    I think we could land #4949 as-is, just without the part where it checks if the script was actually invoked and then we can tackle the remaining issue separately.

  6. koto commented on Oct 8, 2021

    @koto

    I agree. In general the behavior where jQuery takes the script nodes from the HTML string to add them separately feels like an antipattern nowadays (for example, this used to be a CSP strict-dynamic bypass vector), but I understand how it was useful back when the API was created (heck, I used it myself :) ).

    In my personal opinion .append(scriptElem) could be a good workaround, and domManip could stop special-casing script nodes, but there are backward compatibility issues that I don't know the full impact of.

  7. mgol commented on Oct 8, 2021

    @mgol
    MemberAuthor

    Yeah, I'd also love to take out all that script execution stuff, at least as a default, but this may be too big a compatibility break. We'll think if anything can be done to that more generic case.

    TBH it's quite weird that Web APIs don't behave like jQuery here natively; it was surprising to me when I first learnt appending script elements directly executes them but not when done via an HTML string or if they're not the top-level element.

  8. added 3 commits that reference this issue on Oct 29, 2021
    520f23a
    8497cd0
    2773427
  9. added a commit that references this issue on Nov 1, 2021
    4250b62
  10. changed the title [-]jQuery.attr: Don't stringify values as it breaks Trusted Types[/-] [+]Attributes: Don't stringify values as it breaks Trusted Types[/+] on Nov 1, 2021
  11. mgol commented on Nov 1, 2021

    @mgol
    MemberAuthor

    The fix has landed; I extracted the script execution issue to #4963.

  12. locked as resolved and limited conversation to collaborators on Sep 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions