Skip to content

Define a non-writeable non-configurable own .toString() on the Trusted* objects #613

Description

@nicolo-ribaudo

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().

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions