n8n-io/n8n · error
Dangerous key "${dangerousKey}" found in JSON data
Error message
Dangerous key "${dangerousKey}" found in JSON data What it means
Thrown by parseJson() inside parseStructuredFile when a JSON array object contains a key named __proto__, constructor, or prototype (see the DANGEROUS_KEYS set at structured-file-parser.ts:49). The guard runs before keys are collected as column headers, so prototype-polluting payloads can never reach downstream row/column processing. It is a hard security refusal, not a recoverable shape problem.
Source
Thrown at packages/@n8n/instance-ai/src/parsers/structured-file-parser.ts:340
}
if (!Array.isArray(parsed)) {
throw new Error('Expected a JSON array of objects, got a single value or object');
}
if (parsed.length === 0) {
return { rawHeaders: [], allRows: [] };
}
// Collect all keys across all objects (preserving order of first appearance)
const keySet = new Set<string>();
for (const item of parsed) {
if (typeof item !== 'object' || item === null || Array.isArray(item)) {
throw new Error('JSON array items must be flat objects (not arrays, nulls, or primitives)');
}
const dangerousKey = hasDangerousKey(item as Record<string, unknown>);
if (dangerousKey) {
throw new Error(`Dangerous key "${dangerousKey}" found in JSON data`);
}
for (const key of Object.keys(item as Record<string, unknown>)) {
keySet.add(key);
}
}
const rawHeaders = [...keySet];
// Validate all values are flat
for (const item of parsed) {
const obj = item as Record<string, unknown>;
for (const [key, value] of Object.entries(obj)) {
if (value !== null && typeof value === 'object') {
throw new Error(
`Nested ${Array.isArray(value) ? 'array' : 'object'} found at key "${key}". Only flat objects are supported.`,
);
}
}View on GitHub (pinned to 5ac6606e81)
Solutions
- Inspect the JSON for the keys __proto__, constructor, or prototype and rename or strip them before parsing.
- If the source is xlsx, open the sheet and rename the offending column header.
- Pre-validate the parsed JSON with your own hasDangerousKey check (structured-file-parser.ts:261) to give a clearer upstream error.
- Reject the attachment at the MIME-validation layer if it cannot be trusted.
Example fix
// before: [{ "__proto__": { "admin": true }, "name": "x" }]
// after: [{ "name": "x" }] Defensive patterns
Strategy: validation
Validate before calling
const DANGEROUS = new Set(['__proto__','constructor','prototype']);
function hasDangerousKey(obj: Record<string, unknown>): string | undefined {
for (const key of Object.keys(obj)) if (DANGEROUS.has(key)) return key;
return undefined;
}
// run before parseStructuredFile:
const parsed = JSON.parse(content);
for (const item of parsed) {
const bad = hasDangerousKey(item);
if (bad) throw new Error(`Refusing to attach: dangerous key "${bad}"`);
} Type guard
function isSafeFlatObject(v: unknown): v is Record<string, string | number | boolean | null> {
if (typeof v !== 'object' || v === null || Array.isArray(v)) return false;
for (const key of Object.keys(v)) {
if (DANGEROUS.has(key)) return false;
const val = (v as Record<string, unknown>)[key];
if (val !== null && typeof val === 'object') return false;
}
return true;
} Try / catch
try { return parseStructuredFile(attachment, idx, input); }
catch (e) {
if (e instanceof Error && e.message.startsWith('Dangerous key')) {
// surface a sanitize prompt to the caller / LLM
}
throw e;
} Prevention
- Sanitize exported data with a key blocklist before attaching.
- Never trust LLM- or user-generated JSON to be prototype-safe; validate first.
- Treat __proto__/constructor/prototype as reserved names in any tool that emits tabular data.
When it happens
Trigger: An attachment with mimeType application/json (or an .xlsx round-tripped through JSON at xlsx-parser.ts:56) whose decoded content is a JSON array containing an object like {"__proto__": {...}} or {"constructor": "x"}. The check fires for every item in the array during header collection.
Common situations: Data exported from a tool that serializes class metadata; a user sanitizing/renaming columns to JS reserved names; an LLM-generated eval-data payload that includes prototype chains; a malicious or fuzzed attachment probing for prototype-pollution sinks.
Related errors
- Cannot access "${name}" via expression extension due to secu
- Nested ${Array.isArray(value) ? 'array' : 'object'} found at
- Too many columns: ${rawHeaders.length} (max ${MAX_COLUMNS})
- Security violation: 'constructor access' is not allowed
- LangSmithTelemetry creates its own tracer — do not use .otlp
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/800ab04c8c4fcd97.
Report an issue: GitHub.