FRAMESCAN
← Blog

protobufjs: DoS in .proto option parsing and prototype mutation fixed in 7.6.5/8.6.5/8.6.6

FrameScan · 2026-07-22

TL;DR

At-a-glance

ID (official advisory) Plain-English impact Severity Affected versions Fixed version
protobufjs < 7.6.5 — DoS in .proto option parsing Crafted .proto can hang parsing medium < 7.6.5 7.6.5
protobufjs < 8.6.5 — Text format string map parsing prototype mutation Map prototype can be mutated medium < 8.6.5 8.6.5
protobufjs < 8.6.6 — DoS in .proto option parsing Crafted .proto can hang parsing medium < 8.6.6 8.6.6

Details and guidance

protobufjs < 7.6.5 — Denial of Service via infinite loop in .proto option parsing

An attacker who can influence .proto definitions or options could trigger an infinite loop during parsing. The result is that your process can hang and stop handling requests, causing a denial of service. Medium severity means treat it seriously, especially in any workflow that processes external or untrusted .proto files.

Technical details

The issue involves an infinite loop when parsing option constructs inside .proto files. A robust parser must advance input state on every iteration and bail out on malformed sequences.

Illustrative example — not protobufjs source:

// Vulnerable pattern (illustrative): loop may not advance on malformed input
function parseOptions(tokens) {
  let i = 0;
  const options = {};
  while (i < tokens.length) {
    const t = tokens[i];
    if (t.type === 'OPTION_START') {
      // BUG: on unexpected token, neither i++ nor return occurs -> infinite loop
      if (!tokens[i + 1] || tokens[i + 1].type !== 'IDENT') {
        continue; // i is unchanged -> potential infinite loop
      }
      options[tokens[i + 1].value] = true;
      i += 2;
    } else {
      i++;
    }
  }
  return options;
}

// Fixed pattern (illustrative): always advance or fail fast with a limit
function parseOptionsSafe(tokens, maxTokens = 100000) {
  let i = 0;
  let steps = 0;
  const options = {};
  while (i < tokens.length) {
    if (++steps > maxTokens) throw new Error('Option parsing limit exceeded');
    const t = tokens[i];
    if (t.type === 'OPTION_START') {
      const ident = tokens[i + 1];
      if (!ident || ident.type !== 'IDENT') {
        i++; // ensure progress on malformed input
        continue;
      }
      options[ident.value] = true;
      i += 2; // progress guaranteed
    } else {
      i++;
    }
  }
  return options;
}

protobufjs < 8.6.5 — Text Format string map parsing can mutate returned map object prototype

When parsing text-format string maps, a caller could receive an object whose prototype is unexpectedly mutable. That can lead to surprising behavior, property shadowing, or unsafe assumptions in downstream code. Treat this as a data integrity and safety fix.

Technical details

Map-like results should not inherit from Object.prototype when keys may come from untrusted input. Returning a plain object can allow prototype fields to be set or influenced via special keys.

Illustrative example — not protobufjs source:

// Vulnerable pattern (illustrative): map inherits from Object.prototype
function parseStringMap(pairs) {
  const map = {}; // inherits prototype
  for (const [k, v] of pairs) {
    map[String(k)] = String(v);
  }
  return map; // prototype can be mutated elsewhere
}

// Fixed pattern (illustrative): create a null-prototype object and freeze prototype
function parseStringMapSafe(pairs) {
  const map = Object.create(null); // no inherited props
  for (const [k, v] of pairs) {
    map[String(k)] = String(v);
  }
  return map;
}

protobufjs < 8.6.6 — Denial of Service via infinite loop in .proto option parsing

A second parser hardening fix for v8 ensures crafted .proto options cannot cause the process to spin indefinitely. Services that compile or load .proto files at runtime should prioritize this update to avoid request starvation or job stalls.

Technical details

As with the v7 issue, safe parsers must guarantee forward progress and enforce iteration limits.

Illustrative example — not protobufjs source:

function parseOptionsHardened(tokens) {
  let i = 0;
  const options = {};
  const maxSteps = Math.max(1000, tokens.length * 10);
  for (let steps = 0; i < tokens.length; steps++) {
    if (steps > maxSteps) throw new Error('Parsing aborted: limit exceeded');
    const t = tokens[i];
    if (t.type !== 'OPTION_START') {
      i++;
      continue;
    }
    const ident = tokens[i + 1];
    if (!ident || ident.type !== 'IDENT') {
      i++; // ensure forward progress on malformed input
      continue;
    }
    options[ident.value] = true;
    i += 2;
  }
  return options;
}

Remediation

Official security-release reference: [MISSING: advisory link]

Call to action

Is your site exposed? Scan it for $1