diff --git a/lib/plugins/system/meta/HTMLMetaHandler.js b/lib/plugins/system/meta/HTMLMetaHandler.js index fd467538b..e64f6fa1f 100644 --- a/lib/plugins/system/meta/HTMLMetaHandler.js +++ b/lib/plugins/system/meta/HTMLMetaHandler.js @@ -469,6 +469,12 @@ function merge(parentObj, props, value) { return; } + // Prototype pollution guard: never let attacker-controlled meta tag names + // (e.g. ) write into Object.prototype. + if (props.some(function(p) { return p === '__proto__' || p === 'constructor' || p === 'prototype'; })) { + return; + } + var currentNodeName = props[props.length - 1]; // Add 'url' to 'og:video'. And other same cases. diff --git a/lib/utils.js b/lib/utils.js index fd6f36706..dd3d58741 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1041,6 +1041,15 @@ export function unifyDate(date) { export function lowerCaseKeys(obj) { for (var k in obj) { + if (!Object.prototype.hasOwnProperty.call(obj, k)) { + // Skip inherited keys (e.g. from an already polluted prototype). + continue; + } + // Prototype pollution guard: never copy dangerous keys coming from + // attacker-controlled JSON (e.g. oembed `{"__proto__":{...}}`). + if (k === '__proto__' || k === 'constructor' || k === 'prototype') { + continue; + } var lowerCaseKey = k.toLowerCase(); if (lowerCaseKey != k) { obj[lowerCaseKey] = obj[k];