Skip to main content

Live Secret Synchronization

Modern cloud architectures frequently rotate secrets at runtime — such as fetching short-lived database tokens from HashiCorp Vault, AWS Secrets Manager, or handling OAuth token refreshes. Static analysis and tools that read environment variables only once at process startup miss these rotated credentials.

The Thread Isolation Problem

Node.js ESM customization hooks execute inside an isolated Worker Thread (the loader thread), separate from the main application thread where your code runs:
  • Startup State: At startup, process.env is serialized and passed to the child process.
  • The Isolation Barrier: Any subsequent mutations in the application thread (e.g. process.env.NEW_KEY = "token") do not automatically sync across thread boundaries to the loader thread.

The Solution: Proxy + MessageChannel

envtrap solves this using a two-way synchronization bridge:
1

MessagePort Transfer During Initialization

When hooks.mjs initializes, a Node.js MessageChannel is created. port2 is transferred to the loader thread via module.register():
The loader thread’s initialize() hook receives the port and registers a message listener.
2

process.env Proxy in Main Thread

In the application thread, process.env is wrapped in a JavaScript Proxy. Whenever a property is set or modified:
The proxy traps the assignment, tests the value against the candidate secret gate (looksLikeSecret), and registers it in the local secret registry.
3

Instant Broadcast to the Loader Thread

When a valid secret candidate is identified, the main thread posts a message across port1:
The loader thread updates its internal matching tables instantly.
Both port1 and port2 invoke .unref() so the internal synchronization channels never prevent the Node.js event loop from exiting naturally.