JavaScript's hasOwnProperty Shadowing Trap: The Method That Isn't a Method When You Need It Most

2026-08-17

A REST endpoint rejects empty payloads before writing to the database:

function isNotEmpty(obj) {
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) return true;
    }
    return false;
}

app.post('/api/user', (req, res) => {
    const data = req.body;                       // parsed JSON
    if (!isNotEmpty(data)) {
        return res.status(400).json({ error: 'empty body' });
    }
    db.insert('users', data);
    res.json({ status: 'ok' });
});

For months it runs fine. Then a fuzzer POSTs {"name":"eve","hasOwnProperty":42} and the route returns 500: TypeError: obj.hasOwnProperty is not a function.

The Bug

hasOwnProperty is not a language keyword; it is a plain method inherited from Object.prototype. Any own property with the same name shadows it. When the payload contains a hasOwnProperty key whose value is a number, string, or null, obj.hasOwnProperty resolves to that value — and calling it throws.

The MDN docs warn about this, but the for...in + hasOwnProperty pattern is so ingrained that people type it reflexively — the same shape lives in old versions of jQuery, in Stack Overflow's most-upvoted answers, and in ESLint's own recommendation from years past.

Three failure modes are worth naming:

The Fix

Reach for the method through the prototype, or use Object.hasOwn (Node 16.9+, ES2022):

function isNotEmpty(obj) {
    for (const key in obj) {
        if (Object.hasOwn(obj, key)) return true;
    }
    return false;
}

Pre-Object.hasOwn, the canonical safe form is:

const hasOwn = Object.prototype.hasOwnProperty;
function isNotEmpty(obj) {
    for (const key in obj) {
        if (hasOwn.call(obj, key)) return true;
    }
    return false;
}

Both bypass the instance lookup, and Object.hasOwn(obj, k) reads honestly — "does obj have its own k?" — instead of "please call obj's inherited method on itself, assuming nobody has overridden it."

If you don't need to consider inherited properties (almost always true for parsed JSON), skip for...in entirely. Object.keys(obj).length > 0 gives you the check in one line: Object.keys returns only own enumerable string keys and cannot be shadowed by data properties on the object itself.

Key Takeaway: Any method inherited from Object.prototype is a data-driven landmine when the data is untrusted JSON — use Object.hasOwn(obj, key) or Object.prototype.hasOwnProperty.call(obj, key) instead of obj.hasOwnProperty(key).

All newsletters