Mar 3, 2026·6 min read·26 visits
Running maintenance commands like `openclaw doctor` or `update` silently replaces secure environment variable placeholders (e.g., `${KEY}`) in your config file with the actual cleartext secret values, permanently writing them to disk.
A critical information disclosure vulnerability exists in the OpenClaw AI assistant's configuration management subsystem. When processing configuration files that utilize environment variable interpolation (e.g., `${API_KEY}`), certain write operations—such as updates or repairs—inadvertently resolve these references to their runtime values and persist the cleartext secrets back to the disk. This effectively converts ephemeral, secure configuration references into permanent, plaintext credentials stored within `openclaw.json`, significantly increasing the risk of accidental secret leakage via version control or backup mechanisms.
The OpenClaw personal AI assistant supports a security best practice known as configuration interpolation, allowing users to reference environment variables in their openclaw.json file using the syntax ${VAR_NAME}. This ensures that sensitive secrets, such as LLM provider API keys (OpenAI, Anthropic) or bot tokens, remain in memory or environment files and are never written to static configuration storage.
However, a regression in the configuration I/O logic breaks this security model. When the application performs operations that require reading, modifying, and saving the configuration—specifically during automated updates, interactive configuration (openclaw configure), or self-healing routines (openclaw doctor --fix)—it fails to distinguish between the resolved runtime value and the original configuration source.
Consequently, the application overwrites the user's secure configuration file with the resolved in-memory state. A placeholder like ${OPENAI_API_KEY}, which is safe to check into version control, is replaced by the actual alphanumeric secret key sk-proj-..., which is strictly confidential. This transformation happens silently, often without the user's knowledge, until the file is inspected or inadvertently committed to a public repository.
The vulnerability resides in the configuration serialization pipeline located in src/config/config-io.ts. The root cause is a lack of separation between the canonical configuration (what is stored on disk) and the effective configuration (what is used in memory).
When OpenClaw initializes, it invokes a loader that parses the JSON file and immediately passes it through a resolution function, resolveConfigEnvVars. This function recursively walks the object tree and substitutes any string matching the pattern ${...} with the corresponding value from process.env. The resulting object is used by the application for all logic.
The critical flaw occurs in the writeConfigFile function. This function accepts the current configuration object state to save changes to disk. Because the application only maintains the resolved state in memory without keeping a reference to the original raw state or a map of interpolated fields, JSON.stringify serializes the actual secret values. The serialization logic assumes that the current value of a field is the desired persistent value, ignoring the fact that the value originated from an ephemeral environment source.
The following pseudo-code illustrates the logic flow responsible for the vulnerability. The application loads the config, interpolates it immediately, and then writes that interpolated version back to disk during updates.
src/config/config-io.ts)// LOAD: Reads JSON and immediately destroys the reference to "${VAR}"
function loadConfig() {
const raw = fs.readFileSync('openclaw.json', 'utf8');
const config = JSON.parse(raw);
// Vulnerability: Original formatting is lost here
return resolveEnvVars(config);
}
// SAVE: Writes the resolved values (secrets) to disk
function saveConfig(updatedConfig) {
// Vulnerability: Writes "sk-12345..." instead of "${API_KEY}"
const output = JSON.stringify(updatedConfig, null, 2);
fs.writeFileSync('openclaw.json', output);
}The fix, introduced in PR #4900, implements a mechanism to preserve the original interpolation syntax. It likely involves tracking which fields contained variables or performing a reverse-lookup against the original raw configuration before saving.
function saveConfig(updatedConfig, originalRawConfig) {
const outputConfig = clone(updatedConfig);
// FIX: Restore ${VAR} references for fields that haven't changed logically
for (const key of Object.keys(originalRawConfig)) {
if (isInterpolated(originalRawConfig[key])) {
// Revert the resolved value back to the placeholder
outputConfig[key] = originalRawConfig[key];
}
}
fs.writeFileSync('openclaw.json', JSON.stringify(outputConfig, null, 2));
}Exploitation of this vulnerability is trivial and often accidental, triggered by standard maintenance commands. An attacker with local access could trigger this to persist ephemeral secrets, or a user could trigger it unknowingly.
Reproduction Steps:
Setup: Create an openclaw.json file utilizing environment variable interpolation for a sensitive field.
{
"llm": {
"provider": "anthropic",
"apiKey": "${ANTHROPIC_API_KEY}"
}
}Environment: Export the corresponding secret in the current shell.
export ANTHROPIC_API_KEY="sk-ant-api03-sensitive-secret-value"Trigger: Execute a command that modifies configuration. The doctor command with the --fix flag is a reliable trigger as it attempts to normalize the configuration structure.
openclaw doctor --fixVerification: Inspect the file content. The placeholder is gone, replaced by the plaintext secret.
cat openclaw.json
# Output: "apiKey": "sk-ant-api03-sensitive-secret-value"The primary impact of this vulnerability is the Unintentional Exposure of Sensitive Information (CWE-200) and Cleartext Storage of Sensitive Information (CWE-312). While the vulnerability requires local execution to trigger, the downstream effects can be severe in DevOps and collaborative environments.
git commit -am "update config"), they may unknowingly push live production credentials to a shared or public repository.Users must upgrade OpenClaw immediately to prevent further exposure. If you have run any maintenance commands on affected versions, your secrets may already be exposed on disk.
Immediate Steps:
v2026.2.7 or later. This version includes the fix from PR #4900 which correctly handles environment variable preservation.grep -r "sk-" openclaw.json or manually inspect your configuration file to verify no cleartext secrets are present.${VAR} syntax manually.Long-term Hardening:
Ensure that openclaw.json is added to your .gitignore file if it contains any specific local configuration, or strictly use separate environment files (e.g., .env) that are never tracked.
CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
OpenClaw OpenClaw | <= v2026.2.6-3 | v2026.2.7 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-312 |
| Vulnerability Type | Information Disclosure |
| Attack Vector | Local / File System |
| Impact | Confidentiality Loss |
| Affected Component | Config I/O (openclaw.json) |
| CVSS Score | 7.4 (High) |
The application stores sensitive information in cleartext within a resource that might be accessible to another control sphere.
A module allowlist bypass vulnerability (CVE-2026-92945 / GHSA-7q3f-wx44-378m) was identified in the vm2 sandboxing library prior to version 3.11.7. This flaw permits unauthenticated or untrusted code running within the sandbox environment to bypass explicit module restrictions. When the transitive resolution option is disabled, the system fails to validate file system path boundaries, allowing prefix-sharing sibling directories to be resolved and loaded, thereby escaping intended sandbox restrictions.
CVE-2026-92941 is a critical sandbox-escape and trust-manipulation vulnerability in the vm2 library (versions 3.11.3 to 3.11.6). This security flaw allows untrusted code executing within a NodeVM sandbox environment to compromise the global TLS trust store of the host Node.js process. By leveraging a design flaw where the host's native 'tls.setDefaultCACertificates' can be executed via a proxy wrapper, combined with a bridge unwrapping bypass in the 'url' module, an attacker can modify the process-wide default root Certificate Authorities. Consequently, all subsequent outbound TLS/HTTPS clients running on the host thread are forced to trust attacker-signed certificates, facilitating transparent Man-in-the-Middle (MitM) attacks. The vulnerability was resolved in version 3.11.7 of vm2 by introducing built-in member-level sanitization before applying read-only proxy wrappers.
A critical engine-level reachability failure in Node.js 26 running V8 14.6 allows attackers to escape the vm2 sandbox environment. When consecutive prototype properties are modified using sequential assignments, a V8 optimization bug fails to invalidate the PromiseThenLookupChain protector. By calling Promise.prototype.finally, the attacker bypasses the vm2 wrappers, hijacks the promise reaction using a custom constructor, triggers a calibrated stack overflow to capture a host-realm RangeError, and executes arbitrary shell commands on the host.
A critical sandbox escape vulnerability in the vm2 library allows sandboxed JavaScript code to bypass containment and execute arbitrary native code on the host process. This occurs when the host's builtin crypto module is exposed to the NodeVM environment. Although vm2 implements a read-only proxy layer to restrict direct modifications to host properties, it does not prevent invocation of host-level functions. By calling the crypto.setEngine API with a path to a malicious native library on disk, an attacker can trigger OpenSSL's dynamic module loader. The host's operating system loader immediately runs the dynamic library's initializers/constructors before verifying engine compatibility, leading to remote code execution in the context of the host process.
CVE-2026-92938 is a critical sandbox escape vulnerability in the vm2 library (versions 3.11.3 through 3.11.6) that allows arbitrary native code execution on the host when the node:sqlite built-in module is loaded inside a sandboxed NodeVM environment.
CVE-2026-92937 is a critical sandbox escape vulnerability in the `vm2` Node.js library. Due to a logical failure in checking direct invocation targets inside the Proxy bridge, an attacker can register Promise callbacks using `Function.prototype.call` or `Function.prototype.apply` indirection. This bypasses the error sanitization wrappers, delivering raw host error objects directly to sandboxed callbacks and allowing the attacker to escape the sandbox and execute arbitrary shell commands on the host.