Skip to content

Security: special keys (toString/hasOwnProperty/constructor) pollute global process.env #28

Description

@Nick-730

Security: special keys (toString/hasOwnProperty/constructor) pollute global process.env

Package: dotenv-parse-variables@2.0.0
Severity: High (process-wide Denial of Service)
Type: Special key handling — writes unfiltered keys into global process.env

Summary

dotenv-parse-variables parses keys from an env object and, by default (assignToProcessEnv: true), writes them back into the global process.env without filtering special keys. An .env file (or any env object) containing keys like toString, valueOf, hasOwnProperty, or constructor overwrites those built-in methods on the global process.env object with string values — affecting the entire process, not just the returned object.

Location

lib/index.js:32 and lib/index.js:35-41:

parsed[key] = parseKey(env[key], key);            // line 32 — no key filter

if (envOptions.assignToProcessEnv === true) {     // line 35 — default true
    if (envOptions.overrideProcessEnv === true) {
        process.env[key] = parsed[key] || process.env[key];   // line 37
    } else {
        process.env[key] = process.env[key] || parsed[key];   // line 39
    }
}

Proof of concept

const parse = require('dotenv-parse-variables');

// Before: process.env methods intact
console.log(typeof process.env.toString);        // "function"

// Parse a poisoned env object (e.g. loaded from an attacker-influenced .env)
parse({
  APP_NAME: 'MyApp',
  toString: 'EVIL',
  hasOwnProperty: 'nope',
  constructor: 'evil',
});

// After: global process.env methods are now strings
console.log(typeof process.env.toString);        // "string"  ← overwritten
console.log(typeof process.env.hasOwnProperty);  // "string"  ← overwritten
console.log(typeof process.env.constructor);     // "string"  ← overwritten

// Any code relying on process.env's built-in methods now crashes:
// `'ENV: ' + process.env`  →  TypeError: Cannot convert object to primitive value

Impact

  • Process-wide DoS: any code that stringifies process.env (logging, error reporting, serialization) or calls process.env.hasOwnProperty() (config checks) throws after a poisoned .env is loaded.
  • Logic corruption: constructor overwrite can break instanceof-style checks and object construction paths in libraries that walk process.env.
  • Unlike a prototype-pollution-to-RCE, this does not escalate to code execution, but the blast radius (global shared object) is much wider than the returned-object-only case seen in other .env parsers (env-file-parser, @tokey/env-file-parser, envfile — all have the same unfiltered-key assignment, but only this package writes to global process.env by default).

Suggested fix

const DANGEROUS_KEYS = new Set([
  '__proto__', 'constructor', 'prototype',
  'toString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
]);

// in the loop:
if (DANGEROUS_KEYS.has(key)) continue;

Note: process.env is not a plain object in Node (it's a special object), but process.env[key] = value for toString/hasOwnProperty/constructor still shadows the inherited methods process-wide.

Related

  • Same class of issue (unfiltered keys, returned-object only) in:
    • env-file-parser@1.0.0lib/parse.js:32
    • @tokey/env-file-parser@2.0.0env-parser.js:183
    • envfile@7.1.0result[key] = value
  • Attack surface: .env content influenced via shared config templates, CI injection, or supply-chain (dependency writing .env at install).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions