ruvnet/ruflo · error · Error

Dangerous key segment rejected

Error message

Dangerous key segment rejected: ${part}

What it means

Thrown by setNestedValue() in config-tools.ts:109 when ANY dot-separated segment of a config_set key is in DANGEROUS_KEYS = {'__proto__', 'constructor', 'prototype'}. This is a prototype-pollution guard: those segment names, when used as object keys during nested writes, can hijack Object.prototype in older runtimes or pollute structures downstream. Every segment is checked before any mutation.

Solutions

  1. Rename the colliding segment ('prototype' -> 'proto', 'base', 'template')
  2. Never forward raw user input as config keys — validate against an allowlist of known keys first
  3. If you did not send the call, treat this error as an attack signal: audit who has access to the config tools

Example fix

// before
await callTool('config_set', { key: '__proto__.polluted', value: true });
// throws: Dangerous key segment rejected: __proto__

// after (legit deep config: avoid the reserved segment name)
await callTool('config_set', { key: 'design.proto.theme', value: 'dark' });
Defensive patterns

Strategy: validation

Validate before calling

const DANGEROUS = new Set(['__proto__', 'constructor', 'prototype']);
function isSafeConfigKey(key: string): boolean {
  return key.split('.').every((seg) => seg.length > 0 && !DANGEROUS.has(seg));
}
if (!isSafeConfigKey(userKey)) throw new TypeError('config key rejected: reserved segment');

Prevention

When it happens

Trigger: config_set with a key like '__proto__.polluted', 'constructor.prototype.x', or any legitimate-looking key that happens to contain a segment named exactly 'constructor', 'prototype', or '__proto__' (e.g. 'ui.widget.prototype.enabled').

Common situations: Security scanners and pentests probing the MCP config endpoint; applications that forward arbitrary user-supplied keys to config_set; domain vocabulary ('design.prototype.theme') colliding with the blacklist.

Related errors


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

Appendix: 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 fa13ee4ad6)