The various Trusted* interfaces (e.g. TrustedScript) are objects that contain a string that is marked as trusted. Then using these objects in place of strings, e.g. in eval(), or in .innerHTML, the browser needs to look at what is this internal string and use it instead of the object.
All of them also have a .toString() method on the prototype, which returns the trusted string.
.toString() however can be replaced/shadowed, either by replacing the one on the prototype or by defining an own .toString property on one of the instances themselves:
const trustedScript = policy.createScript(`return "hi!"`);
trustedScript.toString = () => `return "bad code!"`;
This can cause problems in code that assumes that a trusted object's stringified version is the trusted string, both in userland and potentially in browser implementations that might try to implement some optimizations on trusted types.
To avoid potential security issues, we can make it so that one cannot tamper with the .toString() behavior of this object, bye making .toString() an own (so, non-shadowable) non-writable non-configurable property. Effectively, a TrustedHTML becomes something like
class TrustedHTML {
constructor(data) { // the constructor is not actually exposed to users
this.#data = data;
Object.defineProperty(this, "toString", {
value: TrustedHTML.#originalToString,
enumerable: false,
writable: false,
configurable: false,
});
}
toString() {
return this.#data;
}
toJSON() {
return this.#data;
}
static #originalToString = TrustedHTML.prototype.toString;
}
and maybe do the same for .toJSON().
The various
Trusted*interfaces (e.g.TrustedScript) are objects that contain a string that is marked as trusted. Then using these objects in place of strings, e.g. ineval(), or in.innerHTML, the browser needs to look at what is this internal string and use it instead of the object.All of them also have a
.toString()method on the prototype, which returns the trusted string..toString()however can be replaced/shadowed, either by replacing the one on the prototype or by defining an own.toStringproperty on one of the instances themselves:This can cause problems in code that assumes that a trusted object's stringified version is the trusted string, both in userland and potentially in browser implementations that might try to implement some optimizations on trusted types.
To avoid potential security issues, we can make it so that one cannot tamper with the
.toString()behavior of this object, bye making.toString()an own (so, non-shadowable) non-writable non-configurable property. Effectively, aTrustedHTMLbecomes something likeand maybe do the same for
.toJSON().