Back to skill

Security audit

N8N EVOL I

Security checks for vulnerabilities and agentic risk

Overview

This is a real n8n automation toolkit, but it needs Review because it can change live workflows and credentials while some install, transport, and persistence behaviors are under-scoped.

Install only if you trust the publisher and are comfortable giving the harness n8n workflow/credential authority. Use HTTPS-only n8n and Upstash endpoints, prefer narrowly scoped API keys, pin to a reviewed commit or release, avoid plugin auto-hooks unless you want automatic template rewrites, and review templates for any ../ placeholder paths before deploying.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
helpers/n8n_client.py:14
Finding

Authenticated requests permit cleartext HTTP and insufficiently constrained redirects

Content
View full analysis
str: return f"{self.base_url}/api/v1/{path.lstrip('/')}" def get(self, path: str, params: Optional[dict] = None) -> Any: resp = requests.get(self._url(path), headers=self._headers, params=params) resp.raise_for_status() return resp.json() if resp.content else None def post(self, path: str, body: Any = None) -> Any: resp = requests.post(self._url(path), headers=self._headers, json=body) resp.raise_for_status() return resp.json() if resp.content else None def put(self, path: str, body: Any) -> Any: resp = requests.put(self._url(path), headers=self._headers, json=body) resp.raise_for_status() return resp.json() if resp.content else None def delete(self, path: str) -> Any: resp = requests.delete(self._url(path), headers=self._headers) resp.raise_for_status() return resp.json() if resp.content else None ``` `helpers/cleanup_queue_state.py:29-35`: ```python def _upstash_call(base_url: str, token: str, cmd: list) -> dict: resp = requests.post( base_url.rstrip("/") + "/", headers={"Authorization": f"Bearer {token}"}, json=cmd, ) resp.raise_for_status() return resp.json() ``` `helpers/run.py:31-49`: ```python ...[truncated 3171 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
helpers/n8n_client.py:26
Finding

Core n8n and Redis requests can block indefinitely because no timeout is configured

Content
View full analysis
Any: resp = requests.get(self._url(path), headers=self._headers, params=params) resp.raise_for_status() return resp.json() if resp.content else None def post(self, path: str, body: Any = None) -> Any: resp = requests.post(self._url(path), headers=self._headers, json=body) resp.raise_for_status() return resp.json() if resp.content else None def put(self, path: str, body: Any) -> Any: resp = requests.put(self._url(path), headers=self._headers, json=body) resp.raise_for_status() return resp.json() if resp.content else None def delete(self, path: str) -> Any: resp = requests.delete(self._url(path), headers=self._headers) resp.raise_for_status() return resp.json() if resp.content else None ``` `helpers/cleanup_queue_state.py:29-37`: ```python def _upstash_call(base_url: str, token: str, cmd: list) -> dict: resp = requests.post( base_url.rstrip("/") + "/", headers={"Authorization": f"Bearer {token}"}, json=cmd, ) resp.raise_for_status() return resp.json() ``` ### Technical Analysis None of these Requests calls defines a connection or response timeout. Requests does not impose a default timeout, so a server can accept the connection and then delay or withhold the response indefinitely. `N8nClient` is the shared client used by deployment, activation, deactivation, workflow inspection, execution inspection, credential management, validation, and other lifecycle operations. The queue cleanup helper similarly performs several sequential Redis calls. An unavailable, compromised, or deliberately slow ...[truncated 1297 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
install.md:19
Finding

Installation uses mutable repository state and unpinned dependency versions

Content
View full analysis
=6.0 ``` `pyproject.toml:1-24`: ```toml [build-system] requires = ["setuptools>=69"] build-backend = "setuptools.build_meta" [project] name = "n8n-evol-I" version = "2.0.0" description = "Read-only skill package for n8n workflow automation. Install via git clone into skills/." requires-python = ">=3.11" dependencies = [ "pyyaml>=6.0", "requests>=2.31", "python-dotenv>=1.0", ] [project.optional-dependencies] dev = [ "pytest>=7", "pytest-httpserver>=1.0", ] dspy = [ "dspy>=2.0", "litellm>=1.0", ] ``` ### Technical Analysis The documented installation process clones the repository's mutable default branch and later updates it with an unrestricted `git pull`. Python dependencies are installed without exact versions or integrity hashes, while project metadata permits any later compatible release through broad lower-bound constraints. As a result, two installations performed at different times can receive different code despite following the same instructions. A future compromised repository commit, malicious package release, compromised package-maintainer account, or dependency-chain compromise could execute code that was not part of this audit. The optional DSPy and LiteLLM dependency sets increase the transitive dependency surface. The audit found no evidence that the dependency names are typosquatted or ...[truncated 1170 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Memory PoisoningPersistent Context Injection, Context Window Stuffing, Memory Manipulation
Findings (84)

Tainted flow: 'base_url' from os.environ.get (line 74, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · helpers/cleanup_queue_state.py (reported line 30)May include surrounding context.

python
def _upstash_call(base_url: str, token: str, cmd: list) -> dict:
    resp = requests.post(
        base_url.rstrip("/") + "/",
        headers={"Authorization": f"Bearer {token}"},
        json=cmd,

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description suggests a general-purpose harness for coding agents working with n8n automation systems. The supplied code instead implements a very specific Redis queue cleanup tool. It loads Redis credentials from environment config, probes queue state, and—when run with --force—issues destructive DEL and XGROUP DESTROY commands against Redis streams and keys. This is a materially different primary purpose from building/deploying/debugging n8n workflows, and it accesses a specific external resource (Upstash Redis) not implied by the description. While queue maintenance could be loosely related to operations, this code chunk is a narrow destructive infrastructure utility rather than the described n8n agent harness.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
89% confidence
Finding

The declared description centers on an n8n automation-system harness for building, deploying, maintaining, and debugging multi-workflow systems. This code chunk instead implements a narrow prompt-iteration utility for DSPy: it checks for DSPy, loads prompt/schema/dataset files, constructs a DSPy signature from JSON schema, evaluates predictions against example outputs, optionally runs a DSPy optimizer, and writes an optimized prompt file. While this may be adjacent to agent tooling, the code shown does not perform the described n8n workflow lifecycle functions, nor interact with n8n UI/workflows. That is a materially different primary purpose, so this chunk is a mismatch.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description presents a broad n8n automation harness for building, deploying, maintaining, and debugging workflows. The supplied code chunk does not implement any n8n integration, workflow orchestration, deployment, maintenance, debugging, or agent/UI handoff features. Instead, it is a narrow utility for resolving UUID placeholders in text. That behavior may be a supporting helper inside a larger system, but on its own it is materially different from the declared primary purpose, so this code chunk does not accurately represent the stated description.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description describes a substantial harness for managing n8n-powered automation workflows through coding agents and UI handoff. The supplied code instead implements only a minimal hello-world cloud function that echoes a greeting based on input. It does not interact with n8n, provide workflow management, deployment, debugging, or agent handoff capabilities. This is a clear material mismatch in primary purpose and implemented capabilities.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The declared description promises a substantial harness for managing and debugging n8n-powered automation systems. The provided code chunk only imports a hello_world function and places it in an exposed-functions registry. That is materially different in primary purpose and capability from the declared n8n orchestration/development harness. While this may be a small fragment of a larger system, based on the supplied code alone, the behavior shown is not accurately represented by the description.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 78)May include surrounding context.

md
- [skills/integrations/redis/lock-pattern.md](skills/integrations/redis/lock-pattern.md)

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
80% confidence
Finding

Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Content

Scanner excerpt · helpers/add_lock_to_workflow.py (reported line 31)May include surrounding context.

python
documented both forms inconsistently; finding #15 from the deep-dive.

    Input shapes:
      (a) `={{ <js> }}`   — already canonical; pass through, no warning.
      (b) `=<js>` (bare)  — wrap into `={{ <js> }}`; emit a one-shot deprecation
                           warning the first time normalization happens.
      (c) `<literal>`     — no leading `=`; treat as a static scope and wrap as

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · helpers/doctor.py (reported line 73)May include surrounding context.

python
load_env(env, ws)
        api_key = os.environ.get("N8N_API_KEY", "")
        if not api_key:
            return [_row(WARN, f"{env} API key", "N8N_API_KEY not set in .env")]
        from helpers.n8n_client import N8nClient
        instance = data.get("n8n", {}).get("instanceName", "")
        N8nClient(base_url=instance, api_key=api_key).get("workflows", params={"limit": 1})

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · helpers/doctor.py (reported line 233)May include surrounding context.

python
load_env(env, ws)
        api_key = os.environ.get("N8N_API_KEY", "")
        if not api_key:
            return [_row(WARN, f"{env} API key", "N8N_API_KEY not set in .env")]
        from helpers.n8n_client import N8nClient
        instance = data.get("n8n", {}).get("instanceName", "")
        N8nClient(base_url=instance, api_key=api_key).get("workflows", params={"limit": 1})

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · helpers/manage_variables.py (reported line 7)May include surrounding context.

python
list    — GET /api/v1/variables (optionally filtered by --name).
  create  — POST /api/v1/variables with {key, value}.
  update  — PUT /api/v1/variables/{id} with {key, value}.
  delete  — DELETE /api/v1/variables/{id}; requires --force unless dry-listing.

CLI surface uses `--name` (NOT `--key`) for the n8n variable's name. Reason: in
the rest of the harness, `--key` means a YAML config slot under

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · helpers/manage_variables.py (reported line 117)May include surrounding context.

python
help="The n8n variable's name (sent as `key` in the request body).")
    p_update.add_argument("--value", required=True)

    p_delete = sub.add_parser("delete", help="DELETE /variables/{id}")
    p_delete.add_argument("--env", required=True)
    p_delete.add_argument("--id", required=True)
    p_delete.add_argument("--force", action="store_true",

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · helpers/bootstrap_env.py (reported line 105)May include surrounding context.

python
def ensure_client(env_name: str, workspace: Path) -> N8nClient:
    """Return a cached N8nClient for the given env. Cache invalidated on .env mtime change."""
    import os
    from helpers.config import load_env, load_yaml

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · helpers/bootstrap_env.py (reported line 149)May include surrounding context.

python
def ensure_client(env_name: str, workspace: Path) -> N8nClient:
    """Return a cached N8nClient for the given env. Cache invalidated on .env mtime change."""
    import os
    from helpers.config import load_env, load_yaml

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · helpers/n8n_client.py (reported line 54)May include surrounding context.

python
def ensure_client(env_name: str, workspace: Path) -> N8nClient:
    """Return a cached N8nClient for the given env. Cache invalidated on .env mtime change."""
    import os
    from helpers.config import load_env, load_yaml

Known Vulnerable Dependency: form-data==4.0.4 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
91% confidence
Finding

The lockfile pins form-data 4.0.4, which is flagged for a CRLF injection issue in multipart field handling. If this helper stack constructs multipart requests using attacker-influenced field names, an attacker could tamper with request structure or headers, which is especially relevant in an automation harness that may forward arbitrary workflow data to external services.

Content

No source excerpt is available for this finding.

Possible Typosquatting: 'uvicorn' resembles popular package 'gunicorn'

High
Category
Supply Chain
Confidence
70% confidence
Finding

Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · skills/integrations/airtable/README.md (reported line 15)May include surrounding context.

md
## Credential type

`airtableTokenApi` — Personal Access Token (PAT) from `airtable.com/create/tokens`.

For setup, see [`skills/manage-credentials.md`](../../manage-credentials.md). Scopes minimum: `data.records:read` and (if writing) `data.records:write`. Each token can be limited to specific bases — granular tokens are best practice.

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
80% confidence
Finding

Skill instructs the agent to omit warnings, disclaimers, or ethical commentary. Stripping safety caveats hides risk from the user and is a common jailbreak preamble.

Content

Scanner excerpt · skills/patterns/code-node-discipline.md (reported line 241)May include surrounding context.

md
## Validator checks (template only)

`validate.py` runs these against every `n8n-nodes-base.code` node in a template. All checks are **errors**, no warnings. Built JSON skips these checks (placeholders are already replaced post-hydrate).

| Rule | Error |
|---|---|

Memory Manipulation

High
Category
Memory Poisoning
Confidence
90% confidence
Finding

Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Content

Scanner excerpt · skills/patterns/error-handling.md (reported line 15)May include surrounding context.

md
2. **Log** — the handler ships the error to your audit/observability platform (Sentry, Datadog, Slack, …).
3. **Process** — the handler does *something about it*: release stale locks, invalidate pending DB rows, notify the originating user, trigger a compensating workflow.

Skipping any step leaves you blind, deafened, or with a corrupt state. The harness wires step 1 for you (`register_error_handler.py`); steps 2 and 3 are your error-handler's body. This doc covers the paradigm; the integration skills give you the concrete API surfaces.

## Step 1: Capture

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · install.md (reported line 67)May include surrounding context.

md
## Auto-tidy hook (plugin mode only)

When n8n-evol-I is installed as a Claude Code plugin, a PostToolUse hook fires `tidy_workflow.py --in-place` automatically after every `*.template.json` Write/Edit/MultiEdit. Standalone-skill-mode users who want auto-tidy can configure a hook manually in `~/.claude/settings.json`.

To disable the hook after plugin install: remove or rename `hooks/hooks.json` in the plugin directory, or disable the plugin in Claude Code settings.

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · skills/tidy-workflow.md (reported line 40)May include surrounding context.

md
## Auto-tidy hook (plugin mode only)

When n8n-evol-I is installed as a Claude Code plugin, a PostToolUse hook fires `tidy_workflow.py --in-place` automatically after every `*.template.json` Write/Edit/MultiEdit. Standalone-skill-mode users who want auto-tidy can configure a hook manually in `~/.claude/settings.json`.

To disable the hook after plugin install: remove or rename `hooks/hooks.json` in the plugin directory, or disable the plugin in Claude Code settings.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
87% confidence
Finding

The skill advertises operational capabilities that include file, shell, environment, and network access, but it does not declare any explicit tool scope or allowed-tools boundaries in the skill definition. In an agent setting, this can lead to over-privileged execution and make it easier for downstream sub-skills or helper scripts to perform unexpected filesystem, command, or network actions without clear policy constraints.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The router instructs the agent to route 'anything n8n-related' to this skill, which is an overly broad trigger with no exclusions, risk gates, or confirmation requirements. In practice, this can cause the agent to invoke high-privilege workflow, deploy, debug, credential, or shell-backed helper paths for loosely related requests, increasing the chance of unintended sensitive actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

This code reads API credentials from environment variables and configures remote LLM providers, which implies prompts or other user/system data may be sent over the network. The file has no confirmation prompt, user-facing log/print, or warning comment/docstring explaining that external API calls will occur.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
skills/patterns/llm-providers.md:23