React kept warning me about an invalid value for prop "inherit". Where the heck did this come from?

Recently I started up a new React project. The dev console kept showing these two warnings

Warning: Invalid value for prop `inherit` on <input> tag. Either remove it from the element, or pass a string or number value to keep it in the DOM. For details, see https://reactjs.org/link/attribute-behavior

and

Warning: Prop `className` did not match. Server: "border border-black bg-green-50 opacity-25" Client: "border border-black bg-green-50 opacity-25 inherit"

where is this "inherit" coming from? Google turned up absolutely nothing. I soon learned why.

Breaking inside React

I went down to node_modules/react-dom/cjs/react-dom.development.js and added a debugger statement just above this warning, and refreshed the page. I saw this

The debugger stopped right before React warns of the unexpected prop

but looking at the props object, I don't see inherit. Wait a minute ...

The inherit property on the object prototype

there it is. Ok, so how did an inherit function get onto the Object prototype?

Surprises from old JavaScript

This project I'm working on is using some "old" JavaScript, a library that was written about ten years ago. I dug into it and sure enough I found this

Object.prototype.inherit = function () {
    for (var in this) {
        this[v] = this[v];
    }
};

This library calls this method in order to pull properties off of the prototype directly onto the object instance. I'm not entirely sure why as on the surface it doesn't seem necessary. But to be safe, I kept this functionality in place.

The "fix"

To make the warning go away, I changed the above to this

Object.defineProperty(Object.prototype, 'inherit', {
    value: function () {
        for (var in this) {
            this[v] = this[v];
        }
    },
    enumerable: false,
});

This lets the library keep using the function, and adding enumerable: false means React no longer stumbles upon it.

Of course a better fix is to leave built-in prototypes alone. Ahhh the good ol' days of wild west JavaScript. But for now, this works. I have a feeling I will be taking this library and updating it to current JS at some point, and I'll get rid of this function when I do that.

So there ya go, prototype pollution can rear its head in strange ways :)