Overwriting Built-In Globals
ID |
javascript.overwriting_builtins |
Severity |
high |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
JavaScript |
Tags |
best-practice, reliability |
Description
Reports plain assignments whose left-hand side is a built-in global identifier — Object, Array, Math, JSON, Promise, console, window, document, navigator, process, and friends. Such an assignment either overwrites the binding (when the surrounding scope is the global one and there is no shadowing declaration), masking the original from the rest of the program, or implicitly creates a global of the same name in non-strict code. Both outcomes are almost always typos or forgotten debug code rather than intentional behaviour.
Property assignments such as Math.foo = … are out of scope. If the identifier resolves to a local declaration in scope (the user deliberately shadowed the builtin elsewhere) the rule does not fire — the assignment then targets the local copy, which is a different concern.
Rationale
// Bad — silently replaces the global, breaking every later caller.
Math = null;
Object = function () {};
console = { log: () => {} };
JSON = { parse: () => null };
Once Math no longer points at the standard object, Math.PI, Math.max(…), and any third-party library that relies on it, all break. The failure mode is non-obvious: errors surface deep inside library code that the author never touched, with no indication that the global was mutated.
Remediation
Pick a different name, or — if the intent is to mock or stub — explicitly stub a property on the original instead of replacing the binding:
// Good — different name, no clash.
const myMath = { PI: 3.14159 };
// Good — stubbing a property leaves the rest of the global intact.
const realLog = console.log;
console.log = (...args) => realLog("[test]", ...args);
// later: console.log = realLog;
// Good — local shadow stays inside its function.
function withFakeFetch() {
const fetch = () => Promise.resolve({ json: () => ({}) });
return fetch();
}
For test stubs, prefer a dedicated mocking library (Jest’s jest.spyOn, Sinon, etc.) over reassigning globals: those track and restore the original on teardown, which a bare assignment does not.