CVE-2025-12489 Overview
CVE-2025-12489 is a command injection vulnerability in the openBrowser function of evernote-mcp-server, a Model Context Protocol (MCP) server that integrates Evernote with AI assistants. The flaw stems from unsanitized user-supplied input being passed to a system call. A local attacker with the ability to execute low-privileged code can leverage the issue to run arbitrary commands in the context of the service account. The vulnerability was reported through the Zero Day Initiative program as ZDI-CAN-27913 and is tracked as [CWE-78] (OS Command Injection).
Critical Impact
Local attackers can escalate privileges and execute arbitrary code as the service account running evernote-mcp-server, compromising confidentiality, integrity, and availability of the host.
Affected Products
- evernote-mcp-server (brentmid/evernote-mcp-server) prior to the patched commit 1e66c78
- Deployments exposing the OAuth openBrowser authentication flow
- Host systems running the MCP server under a privileged service account
Discovery Timeline
- 2025-11-06 - CVE-2025-12489 published to the National Vulnerability Database
- 2026-06-17 - Last updated in NVD database
Technical Details for CVE-2025-12489
Vulnerability Analysis
The evernote-mcp-server project exposes an OAuth authorization workflow that launches the user's browser to complete authentication. The helper function openBrowser in auth.js constructs a shell command using a URL value derived from external input. Because the value is concatenated into the command string and executed through the shell, an attacker who can influence the URL parameter can inject additional shell metacharacters and commands.
Exploitation requires local, low-privileged code execution on the target host. Once triggered, the injected command executes in the context of the service account hosting the MCP server. This creates a privilege escalation path when the service runs with elevated permissions relative to the attacker's initial foothold.
Root Cause
The root cause is the use of child_process.exec to launch the browser. The exec API spawns a shell, so any unescaped shell metacharacters in the argument string are interpreted as commands. The function did not validate or sanitize the user-supplied string before passing it to exec, satisfying the conditions for [CWE-78] OS command injection.
Attack Vector
An attacker with local code execution invokes the OAuth flow in a manner that supplies a crafted URL containing shell metacharacters such as backticks, ;, &&, or $(). When openBrowser executes the command, the injected payload runs alongside the intended browser launch. Because the MCP server may run with different privileges than the invoking user, the attacker gains code execution in the service account context.
// Patch: replace exec with spawn in auth.js
const https = require('https');
const url = require('url');
const querystring = require('querystring');
-const { exec } = require('child_process');
+const { spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
// Source: https://github.com/brentmid/evernote-mcp-server/commit/1e66c78c4ce6ea294ac6b0eb289a9eae9c5e9579
The patch replaces child_process.exec with child_process.spawn. Unlike exec, spawn does not invoke a shell by default and passes arguments as a discrete array, eliminating shell metacharacter interpretation.
Detection Methods for CVE-2025-12489
Indicators of Compromise
- Unexpected child processes spawned by the Node.js process running evernote-mcp-server
- Shell interpreters (/bin/sh, cmd.exe) launched as descendants of the MCP server process
- Outbound network connections initiated by the MCP service to non-Evernote endpoints
- New files written to service-account-owned directories following an OAuth authentication attempt
Detection Strategies
- Monitor process creation telemetry for the MCP server spawning shells or arbitrary binaries during OAuth flows
- Alert on command lines containing shell metacharacters (;, |, &&, backticks, $()) passed to browser-launch commands such as open, xdg-open, or start
- Compare deployed versions of auth.js against the patched commit 1e66c78 to identify unpatched hosts
Monitoring Recommendations
- Ingest process, file, and network telemetry from hosts running MCP servers into a centralized data lake for correlation
- Baseline expected child processes of Node.js MCP services and alert on deviations
- Track OAuth callback URLs and flag values containing shell control characters or unusual encoding
How to Mitigate CVE-2025-12489
Immediate Actions Required
- Update evernote-mcp-server to a version that includes commit 1e66c78 or later
- Restrict the service account running the MCP server to the minimum privileges required
- Limit local access to systems hosting the MCP server to trusted administrators only
- Audit any custom forks or downstream integrations that reuse the vulnerable openBrowser implementation
Patch Information
The maintainer resolved the issue in commit 1e66c78c4ce6ea294ac6b0eb289a9eae9c5e9579 by replacing child_process.exec with child_process.spawn in auth.js. See the GitHub commit and the Zero Day Initiative advisory ZDI-25-983 for full details.
Workarounds
- Disable the browser-launch OAuth path and complete authentication manually if patching is not immediately feasible
- Run the MCP server under a dedicated, unprivileged service account to reduce escalation impact
- Apply application allowlisting to prevent unexpected child processes from executing under the Node.js runtime
# Update to the patched revision
cd evernote-mcp-server
git fetch origin
git checkout 1e66c78c4ce6ea294ac6b0eb289a9eae9c5e9579
npm install
# Restart the service under a least-privilege account
sudo systemctl restart evernote-mcp-server
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

