CherryHQ/cherry-studio · error · Error

Invalid MCP package env: null byte detected in environment v

Error message

Invalid MCP package env: null byte detected in environment variable name

What it means

Thrown by buildResolvedEnv while iterating environment variables from an MCP package manifest. A key in the env map contained a NUL (\0) byte. Null bytes in env keys are a classic injection vector because they can truncate or confuse downstream C-string handling in the spawned process or the OS exec layer. The guard runs after the env map is received from the manifest but before any value substitution, so it inspects the key as authored.

Source

Thrown at src/main/ai/mcp/McpPackageService.ts:257

const DXT_ENV_DENYLIST = ['NODE_OPTIONS', 'LD_PRELOAD', 'LD_LIBRARY_PATH']

/**
 * Validate an MCP package environment map and build a new sanitized object.
 * Package env values bypass the command/arg validation, so apply equivalent hardening here:
 * reject null bytes in keys/values and denylist process-affecting variables.
 *
 * @throws Error if a key/value contains a null byte or a key is denylisted
 */
export function buildResolvedEnv(
  env: Record<string, string>,
  extractDir: string,
  userConfig?: Record<string, any>
): Record<string, string> {
  const resolvedEnv: Record<string, string> = {}

  for (const [key, value] of Object.entries(env)) {
    if (key.includes('\0')) {
      throw new Error('Invalid MCP package env: null byte detected in environment variable name')
    }

    // Denylist process-affecting variables (DYLD_* on macOS, plus exact matches above).
    const canonicalKey = key.toUpperCase()
    if (DXT_ENV_DENYLIST.includes(canonicalKey) || canonicalKey.startsWith('DYLD_')) {
      throw new Error(`Invalid MCP package env: environment variable "${key}" is not allowed`)
    }

    const substituted = performVariableSubstitution(value, extractDir, userConfig)
    if (substituted.includes('\0')) {
      throw new Error(`Invalid MCP package env: null byte detected in value of environment variable "${key}"`)
    }

    resolvedEnv[key] = substituted
  }

  return resolvedEnv
}

View on GitHub (pinned to 726446b54c)

Solutions

  1. Open the package's manifest.json and scan server.mcp_config.env keys (and platform_overrides.env keys) for embedded NUL or other control characters; remove them.
  2. If the manifest was generated, fix the generator to strip control characters from env keys before writing JSON.
  3. Repackage and re-upload; the install is atomic so no partial state remains.
Defensive patterns

Strategy: validation

Validate before calling

function hasCleanEnvKeys(env: Record<string, string>): boolean {
  return Object.keys(env).every((k) => !k.includes('\0'))
}

Type guard

function isCleanEnvKey(key: string): boolean {
  return typeof key === 'string' && !key.includes('\0')
}

Prevention

When it happens

Trigger: A manifest's server.mcp_config.env (or a platform_overrides env map merged in by applyPlatformOverrides) has a key containing a literal \0, e.g. "FOO\0BAR". JSON permits escaped control characters, so this can survive parsing intact.

Common situations: A hand-edited manifest with a copy-paste error introduced a control character; a malicious or corrupted package was uploaded; a build tool that generated the manifest emitted raw bytes instead of UTF-8 text.

Related errors


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/0eca2570a9207990. Report an issue: GitHub.