Nodes/ComfyUI-SaturnNodes/πŸͺ ⚑ Run Local File
ComfyUI Node

πŸͺ ⚑ Run Local File

Run a local script from a workflow β€” with two locks on the door

By KOFibltoΒ·Created 2 months agoΒ·Updated 2 days agoΒ· 1
πŸͺ ⚑ Run Local File
  • trigger
  • stdout
  • stderr
  • exit_code
  • success
  • passthrough
β—„file_pathβ–Ί
β—„parametersβ–Ί
β—„working_directoryβ–Ί
β—„run_modeSynchronous (Wait for Output)β–Ί
β—„timeout60β–Ί

There comes a point in every workflow where the last step isn't a node. Stripping metadata for a client delivery, muxing with ffmpeg, pushing finished renders to a NAS, firing a notification script. This node runs a local script or executable from inside the graph and hands you back what it printed.

It's also, unavoidably, the scariest category of node in ComfyUI: "run a local file" is exactly what an attacker would want in a workflow you downloaded because it looked neat. So this node ships with two locks, and understanding them is the whole article.

The two locks

A global switch, off by default. Allow Local File Execution lives in ComfyUI's settings under the pack's ⌨ Security section. With it off, the node refuses to run anything and returns exit_code -1 with an error string telling you where the switch is. It's an explicit opt-in for the whole install, not per node.

A per-node button, also off by default. On the node there's an ⚑ Authorize Run (5 min) button you click on the canvas. Clicking it grants a single-use token to that node, valid for five minutes, and it's stored in server memory only. The token is consumed when the node executes, so re-queueing means clicking again. It's also bound to the script you authorized: change file_path after authorizing and the run is refused.

The reason it's a button rather than a checkbox widget is the interesting bit. A widget is part of the workflow JSON, and workflow JSON travels - inside shared graphs, inside the metadata chunk of a PNG you downloaded. Consent that travels can be forged; an in-memory click on your own canvas can't be shipped to you inside a file.

Path rules

The script must live inside ComfyUI/scripts/, so file_path is a relative path: process.sh, tools/convert.bat. Subfolders are fine as long as they resolve inside that directory; absolute paths and anything containing .. are rejected before a process is spawned. The directory is created if missing, but the pack ships no scripts - you supply the file.

How it actually runs

parameters is parsed with shell-safe argument splitting and passed as an argument list - there's no shell involved, so &&, | and ; are just characters, not chaining. On Windows, .bat/.cmd go through the command interpreter and .ps1 through PowerShell with -NoProfile -ExecutionPolicy Bypass -File (needed because local scripts are blocked by default machine policy). On Linux and macOS, .sh runs via /bin/bash and anything else runs as an executable.

run_mode is the fork in behaviour. Synchronous (Wait for Output) runs the process, captures stdout and stderr, and polls ComfyUI's interrupt flag while it waits, so cancelling the queue kills the process tree (taskkill /F /T on Windows) instead of leaving a stray ffmpeg chewing CPU. Asynchronous (Background) launches detached and returns immediately: no output, timeout ignored, and success just means "it launched."

timeout (default 60 seconds, 0 = unlimited) only applies to synchronous runs. Exceeding it, or being blocked by a guard, gives exit_code -1.

Inputs and outputs

file_path is the only required input. Optional: parameters, working_directory (also confined to scripts/, blank = the script's own folder), run_mode, timeout, and trigger - a wildcard input that exists purely for ordering. Wire something from whatever must finish first (an image from your save node, for instance) into trigger, and the graph's dependency order puts your script after it.

Outputs: stdout, stderr, exit_code, success (true when the exit code is 0), and passthrough - whatever you fed into trigger, handed onward untouched so you can chain more nodes after the script.

Install

ComfyUI Manager β†’ search SaturnNodes, or:

cd ComfyUI/custom_nodes
git clone https://github.com/KOFiblto/ComfyUI-SaturnNodes
mkdir -p ComfyUI/scripts

The scripts folder is created if it's missing; drop your file in it, restart, and enable the security toggle. No dependencies beyond the pack's Pillow/numpy/piexif trio. Category: πŸͺ SaturnNodes/Automation.

Where people get burned

"Execution Blocked: Local file execution is disabled by default." That's lock one. Settings β†’ the pack's Security section β†’ enable it.

"Node has not been authorized." Lock two. Click the authorize button on the node itself - not in a menu - and queue within five minutes. Authorization has expired (5-minute timeout) means exactly that. If you edited file_path after clicking, you'll get a script-mismatch rejection; re-authorize.

A headless or remote run can never authorize. The button is a canvas interaction in your browser, so a workflow containing this node will always block when run through the API, from a script, or on a cloud instance with no one clicking. That's the design, not a bug - but it means this node is for your machine, not for a batch pipeline on a rented GPU.

exit_code -1 is not your script's code. -1 means blocked or timed out; real exit codes only come from runs that cleared both locks. And async mode gives you no stdout, no stderr, and a success that means "launched" - stay synchronous if you need the output.

It is not a sandbox. The script runs with your user account and full filesystem access. The locks stop a workflow from conscripting your machine; they constrain nothing inside the script you chose to run. Given that ComfyUI has no code review for custom nodes and installing a pack means executing its code, keep the "whose script is this?" question sharp.

CategoryπŸͺ SaturnNodes/Automation

Inputs (6)

NameTypeDefaultDescription
file_pathSTRINGScript or binary to execute. MUST be located inside 'ComfyUI/scripts/'. Subfolders (e.g. tools/process.bat) are permitted. Absolute paths and directory traversal ('..') are strictly blocked.
parametersoptSTRINGOptional command-line arguments passed to the script. Parsed safely without shell expansion.
working_directoryoptSTRINGExecution working directory. MUST be located inside 'ComfyUI/scripts/'. Leave empty to default to the script's own folder.
run_modeoptCOMBOSynchronous (Wait for Output)2 options: Synchronous (Wait for Output), Asynchronous (Background)
timeoutoptINT600–3600Max execution time in seconds (0 = unlimited). Ignored in asynchronous mode.
triggeropt*Optional passthrough wire to sequence execution in your workflow.

Outputs (5)

NameTypeDescription
stdoutSTRINGβ€”
stderrSTRINGβ€”
exit_codeINTβ€”
successBOOLEANβ€”
passthrough*β€”