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.