ruvnet/ruflo · error · Error

Dangerous key segment rejected: ${part}

Error message

Dangerous key segment rejected: ${part}

What it means

Thrown by setNestedValue to block prototype pollution: any segment of a dotted config key that equals '__proto__', 'constructor', or 'prototype' (the DANGEROUS_KEYS set) is rejected. Writing through these keys on a plain object would mutate Object.prototype and is a classic injection vector, so the tool fails closed.

Source

Thrown at v3/@claude-flow/cli/src/mcp-tools/config-tools.ts:109

function filterDangerousKeys(obj: Record<string, unknown>): Record<string, unknown> {
  const filtered: Record<string, unknown> = {};
  for (const [key, value] of Object.entries(obj)) {
    if (!DANGEROUS_KEYS.has(key)) {
      filtered[key] = value;
    }
  }
  return filtered;
}

function setNestedValue(obj: Record<string, unknown>, key: string, value: unknown): void {
  const MAX_NESTING_DEPTH = 10;
  const parts = key.split('.');
  if (parts.length > MAX_NESTING_DEPTH) {
    throw new Error(`Key exceeds maximum nesting depth of ${MAX_NESTING_DEPTH}`);
  }
  for (const part of parts) {
    if (DANGEROUS_KEYS.has(part)) {
      throw new Error(`Dangerous key segment rejected: ${part}`);
    }
  }
  let current = obj;
  for (let i = 0; i < parts.length - 1; i++) {
    const part = parts[i];
    if (!(part in current) || typeof current[part] !== 'object') {
      current[part] = {};
    }
    current = current[part] as Record<string, unknown>;
  }
  current[parts[parts.length - 1]] = value;
}

export const configTools: MCPTool[] = [
  {
    name: 'config_get',
    description: 'Get configuration value Use when native settings.json edits are wrong because the values need to be read by the Ruflo runtime (daemon, MCP server, neural router) — those load via the config_* path, not by re-reading settings.json. For .gitignore / .editorconfig style files, native Edit is fine.',
    category: 'config',

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Rename the offending segment to a safe literal (e.g. 'proto' or 'ctor').
  2. Sanitise user-derived keys by rejecting or mapping the three dangerous names before calling config_set.
  3. Treat this error as intentional fail-closed behaviour — do not catch and retry with the same key.
  4. Audit the upstream source of the key (CLI arg, HTTP body, LLM output) and constrain it to an allowlist.

Example fix

// before
config_set('obj.__proto__.polluted', true)
// after
config_set('obj.proto.polluted', true)
Defensive patterns

Strategy: validation

Validate before calling

const DANGEROUS = new Set(['__proto__', 'constructor', 'prototype']);
function assertSafeConfigKey(key) {
  for (const part of key.split('.')) {
    if (DANGEROUS.has(part)) throw new Error(`unsafe config key segment: ${part}`);
  }
}

Type guard

function isSafeConfigKey(key: string): boolean {
  const dangerous = new Set(['__proto__', 'constructor', 'prototype']);
  return key.split('.').every((p) => !dangerous.has(p));
}

Prevention

When it happens

Trigger: Calling config_set with a key containing a segment exactly named '__proto__', 'constructor', or 'prototype' — e.g. 'a.__proto__.polluted' or 'constructor.prototype.x'. The check iterates all segments before any write occurs.

Common situations: User-supplied or LLM-generated key strings routed straight into config_set; a key derived from a filename or identifier that happens to be 'constructor'; security testing/fuzzing that probes for prototype pollution; merging untrusted JSON whose keys become config paths.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/5318c5fdf8c881ae. Report an issue: GitHub.