Skip to Content

n8n

Static analysis for n8n workflow files to detect loops, AI agent vulnerabilities, and credential exposure.

Quick Start

# Export workflow from n8n UI, then scan inkog scan ./workflows

What Inkog Detects

FindingSeverityDescription
Workflow LoopCRITICALSplit/Merge or Loop node without limits
AI Agent RiskCRITICALAI Agent node with unrestricted tools
Credential LeakCRITICALAPI keys exposed in workflow JSON
HTTP Request RiskHIGHHTTP Request to arbitrary URLs
Code Node RiskCRITICALCode nodes with dangerous operations

Workflow Loops

n8n Loop nodes without iteration limits run forever.

Vulnerable
No maxIterations - loops forever
{
"nodes": [
  {
    "name": "Loop Over Items",
    "type": "n8n-nodes-base.loop",
    "parameters": {}
  },
  {
    "name": "HTTP Request",
    "type": "n8n-nodes-base.httpRequest",
    "parameters": {
      "url": "https://api.example.com"
    }
  }
],
"connections": {
  "Loop Over Items": {
    "main": [[{"node": "HTTP Request"}]]
  },
  "HTTP Request": {
    "main": [[{"node": "Loop Over Items"}]]
  }
}
}
Secure
Explicit iteration limit and timeout
{
"nodes": [
  {
    "name": "Loop Over Items",
    "type": "n8n-nodes-base.loop",
    "parameters": {
      "maxIterations": 100
    }
  },
  {
    "name": "HTTP Request",
    "type": "n8n-nodes-base.httpRequest",
    "parameters": {
      "url": "https://api.example.com",
      "timeout": 30000
    }
  },
  {
    "name": "Check Limit",
    "type": "n8n-nodes-base.if",
    "parameters": {
      "conditions": {
        "number": [{
          "value1": "={{$runIndex}}",
          "operation": "smaller",
          "value2": 100
        }]
      }
    }
  }
]
}

AI Agent Node Vulnerabilities

AI Agent nodes using LangChain can execute unsafe tools.

Vulnerable
Code tool with eval() - RCE risk
{
"nodes": [
  {
    "name": "AI Agent",
    "type": "@n8n/n8n-nodes-langchain.agent",
    "parameters": {
      "tools": [
        {
          "type": "@n8n/n8n-nodes-langchain.toolCode",
          "parameters": {
            "code": "return eval($input)"
          }
        }
      ]
    }
  }
]
}
Secure
Safe built-in tools with iteration limit
{
"nodes": [
  {
    "name": "AI Agent",
    "type": "@n8n/n8n-nodes-langchain.agent",
    "parameters": {
      "maxIterations": 10,
      "tools": [
        {
          "type": "@n8n/n8n-nodes-langchain.toolCalculator"
        },
        {
          "type": "@n8n/n8n-nodes-langchain.toolWikipedia"
        }
      ],
      "systemMessage": "Only use provided tools. Never execute code."
    }
  }
]
}

Credential Exposure

Workflow exports can contain plaintext credentials.

Vulnerable
API keys hardcoded in workflow
{
"nodes": [
  {
    "name": "OpenAI",
    "type": "@n8n/n8n-nodes-langchain.lmOpenAi",
    "parameters": {
      "apiKey": "sk-abc123..."
    }
  },
  {
    "name": "HTTP Request",
    "type": "n8n-nodes-base.httpRequest",
    "parameters": {
      "url": "https://api.stripe.com",
      "headers": {
        "Authorization": "Bearer sk_live_..."
      }
    }
  }
]
}
Secure
Credentials stored in n8n credential store
{
"nodes": [
  {
    "name": "OpenAI",
    "type": "@n8n/n8n-nodes-langchain.lmOpenAi",
    "credentials": {
      "openAiApi": {
        "id": "1",
        "name": "OpenAI Account"
      }
    }
  },
  {
    "name": "HTTP Request",
    "type": "n8n-nodes-base.httpRequest",
    "parameters": {
      "url": "https://api.stripe.com"
    },
    "credentials": {
      "httpHeaderAuth": {
        "id": "2",
        "name": "Stripe API"
      }
    }
  }
]
}

HTTP Request to Arbitrary URLs

HTTP nodes accepting dynamic URLs enable SSRF.

Vulnerable
User controls URL - SSRF risk
{
"nodes": [
  {
    "name": "Webhook",
    "type": "n8n-nodes-base.webhook",
    "parameters": {
      "path": "fetch-url"
    }
  },
  {
    "name": "HTTP Request",
    "type": "n8n-nodes-base.httpRequest",
    "parameters": {
      "url": "={{$json.url}}"
    }
  }
]
}
Secure
URL validation with allowlist
{
"nodes": [
  {
    "name": "Webhook",
    "type": "n8n-nodes-base.webhook",
    "parameters": {
      "path": "fetch-url"
    }
  },
  {
    "name": "Validate URL",
    "type": "n8n-nodes-base.code",
    "parameters": {
      "code": "const url = new URL($json.url); const allowed = ['api.example.com']; if (!allowed.includes(url.hostname)) throw new Error('URL not allowed'); return $json;"
    }
  },
  {
    "name": "HTTP Request",
    "type": "n8n-nodes-base.httpRequest",
    "parameters": {
      "url": "={{$json.url}}",
      "timeout": 10000
    }
  }
]
}

Code Node Risks

Code nodes can execute dangerous operations.

Vulnerable
Shell command execution
{
"name": "Code",
"type": "n8n-nodes-base.code",
"parameters": {
  "code": "const { execSync } = require('child_process'); return execSync($json.command).toString();"
}
}
Secure
Data transformation only
{
"name": "Code",
"type": "n8n-nodes-base.code",
"parameters": {
  "code": "// Safe operations only - no require(), no eval(), no exec()
const data = $json.data;
const processed = data.map(item => ({ id: item.id, name: item.name.trim() }));
return processed;"
}
}

How to Export Workflows

To scan n8n workflows, export them as JSON:

  1. Single Workflow: Workflow menu → Download as JSON
  2. All Workflows: Settings → Export → Download all workflows
  3. API Export:
# Export via n8n API curl -X GET "http://localhost:5678/api/v1/workflows" \ -H "X-N8N-API-KEY: your-api-key" \ -o workflows.json

Then scan:

inkog scan ./workflows.json

Best Practices

  1. Set maxIterations on all Loop nodes
  2. Use credential store - never hardcode API keys
  3. Avoid Code nodes with require() or eval()
  4. Validate URLs before HTTP Request nodes
  5. Limit AI Agent iterations with maxIterations
  6. Review exports before sharing or committing

CLI Examples

# Scan workflow files inkog scan ./workflows # Check for credential leaks inkog scan . -severity critical # JSON output for CI inkog scan ./workflows -output json
Last updated on