xtermjs / xterm.js

A terminal for the web
https://xtermjs.org/
MIT License
17.46k stars 1.62k forks source link

Prototype pollution protection breaks decorator functionality #5131

Open holgerkoser opened 1 month ago

holgerkoser commented 1 month ago

I'm trying to implement protection against prototype pollution in my SinglePageApp that uses xterm.js. I'm using the following code at initialization:

[
  Object,
  Object.prototype,
  Function,
  Function.prototype,
  Array,
  Array.prototype,
  String,
  String.prototype,
  Number,
  Number.prototype,
  Boolean,
  Boolean.prototype,
].forEach(Object.freeze)

However, this causes an error when xterm.js tries to create a decorator:

TypeError: Cannot assign to read only property 'toString' of function 'function(e4, t3, n) {
            if (3 !== arguments.length) throw new Error("@IServiceName-decorator can only...<omitted>... }'
    at t2.createDecorator (@xterm_xterm.js?v=0e3f3914:5833:29)

The error seems to originate from this line in ServiceRegistry.ts: https://github.com/xtermjs/xterm.js/blob/master/src/common/services/ServiceRegistry.ts#L36 It appears that the decorator creation is trying to modify Function.prototype, which is no longer allowed due to the Object.freeze() call.

To reproduce the problem more simply:

Object.freeze(Function.prototype)
const decorator = function () {}
decorator.toString = () => 1

This returns the same error.

decorator.toString = () => 1
                   ^

TypeError: Cannot assign to read only property 'toString' of function 'function () {}'

Proposed solution: Instead of using toString to store the id, consider using a different property name (e.g., decorator._id = 1) or a Symbol. This would allow the decorator to function without modifying Function.prototype. Is it possible to implement the decorator functionality using one of these alternative approaches? This would allow users to implement stronger prototype pollution protections without breaking xterm.js functionality.

Tyriar commented 1 month ago

If the alternate works, sounds good to me.

holgerkoser commented 2 days ago

I would also like to add that freezing the constructors and prototypes after xterm.js is loaded is not an option for me. Since xterm.js is a relatively large library, I only want to load the code when a terminal window is actually opened by the user. In most cases, this doesn't happen, so it would be inefficient to include xterm.js in the initial bundle.