SafetyCard Request a review

Qwen-Agent

Alibaba Qwen team's Python framework for building LLM agents with function calling, a Docker code interpreter, RAG, MCP and a Gradio UI.

github.com/QwenLM/Qwen-Agent · 2026-10-04 · 31a4d36

Defense-in-depth score

2.1 / 10

Qwen-Agent is a capable framework with almost no safety primitives of its own. Every model-chosen tool call runs immediately with no approval step, argument checks are limited to JSON types, and document and web tools fetch any URL or read any local file. The Docker code interpreter is a real but unhardened boundary (root, full network, read-write mount), and an exported math agent runs code directly on the host. Treat any deployment that reads untrusted content as able to leak data and change files unattended.

Safest setup

Qwen-Agent starts agents with no tools, stops each run after 20 model calls, and runs its code interpreter in a Docker container that receives none of your host's environment variables. Beyond that the defaults are thin: no approval step, no argument limits beyond JSON types, and no durable record, so the safest setup keeps the tool list short and builds the boundaries around the process yourself.

SetupHowWhat it gives you
Scoped, low-limit keysGive the process only the model and search API keys this agent needs, each scoped where the provider allows and with a spending limit set at the providerWhatever the agent does, it reaches only the accounts and spend you chose, not everything in your shell C1
Only the tools neededKeep the default function_list=None and list only the tools the task usesThe model can call only the tools you chose for this agent C3
The Docker code interpreterRun model-written code through code_interpreter, with work_dir in its config set to an empty directory kept for itCode runs in a container that sees only that directory, and the mount stays where you put it C4
A clean working directoryStart the app from a directory with no .env file you didn't write, and point QWEN_AGENT_DEFAULT_WORKSPACE at a directory for this app aloneSettings come only from you, and the document cache holds only this app's content C6
Pinned MCP serversIn mcpServers, name an exact package version for each server and pass only the env it needsEach server runs the code you chose, with only the credentials you gave it C7
A model-call budgetKeep QWEN_AGENT_MAX_LLM_CALL_PER_RUN at its default of 20, or lower it for short tasksEach agent loop ends after a fixed number of model calls C10
Its own container or VMRun the agent process in a container or VM whose network reaches only the hosts the task needsAn outer boundary around in-process tools and MCP servers, and a narrow path for data to leave C5
A run record on diskSave the message list each run returns, which holds every tool call and result, to storage the agent can't modifyA record of what the agent did that outlives the process C9

Handling data

  • Leave QWEN_AGENT_DEBUG unset where logs are shared; it writes full model inputs unredacted.
  • Parsed documents stay cached in the workspace directory across sessions; deleting that directory clears them.

Key gaps (1)

  1. Untrusted web/document content, any local file readable by the process, and unrestricted egress combine in one unattended session with no gate. C5 · Untrusted input blast radius

Criteria

C1 Identity & least privilege

0.05 / 1.00

Qwen-Agent has no notion of an agent identity or per-request authorization. It runs with the full authority of the Python process: API keys come from environment variables or config, tools build their own HTTP clients, and file-handling tools read any local path the OS user can read. Nothing narrows that ambient authority or checks a request against a policy, so a hijacked agent acts with everything the process holds.

C2 Approval gates

0.00 / 1.00

There is no human-approval step anywhere in the framework. The agent loop hands every model-generated tool call straight to the tool, including code execution, file writes and deletes through the storage tool, and any MCP tool. Developers would have to wrap tools themselves, and nothing in the framework helps them do so. A wrongly chosen call simply runs.

C3 Tool & action scoping

0.25 / 1.00

Tool arguments are checked only against their JSON schema types, and not every tool does even that. The document and web tools accept any URL or local path, follow redirects and fetch internal addresses; the storage tool's path handling is not a strict boundary. Code-interpreter and MCP calls skip schema validation entirely. No tools are on by default, but the README's first example turns on code execution.

C4 Code-execution isolation

0.42 / 1.00

The built-in code interpreter runs code in a local Docker container and refuses to start if Docker is missing, which is a real boundary. But the container is a stock image running as root with default capabilities, full network egress, and the work directory mounted read-write, and its kernel ports are published on all host interfaces. The framework also exports a math agent whose Python executor runs code directly on the host with exec, and MCP stdio servers run on the host. The mounted host directory can be redirected by an environment variable that a .env file in the working directory can supply.

C5 Untrusted input blast radius

0.00 / 1.00

Nothing limits what a hijacked agent can do. Web pages, documents, and MCP tool results and descriptions enter the conversation as ordinary function messages with no provenance marking, and no capability is disabled or gated once untrusted content has been read. With the tools the README demonstrates (document/web reading plus a networked code interpreter), injected text can make the agent send data out and modify files with no human involved.

C6 Memory, context & configuration integrity

0.13 / 1.00

Qwen-Agent has no long-term agent memory, but it persists parsed documents in a shared workspace cache keyed only by URL, with no per-user separation or expiry, so content fetched once (including attacker-controlled pages) is re-served to later sessions and users. The storage tool, if enabled, lets the model write arbitrary files that later reads return. The MCP manager also calls load_dotenv(), silently loading a .env file from the current working directory into the process environment.

C7 Third-party extensions

0.28 / 1.00

Third-party code enters mainly through MCP servers that the developer lists in code. Nothing is enabled by default and a workspace file cannot add servers, but the README example launches unpinned packages with 'npx -y', there is no version pinning or integrity check, and server-provided tool descriptions go straight into the model's tool list. Stdio servers run as separate host processes; the MCP SDK passes them a minimal default environment unless the config supplies one.

C8 Secrets & sensitive-data protection

0.25 / 1.00

API keys are read from environment variables or config and kept in plain process memory. There is no redaction anywhere: debug logging prints full model inputs, and tool exceptions with full tracebacks are returned to the model. On the positive side there is no telemetry, the default log level is INFO, and the code container is started without host environment variables.

C9 Audit & traceability

0.25 / 1.00

The framework does not record tool calls. Calls and results appear in the message list returned to the caller, but nothing is persisted, and the only log lines are scattered INFO messages (downloads, container start) and warnings when a tool raises. There is no actor attribution, correlation across sub-agents, or durable trail.

C10 Limits & kill switch

0.42 / 1.00

Each agent run is capped at 20 model calls by default, and code-interpreter executions time out after 30 seconds. There is no token, cost, or wall-clock budget, MCP calls and URL downloads wait indefinitely, and a router or group chat starts each sub-agent with a fresh 20-call budget. On exit the framework stops Docker containers and terminates MCP processes.