CVE-2026-41264: How a Regex Let Prompts Run Code in Flowise

Published October 2, 2026

By Charles Givre

LLM securityprompt injectionCVEFlowiseAI red-teaminginsecure output handling
import pandas as np, os as pandas
pandas.system("xcalc")

Those two lines are the whole bypass in CVE-2026-41264, a CVSS 9.8 bug in Flowise, the open source drag-and-drop builder for LLM apps. Flowise’s CSV Agent asked a model to write pandas code, checked the code with a regex, and ran it on the server. The regex was meant to stop any import other than pandas or numpy. It looked at the first module name after import and stopped there. Alias os as pandas and the check passes.

The bug is worth studying because of what happened after it was reported. The fix in 3.1.0 was a stricter regex. Over the next three months the validator grew to 390 lines, picked up five more CVEs, and in June Flowise deleted the feature. If you build or test anything that runs model-generated code, that history is the lesson.

The data path

Trend Micro’s Zero Day Initiative reported the bug as ZDI-CAN-29411. The researchers credited are Dre Cura and Nicholas Zubrisky of TrendAI Research. Their analysis is published in full in the Flowise advisory GHSA-3hjv-c53m-58jj. The flow inside CSV_Agents.run(), as the advisory quotes it:

  1. Load the uploaded CSV in Pyodide and extract column names and dtypes with pandas.
  2. Fill a prompt template with those dtypes and the user’s question. The template ends with a “Security:” paragraph telling the model not to use import, exec, eval, open, os or subprocess.
  3. Take the model’s reply, strip Markdown fences, and store it as pythonCode.
  4. Run validatePythonCodeForDataFrame(pythonCode), a loop over 34 forbidden regexes.
  5. Execute import pandas as pd\n plus pythonCode with pyodide.runPythonAsync().

Step 2 is a request to the model, not a control. Step 4 is the only real check, and step 5 is where it fails. An unauthenticated attacker reaches all of it because /api/v1/prediction/ sits on Flowise’s WHITELIST_URLS. The ZDI proof of concept puts a prompt injection in the question field asking the model to reply with the payload above. The advisory says it was tested against Llama 3.2 in Ollama and can take several attempts, which is normal for anything that depends on model output.

There is also a path with no model at all. A logged-in user creates a chatflow whose ChatOllama node points at a server they control, and that server answers /api/chat with Python. The regex is the only thing between that reply and the interpreter.

The version range hides one detail. Steps 2 and 4 came from PR #5701, merged on 2026-02-06, three days after 3.0.13 shipped. The 3.0.13 release has no validator and no “Security:” paragraph: model output went straight to runPythonAsync(). ZDI’s bypass beat the code headed for the next release. Anyone on 3.0.13 or earlier was exposed without the alias trick. The same node had a second bug, CVE-2026-41137 (CVSS 8.8): a custom read call set by the chatflow builder was pasted into Python as pd.${customReadCSVFunc} with no checks.

Why Pyodide did not contain it

Pyodide is CPython compiled to WebAssembly, and it is easy to assume that means isolation. Inside Node it does not. The Pyodide Python API docs describe the js module as “the global JavaScript scope.” In a Node process that scope leads to child_process. CVE-2026-69255 describes exactly that chain: use Pyodide’s js bridge to load child_process, then run commands as root in the Flowise container. WebAssembly limits memory access. It does not limit what the host hands the guest.

The fix that kept failing

Version 3.1.0, released 2026-03-16, was the first release with any validator. It shipped with a stricter import rule from PR #5879 (any use of the word import fails), four more reflection patterns, and the custom read field run through the same check. That closes the alias trick and CVE-2026-41137. The CVE records in our AI CVE index show what came next, all fixed in 3.1.3:

CVE CVSS Bypass
CVE-2026-69256 8.8 pd.read_pickle() in the custom read field deserializes a payload without matching any forbidden word
CVE-2026-69255 8.8 CSV contents interpolated into base64_string = "...", so a quote in the data breaks out
CVE-2026-70470 9.8 Unicode homoglyphs in dunder names
CVE-2026-70477 9.8 Prompt injection that gets model-written code past the denylist, the same path as CVE-2026-41264
CVE-2026-73487 9.8 pd.read_json() left open, giving data exfiltration and SSRF

The homoglyph bug is the one to remember. JavaScript’s \b only knows ASCII word characters. Python normalizes identifiers with NFKC at parse time, as PEP 3131 specifies. Spell __class__ with MATHEMATICAL BOLD SMALL A (U+1D41A) in place of the a and the two languages disagree about what the string says:

/\b__class__\b/.test("__cl\u{1D41A}ss__")   // false: validator passes it
import unicodedata
unicodedata.normalize("NFKC", "__cl\U0001D41Ass__")   # '__class__'
exec("x = ().__cl\U0001D41Ass__")                     # x is <class 'tuple'>

The commit history reads the same way. Flowise blocked read_pickle and class definitions on 2026-04-27 (PR #6257), restricted the CSV field to a literal read_csv() call on 2026-05-05 (#6313), and added homoglyph and backslash line-continuation normalization on 2026-06-05 (#6476). On 2026-06-10, PR #6499 removed the CSV Agent, the Airtable Agent, the 390-line validator, and its 599-line test file. That shipped in 3.1.3 on 2026-06-25.

So NVD’s “fixed in 3.1.0” is accurate for this CVE and misleading for your exposure. If a CSV Agent ran on 3.1.0 through 3.1.2, it was still exploitable.

If you run Flowise

Check the version first. npm ls -g flowise --depth=0 covers npm installs. For containers, docker ps --format '{{.Image}}' | grep -i flowise shows the tag. Anything below 3.1.3 with a CSV or Airtable Agent in use is exposed.

Then find the flows. The default SQLite store lives at ~/.flowise/database.sqlite, and the node names are csvAgent and airtableAgent:

sqlite3 ~/.flowise/database.sqlite \
  "SELECT id, name, isPublic, apikeyid IS NULL AS no_key
   FROM chat_flow
   WHERE flowData LIKE '%csvAgent%' OR flowData LIKE '%airtableAgent%';"

Rows with no_key = 1 were reachable without credentials. Those flows break on upgrade, so warn their owners first.

To hunt, pull user messages sent to those chatflows and look for code, pandas I/O calls, and characters outside printable ASCII:

sqlite3 ~/.flowise/database.sqlite \
  "SELECT createdDate, chatflowid, substr(content, 1, 200)
   FROM chat_message
   WHERE role = 'userMessage'
     AND (content LIKE '%import%' OR content LIKE '%read_pickle%'
          OR content LIKE '%read_json%' OR content LIKE '%\_\_%' ESCAPE '\'
          OR content GLOB '*[^ -~]*');"

The last clause also matches ordinary newlines and non-English text, so expect noise. The authenticated path leaves no injection in chat_message. For that, review chat model nodes whose base URL points somewhere you do not recognize.

Process telemetry catches both paths. Exploitation shows up as T1190 followed by T1059.004: a node process spawning a shell. A Falco rule:

- rule: Shell or network tool spawned by Flowise
  desc: Node process in a Flowise container started a shell or downloader
  condition: >
    spawned_process and proc.pname = node
    and container.image.repository contains "flowise"
    and proc.name in (sh, bash, dash, curl, wget, nc, python3)
  output: "Flowise child process (cmd=%proc.cmdline parent=%proc.pcmdline image=%container.image.repository)"
  priority: CRITICAL

On the ATLAS side, the injection is AML.T0051 and the code execution is AML.T0050, Command and Scripting Interpreter.

What the CSV Agent should have been

OWASP LLM05:2025 Improper Output Handling covers this class of bug: model output passed to an interpreter without being treated as untrusted. CVE-2026-41264 is a textbook case. The fix is the same as for any untrusted code. Run it in a separate process with no network, no credentials, a read-only copy of the data, and a seccomp or gVisor boundary. A denylist on Python source is a losing game. Python has too many ways to name the same object.

Isolation has limits too. A sandboxed interpreter can still return every row of the dataframe to whoever asked, and CVE-2026-73487’s read_json SSRF is a reminder that egress needs blocking as well. Sometimes the right answer is the one Flowise reached: remove the feature.

None of the bypasses needed machine learning knowledge. An alias, a pickle, a Unicode quirk and an unescaped quote are standard application security findings. That is why the AI Red-Teaming course asks for security testing experience and not a data science background. When the LLM’s output feeds an interpreter, testing it is the same as testing any other input validator.

Frequently Asked Questions

Which Flowise versions are affected by CVE-2026-41264?
The GitHub advisory GHSA-3hjv-c53m-58jj lists flowise and flowise-components 3.0.13 and earlier, patched in 3.1.0. That range is correct for this specific bypass, but CSV Agent instances on 3.1.0 through 3.1.2 were still exploitable through later bypasses (CVE-2026-70470, CVE-2026-70477, CVE-2026-73487 and others). Flowise removed the CSV Agent and Airtable Agent nodes in 3.1.3, released 2026-06-25. Treat 3.1.3 as the minimum safe version.
Does exploiting CVE-2026-41264 require authentication?
Not for the prompt injection path. Flowise lists /api/v1/prediction/ in its WHITELIST_URLS, so anyone who can reach a chatflow's prediction endpoint can send it a question unless the chatflow has an API key assigned. A second path in the advisory needs an authenticated user who can build a chatflow pointing at an attacker-run model server, which skips the LLM entirely.
Would a prompt injection filter or moderation node have stopped this?
No. The CSV Agent supported optional input moderation nodes, and the advisory's code annotations note they may not catch every injection. The authenticated path does not involve a real LLM at all: the attacker's fake model server returns the Python directly. The flaw is that model output reached an interpreter with access to the host. Filtering the input does not change that.

Related posts

Want to learn more?

Explore our hands-on AI and cybersecurity training courses.

View Courses