n8n-syntax-code-node — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited n8n-syntax-code-node (Agent Skill) and scored it 45/100 (orange). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 1 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Complete reference for the n8n v1.x Code node — JavaScript and Python modes, execution models, available variables, binary data, restrictions, and return format.
| Aspect | Detail |
|---|---|
| Languages | JavaScript (Node.js) — always available; Python — requires N8N_PYTHON_ENABLED=true (stable v1.111.0+) |
| Default mode | Run Once for All Items |
| Return format | MUST return [{json: {...}}] (all-items) or {json: {...}} (each-item) |
| Environment | Sandboxed — no filesystem, no HTTP, no $itemIndex, no $secrets, no $parameter |
These restrictions apply to ALL Code node executions. Violating them causes runtime errors.
fs, path, or any file I/O. Use Read/Write Files From Disk nodes instead.fetch, axios, or http. Use the HTTP Request node instead.Need to write Code node logic?
├── Processing items independently (filter, transform, enrich)?
│ └── Use "Run Once for Each Item"
│ ├── JS: access current item via $input.item.json
│ └── Python: access current item via _item["json"]
├── Need to compare/aggregate across ALL items (sort, deduplicate, summarize)?
│ └── Use "Run Once for All Items" (default)
│ ├── JS: access all items via items array
│ └── Python: access all items via _items list
└── Can a native node do this instead (Set, Filter, Sort, Merge)?
└── ALWAYS prefer native nodes — they are faster and maintain item linking// JavaScript — ALWAYS return an array of {json: {...}} objects
return items.map(item => ({
json: { name: item.json.name, processed: true }
}));# Python — ALWAYS return a list of {"json": {...}} dicts
return [{"json": {"name": item["json"]["name"], "processed": True}} for item in _items]// JavaScript — return ONE {json: {...}} object
return { json: { name: $input.item.json.name, processed: true } };# Python — return ONE {"json": {...}} dict
return {"json": {"name": _item["json"]["name"], "processed": True}}NEVER return raw data without thejsonwrapper. The format{json: {...}}is mandatory.
| Variable | Mode | Description |
|---|---|---|
items | All Items | Array of all input items |
$input.item | Each Item | Current item being processed |
$input.all() | Both | All input items from current node |
$input.first() | Both | First input item |
$input.last() | Both | Last input item |
$json | Each Item | Shorthand for $input.item.json |
$binary | Each Item | Shorthand for $input.item.binary |
$("<node>").all() | Both | All items from named node |
$("<node>").first() | Both | First item from named node |
$("<node>").itemMatching(i) | Both | Trace back to matching item in named node |
$execution.id | Both | Current execution ID |
$execution.mode | Both | "test", "production", or "evaluation" |
$execution.customData | Both | Get/set custom execution metadata |
$workflow.id | Both | Workflow ID |
$workflow.name | Both | Workflow name |
$workflow.active | Both | Whether workflow is active |
$now | Both | Current DateTime (Luxon), respects timezone |
$today | Both | Midnight today (Luxon) |
$env | Both | Instance environment variables |
$vars | Both | User-defined variables (all strings) |
$prevNode.name | Both | Name of previous node |
$runIndex | Both | How many times current node has executed |
$jmespath(obj, query) | Both | JMESPath query function |
$ifEmpty(val, fallback) | Both | Null-safe fallback |
$getWorkflowStaticData(type) | Both | Persistent data ("global" or "node") |
Python uses _ prefix instead of $:
| Python Variable | JavaScript Equivalent |
|---|---|
_items | items |
_item | $input.item |
_input | $input |
_execution | $execution |
_workflow | $workflow |
_env | $env |
_vars | $vars |
_jmespath(obj, query) | $jmespath(obj, query) |
_getWorkflowStaticData(type) | $getWorkflowStaticData(type) |
_prevNode | $prevNode |
_now | $now |
_today | $today |
Python-specific rules:
item["json"]["field"] — dot notation failsgetBinaryDataBuffer() is NOT supported in Python// Get binary buffer (JavaScript only, NOT available in Python)
const buffer = await this.helpers.getBinaryDataBuffer(itemIndex, 'data');
// Create new item with binary data from base64
return [{
json: { fileName: 'output.txt' },
binary: {
data: await this.helpers.prepareBinaryData(
Buffer.from('file content', 'utf-8'),
'output.txt',
'text/plain'
)
}
}];NEVER access binary data directly viaitems[0].binary.data.data. ALWAYS usegetBinaryDataBuffer().
| Module | Availability |
|---|---|
Node.js crypto | Cloud + Self-hosted |
moment (npm package) | Cloud + Self-hosted |
| Luxon (via expressions) | Cloud + Self-hosted |
| External npm modules | Self-hosted only (requires env config) |
ALWAYS use $("<node>").itemMatching(index) in Code node — NOT $("<node>").item:
// Correct — Code node item tracing
const originalData = $("HTTP Request").itemMatching(0).json;
// Wrong — .item does not work reliably in Code node
// const originalData = $("HTTP Request").item.json;// Try-catch pattern for Code node
try {
const value = items[0].json.requiredField;
if (!value) throw new Error('requiredField is missing');
return [{ json: { result: value } }];
} catch (error) {
// Return error as data (workflow continues)
return [{ json: { error: error.message } }];
}ALWAYS prefer native nodes for these operations:
| Operation | Use Instead |
|---|---|
| Filter items | Filter node |
| Set/rename fields | Edit Fields (Set) node |
| Sort items | Sort node |
| Remove duplicates | Remove Duplicates node |
| Limit items | Limit node |
| Split arrays | Split Out node |
| Merge data | Merge node |
| Date/time formatting | Expressions with Luxon |
| Simple conditionals | IF / Switch node |
Native nodes are faster (no sandbox overhead) and maintain automatic item linking.
n8n-io/n8n-docs (main branch)packages/nodes-base/nodes/Code/Code.node.tsdocs/data/expression-reference/docs/data/specific-data-types/binary-data.md~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.