VYPR
High severityNVD Advisory· Published Aug 5, 2025· Updated Aug 5, 2025

js-toml is vulnerable to Prototype Pollution

CVE-2025-54803

Description

js-toml is a TOML parser for JavaScript, fully compliant with the TOML 1.0.0 Spec. In versions below 1.0.2, a prototype pollution vulnerability in js-toml allows a remote attacker to add or modify properties of the global Object.prototype by parsing a maliciously crafted TOML input. This is fixed in version 1.0.2.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
js-tomlnpm
< 1.0.21.0.2

Affected products

1

Patches

1
b125910a3f09

fix: address prototype pollution vulnerability (CWE-1321)

https://github.com/sunnyadn/js-tomlSunny YangAug 3, 2025via ghsa
3 files changed · +148 6
  • package.json+1 1 modified
    @@ -1,6 +1,6 @@
     {
       "name": "js-toml",
    -  "version": "1.0.1",
    +  "version": "1.0.2",
       "description": "A TOML parser for JavaScript/TypeScript, targeting TOML 1.0.0 Spec",
       "keywords": [
         "toml",
    
  • src/load/interpreter.ts+10 5 modified
    @@ -7,7 +7,11 @@ import { Float } from './tokens/Float.js';
     import { DateTime } from './tokens/DateTime.js';
     import { Integer } from './tokens/Integer.js';
     
    -const isPlainObject = (obj): boolean => obj && obj.constructor === Object;
    +const isPlainObject = (obj): boolean =>
    +  obj && (obj.constructor === Object || obj.constructor === undefined);
    +
    +// Create a safe object without prototype pollution vulnerability
    +const createSafeObject = () => Object.create(null);
     
     const tryCreateKey = (operation, message) => {
       try {
    @@ -35,7 +39,7 @@ export class Interpreter extends BaseCstVisitor {
       }
     
       toml(ctx) {
    -    const root = {};
    +    const root = createSafeObject();
         let current = root;
         ctx.expression?.forEach(
           (expression) => (current = this.visit(expression, { current, root }))
    @@ -82,7 +86,8 @@ export class Interpreter extends BaseCstVisitor {
       }
     
       inlineTable(ctx) {
    -    const result = { [notEditable]: true };
    +    const result = createSafeObject();
    +    result[notEditable] = true;
         if (ctx.inlineTableKeyValues) {
           this.visit(ctx.inlineTableKeyValues, result);
         }
    @@ -141,7 +146,7 @@ export class Interpreter extends BaseCstVisitor {
               throw new DuplicateKeyError();
             }
     
    -        const object = {};
    +        const object = createSafeObject();
             array.push(object);
             return object;
           },
    @@ -205,7 +210,7 @@ export class Interpreter extends BaseCstVisitor {
             throw new DuplicateKeyError();
           }
         } else {
    -      object[key] = {};
    +      object[key] = createSafeObject();
           if (declareSymbol) {
             object[key][declareSymbol] = true;
           }
    
  • test/security.ts+137 0 added
    @@ -0,0 +1,137 @@
    +import { describe, it, expect } from 'vitest';
    +import { load } from '../src/index.js';
    +
    +describe('Security', () => {
    +  describe('Prototype Pollution Prevention', () => {
    +    it('should not allow __proto__ pollution', () => {
    +      const toml = `
    +[__proto__]
    +polluted = true
    +`;
    +
    +      const result = load(toml);
    +
    +      const testObj = {};
    +      expect('polluted' in testObj).toBe(false);
    +      expect('polluted' in Object.prototype).toBe(false);
    +
    +      expect(result).toHaveProperty('__proto__');
    +      expect(result['__proto__']).toHaveProperty('polluted', true);
    +    });
    +
    +    it('should not allow constructor pollution', () => {
    +      const toml = `
    +[constructor]
    +[constructor.prototype]
    +polluted = true
    +`;
    +
    +      const result = load(toml);
    +
    +      const testObj = {};
    +      expect('polluted' in testObj).toBe(false);
    +      expect('polluted' in Object.prototype).toBe(false);
    +
    +      expect(result).toHaveProperty('constructor');
    +    });
    +
    +    it('should reproduce the authentication bypass scenario', () => {
    +      const toml = `
    +[__proto__]
    +isAdmin = true
    +`;
    +
    +      // Simulate the vulnerable authentication function
    +      const isAdmin = (user: Record<string, unknown>) => {
    +        return user.isAdmin === true;
    +      };
    +
    +      // Parse the malicious TOML
    +      load(toml);
    +
    +      // Create a user object that should not be admin
    +      const user = { username: 'foo' };
    +
    +      // This should return false (user is not admin)
    +      // If prototype pollution occurred, this would return true
    +      expect(isAdmin(user)).toBe(false);
    +      expect('isAdmin' in user).toBe(false);
    +    });
    +
    +    it('should handle dotted __proto__ keys safely', () => {
    +      const toml = `
    +[table.__proto__]
    +polluted = true
    +`;
    +
    +      const result = load(toml);
    +
    +      const testObj = {};
    +      expect('polluted' in testObj).toBe(false);
    +      expect('polluted' in Object.prototype).toBe(false);
    +
    +      expect('table' in result).toBe(true);
    +      expect('__proto__' in result['table']).toBe(true);
    +    });
    +
    +    it('should handle inline table __proto__ safely', () => {
    +      const toml = `
    +obj = { __proto__ = { polluted = true } }
    +`;
    +
    +      const result = load(toml);
    +
    +      const testObj = {};
    +      expect('polluted' in testObj).toBe(false);
    +      expect('polluted' in Object.prototype).toBe(false);
    +
    +      expect(result).toHaveProperty('obj');
    +    });
    +  });
    +
    +  it('should not allow pollution via array of tables syntax', () => {
    +    const toml = `
    +[[__proto__]]
    +polluted = true
    +`;
    +    const result = load(toml);
    +
    +    expect('polluted' in Object.prototype).toBe(false);
    +    expect('polluted' in Array.prototype).toBe(false);
    +
    +    expect(result).toHaveProperty('__proto__');
    +    expect(Array.isArray(result['__proto__'])).toBe(true);
    +    expect(result['__proto__'][0]).toEqual({ polluted: true });
    +  });
    +
    +  it('should handle deeply nested __proto__ keys safely', () => {
    +    const toml = `
    +[a.b.__proto__.c]
    +polluted = true
    +`;
    +    const result = load(toml);
    +
    +    const testObj = {};
    +    expect('polluted' in testObj).toBe(false);
    +
    +    const resultObj = result as Record<
    +      string,
    +      Record<string, Record<string, Record<string, unknown>>>
    +    >;
    +    expect(resultObj.a.b['__proto__'].c).toEqual({ polluted: true });
    +  });
    +
    +  it('should treat "prototype" as a regular key', () => {
    +    const toml = `
    +[prototype]
    +polluted = true
    +`;
    +    const result = load(toml);
    +
    +    const testObj = {};
    +    expect('polluted' in testObj).toBe(false);
    +
    +    expect(result).toHaveProperty('prototype');
    +    expect(result['prototype']).toEqual({ polluted: true });
    +  });
    +});
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

5

News mentions

0

No linked articles in our index yet.