secure-json-parse

repository·main·Indexed 42 days ago

https://github.com/fastify/secure-json-parse

A security-focused drop-in replacement for JSON.parse() version 4.1.0 designed to prevent prototype poisoning attacks. It detects and handles dangerous keys like __proto__ and constructor.prototype via sjson.parse(), sjson.scan(), and safeParse() to protect against prototype pollution.

Tokens
1.9K
Snippets
7
Records
8
Agent score
4%

What's inside secure-json-parse

  1. Use sjson.parse() to prevent prototype poisoning

    main

    Use sjson.parse(text, [reviver], [options]) to parse JSON strings safely. Unlike standard JSON.parse(), this method can be configured to throw an error, remove, or ignore dangerous keys like __proto__ and constructor.prototype that could lead to prototype pollution when objects are merged or copied.

    const sjson = require('secure-json-parse')
    
    const goodJson = '{ "a": 5, "b": 6 }'
    const badJson = '{ "a": 5, "b": 6, "__proto__": { "x": 7 }, "constructor": {"prototype": {"bar": "baz"} } }'
    
    // Standard JSON.parse will retain the dangerous keys
    console.log(JSON.parse(goodJson), sjson.parse(goodJson, undefined, { protoAction: 'remove', constructorAction: 'remove' }))
    
    // sjson.parse with 'remove' action will strip the dangerous keys
    console.log(JSON.parse(badJson), sjson.parse(badJson, undefined, { protoAction: 'remove', constructorAction: 'remove' }))
  2. Scan an existing object with sjson.scan()

    main

    Use sjson.scan(obj, [options]) to inspect an already existing object for dangerous prototype properties. This is useful for validating objects that were not created via sjson.parse().

    Available options:

    • protoAction: 'error' (default), 'remove', or 'ignore' for __proto__ keys.
    • constructorAction: 'error' (default), 'remove', or 'ignore' for constructor.prototype keys.
    • safe: Boolean (default false). If true, returns null instead of throwing when a forbidden property is found.
  3. Configure prototype protection via `parse` options

    main

    When calling parse(text, reviver, options), you can provide an options object to control the behavior when forbidden properties are encountered.

    Available options:

    • protoAction: Action to take when __proto__ is found. Options: 'error' (default), 'remove', or 'ignore'.
    • constructorAction: Action to take when constructor is found. Options: 'error' (default), 'remove', or 'ignore'.
    • safe: Boolean. If true, instead of throwing an error or removing keys, the function returns null if any security issues are detected.
    const sjson = require('secure-json-parse');
    const json = '{"__proto__": {"a": 1}}';
    
    // Remove the forbidden property instead of throwing
    const obj = sjson(json, null, { protoAction: 'remove', constructorAction: 'remove' });
    // obj is now {}
    
    // Ignore the property entirely
    const objIgnore = sjson(json, null, { protoAction: 'ignore', constructorAction: 'ignore' });
    // objIgnore is { '__proto__': { 'a': 1 } }
  4. Configure sjson.parse() options

    main

    The options object for sjson.parse(text, [reviver], [options]) allows you to define how the parser handles prototype-related keys:

    • protoAction: Action for __proto__ keys.
      • 'error' (default): Throws a SyntaxError.
      • 'remove': Deletes the __proto__ keys from the resulting object.
      • 'ignore': Skips validation (behaves like JSON.parse()).
    • constructorAction: Action for constructor.prototype keys.
      • 'error' (default): Throws a SyntaxError.
      • 'remove': Deletes the constructor keys from the resulting object.
      • 'ignore': Skips validation (behaves like JSON.parse()).
    • safe: Boolean (default false).
      • true: Returns null instead of throwing an error when a forbidden property is found.
    // Example of using the 'safe' option to return null instead of throwing
    sjson.parse(badJson, undefined, { 
      protoAction: 'error', 
      safe: true 
    }); // returns null
  5. Use `safeParse()` for non-throwing parsing

    main

    The safeParse(text, reviver) function is a convenience wrapper for parsing JSON without throwing exceptions. It uses the safe: true option internally.

    • If security issues (like forbidden prototype properties) are found, it returns null.
    • If the JSON is malformed (syntax error), it returns undefined.
    • Otherwise, it returns the parsed object.
    const sjson = require('secure-json-parse');
    
    // Malformed JSON
    const malformed = sjson('{"a": 1'); 
    // returns undefined
    
    // Prototype poisoning attempt
    const poisoned = sjson('{"__proto__": {"a": 1}}');
    // returns null
    
    // Valid JSON
    const valid = sjson('{"a": 1}');
    // returns { a: 1 }
  6. Scan and filter objects with `scan()`

    main

    The scan(obj, options) function (exported as module.exports.scan) allows you to manually inspect and clean an existing JavaScript object for forbidden prototype properties. It performs a deep scan of the object and its nested properties.

    const sjson = require('secure-json-parse');
    
    const dirtyObj = {
      a: 1,
      b: {
        __proto__: { polluted: true }
      }
    };
    
    // Remove forbidden properties deep in the object
    const cleanObj = sjson.scan(dirtyObj, { protoAction: 'remove', constructorAction: 'remove' });
    // cleanObj is { a: 1, b: {} }
  7. Parse JSON securely with `parse()`

    main

    The parse function parses JSON text (string or Buffer) while protecting against prototype poisoning attacks. It checks for forbidden properties like __proto__ and constructor.

    By default, if a forbidden property is detected, it throws a SyntaxError. You can configure how these properties are handled using the options object.

    const sjson = require('secure-json-parse');
    
    const json = '{"name": "foo", "__proto__": {"polluted": true}}';
    
    // Default behavior: throws SyntaxError
    try {
      const obj = sjson(json);
    } catch (err) {
      console.error(err.message); // "Object contains forbidden prototype property"
    }