Back to skill

Security audit

n8n Pilot

Security checks for vulnerabilities and agentic risk

Overview

This n8n automation skill is mostly coherent, but it needs review because it advises live, unpinned community-node installation that can run third-party npm code inside the n8n container.

Review this skill before installing. Use it only with an n8n instance you administer, protect N8N_API_KEY and N8N_ENCRYPTION_KEY carefully, avoid plaintext secret backups, and do not follow the community-node npm install guidance on a live container unless the package is trusted, pinned, reviewed, and tested in staging. Prefer quarantine or labels over automatic deletion for email and business-data workflows.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T08 · Insecure Dependencies

Error
Location
nodes.md:113
Finding
Unverified Community Node Installation in the Live n8n Container## Vulnerability Details **File Location**: `nodes.md`, lines 113–119 **Additional Locations**: `SKILL.md`, lines 629 and 678 **Vulnerability Type**: T08: Insecure Dependencies **Risk Level**: High ### Vulnerable Code ```markdown ## Community Nodes Install via `npm install` in n8n container: ```bash docker exec n8n npm install n8n-nodes-PACKAGE_NAME docker restart n8n ``` Browse available: https://www.npmjs.com/search?q=n8n-nodes ``` The same unsafe installation pattern is also presented in `SKILL.md`: ```markdown | Install community nodes | ❌ | `npm install` in container + restart | ``` ```markdown | Install community node | `docker exec n8n npm install n8n-nodes-NAME && docker restart n8n` | ``` ### Technical Analysis The instructions permit an unrestricted package name and do not require an exact version, lockfile, integrity hash, trusted-package allowlist, provenance verification, or package review. Installation occurs directly inside the running n8n application container. npm packages can execute lifecycle scripts such as `preinstall`, `install`, and `postinstall`. Consequently, installing a malicious, typo-squatted, compromised, or unexpectedly updated community package can execute attacker-controlled code with the permissions of the container user. The package could also provide malicious n8n node implementations that execute when workflows load or invoke them. Restarting the live container immediately after installation makes the newly installed component part of the active automation environment without an isolated build, security scan, or staged validation process. ### Attack Path 1. An attacker publishes a malicious or typo-squatted package using a plausible `n8n-nodes-*` name, or compromises an existing community package. 2. The attacker recommends that package for an integration needed by the user. 3. The agent or operator follows the documented command and substitutes the attacker-controlled package name: ```bash docker exec n ...[truncated 1387 chars]
Remediation
## Remediation Suggestions 1. **Use an explicit allowlist** - Permit only reviewed package names from verified publishers. - Reject arbitrary package names supplied through workflow input or untrusted recommendations. 2. **Pin and verify dependencies** - Require exact package versions rather than floating versions. - Use a lockfile and verify registry integrity metadata. - Review package ownership, release history, source repository, signatures or provenance, and transitive dependencies before approval. 3. **Do not modify the live container** - Install approved nodes during an isolated image-build stage. - Scan the resulting image and dependencies before deployment. - Promote an immutable, versioned image through development, staging, and production. - Roll back by redeploying the previous image rather than editing a running container. 4. **Control lifecycle scripts** - Use `npm install --ignore-scripts` during initial inspection where compatible. - Audit any package that requires lifecycle scripts before allowing those scripts to execute. - Run software composition analysis and malware scanning against the package and resulting image. 5. **Apply runtime least privilege** - Run n8n as a non-root user. - Remove unnecessary Linux capabilities. - Use read-only filesystems and narrowly scoped writable volumes where feasible. - Never mount the Docker socket into the n8n container. - Restrict outbound network access and isolate sensitive internal services. 6. **Require explicit confirmation and staged testing** - Display the exact package, version, publisher, integrity value, and requested change before installation. - Require operator approval. - Test community nodes with non-production credentials and data in an isolated environment before production promotion. 7. **Replace the documented command** - Remove guidance that runs an unpinned `npm install` directly in the active container. - Provide a c ...[truncated 82 chars]
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (21)

Credential Access

High
Category
Privilege Escalation
Content
# 2. n8n data volume (encryption key, config)
docker cp n8n:/home/node/.n8n ./n8n_data_backup/

# 3. .env file with passwords and encryption key
```

**Critical:** If you lose `N8N_ENCRYPTION_KEY`, ALL credentials become permanently unrecoverable. Back it up securely.
Confidence
88% confidence
Finding
The backup guidance explicitly includes copying the `.env` file containing passwords and the encryption key, which concentrates high-value secrets into portable files. If operators follow this without strict storage controls, compromise of the backup location would expose credentials and the key needed to decrypt n8n secrets, leading to broad credential theft.

Credential Access

High
Category
Privilege Escalation
Content
| `smtpAccount` | SMTP credentials | ✅ Yes | Host, port, user, password |
| `slackApi` | Bot token | ✅ Yes | Token-based |
| `googleApiOAuth2` | OAuth2 flow | ❌ Browser required | Gmail, Sheets, Calendar, Drive |
| `githubApi` | Personal access token | ✅ Yes | Token + optional 2FA |

## Creating Credentials via API
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
| `smtpAccount` | SMTP credentials | ✅ Yes | Host, port, user, password |
| `slackApi` | Bot token | ✅ Yes | Token-based |
| `googleApiOAuth2` | OAuth2 flow | ❌ Browser required | Gmail, Sheets, Calendar, Drive |
| `githubApi` | Personal access token | ✅ Yes | Token + optional 2FA |

## Creating Credentials via API
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
2. **User completes consent flow** in the n8n UI (Settings → Credentials → click → Connect)

3. **n8n stores the refresh/access tokens** automatically after consent

### OAuth2 Redirect URI
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
2. **User completes consent flow** in the n8n UI (Settings → Credentials → click → Connect)

3. **n8n stores the refresh/access tokens** automatically after consent

### OAuth2 Redirect URI
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
1. **PostgreSQL database** (contains workflows, credentials, execution history)
2. **n8n data volume** (encryption key, config files)
3. **Environment variables** (.env file with passwords and encryption key)

### What NOT to Back Up
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Vague Triggers

Medium
Confidence
84% confidence
Finding
The 'When to Use' section says to use the skill whenever a task 'involves n8n' and then lists a very wide range of activities. For a markdown skill description, this is an ambiguous trigger scope because it does not clearly distinguish when this skill should activate versus when a different n8n-related skill should not, nor does it provide exclusion conditions or negative examples.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
|---------|------|-----------|
| Loop without max iteration | 🔴 Infinite execution | Split In Batches without `batchSize`, or Code node with `while(true)` |
| Delete without filter | 🔴 Data destruction | Database delete/HTTP DELETE without WHERE/filter parameters |
| Webhook without auth | 🟡 Anyone can trigger | Webhook node with `authentication=none` |
| HTTP to private IPs | 🟡 SSRF risk | HTTP Request to `10.x`, `172.16-31.x`, `192.168.x`, `localhost` |
| Email/Send without limit | 🟡 Mass spam | Loop + email/Send node without max cap |
| No error handling | 🟡 Silent failures | Workflow with no Error Trigger or error branches |
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Unsafe Defaults

Medium
Category
Tool Misuse
Content
|---------|------|-----------|
| Loop without max iteration | 🔴 Infinite execution | Split In Batches without `batchSize`, or Code node with `while(true)` |
| Delete without filter | 🔴 Data destruction | Database delete/HTTP DELETE without WHERE/filter parameters |
| Webhook without auth | 🟡 Anyone can trigger | Webhook node with `authentication=none` |
| HTTP to private IPs | 🟡 SSRF risk | HTTP Request to `10.x`, `172.16-31.x`, `192.168.x`, `localhost` |
| Email/Send without limit | 🟡 Mass spam | Loop + email/Send node without max cap |
| No error handling | 🟡 Silent failures | Workflow with no Error Trigger or error branches |
Confidence
75% confidence
Finding
Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The example workflow JSON sets 'timezone' to 'Europe/Berlin', which imposes a locale-specific default in natural-language guidance. Similar locale-specific defaults recur later in the self-hosting examples, but no user choice or justification is provided for using that region.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The development compose example sets 'TZ=Europe/Berlin', which is a locale-specific operational default. Under the policy, forcing a specific locale is a violation unless the skill offers user opt-in or documents why that region is required.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The production compose example again fixes 'TZ=Europe/Berlin', creating a locale-specific default in operational guidance. No region-specific compliance reason or user selection step is provided.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
# Create an API key credential via API
curl -X POST "${N8N_BASE_URL}/api/v1/credentials" \
  -H "X-N8N-API-KEY: ${N8N_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
### API Key / Header Auth

```bash
curl -X POST "${N8N_BASE_URL}/api/v1/credentials" \
  -H "X-N8N-API-KEY: ${N8N_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
while (hasMore) {
  const url = cursor
    ? `https://api.example.com/items?cursor=${cursor}`
    : `https://api.example.com/items`;

  const response = await this.helpers.httpRequest({
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
while (hasMore) {
  const url = cursor
    ? `https://api.example.com/items?cursor=${cursor}`
    : `https://api.example.com/items`;

  const response = await this.helpers.httpRequest({
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
while (hasMore) {
  const url = cursor
    ? `https://api.example.com/items?cursor=${cursor}`
    : `https://api.example.com/items`;

  const response = await this.helpers.httpRequest({
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
while (hasMore) {
  const url = cursor
    ? `https://api.example.com/items?cursor=${cursor}`
    : `https://api.example.com/items`;

  const response = await this.helpers.httpRequest({
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
```

**Gotchas:**
- n8n automatically runs independent branches in parallel
- Merge node waits for all inputs by default
- Use `mergeByKey` to join results from different APIs on a shared field
Confidence
80% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The recipe includes an automated email-classification flow that deletes messages classified as spam, but it gives no caution about false positives, review queues, or safer alternatives. In a workflow-automation skill, this can directly cause irreversible data loss or business disruption if the classifier mislabels legitimate mail.

Missing User Warnings

Low
Confidence
87% confidence
Finding
This markdown file instructs the user to run `docker exec ... npm install ...` and `docker restart n8n`, which are system-modifying operations. The surrounding text does not warn that these commands change the running container and may affect the existing n8n installation.

Static analysis

No suspicious patterns detected.