SafetyCard Request a review

OpenAgents (XLang)

Self-hosted web platform with a data agent (Python/SQL code interpreter), a plugins agent (200+ third-party API plugins), and a web-browsing agent driven through a Chrome extension.

github.com/xlang-ai/openagents · 2026-10-04 · ff2e464

Defense-in-depth score

1.8 / 10

As shipped, OpenAgents runs model-written Python directly inside its backend process, with the operator's OpenAI key in the environment and no approval step. Any content that hijacks the model can execute code as root in the container and read every user's data; access control on the backend API is not locked down. The optional Docker code interpreter helps, but it is off by default and not hardened in this repo.

Safest setup

OpenAgents ships few protections on by default: model-written Python runs inside the backend with no approval step, and access to the backend API is not locked down. The one mechanism to turn on is the Docker code interpreter, so the safest setup pairs it with scoped keys, a private deployment and containment you add yourself.

SetupHowWhat it gives you
Dedicated, low-limit keysGive the deployment its own OpenAI key with a spending limit set at the provider, a Kaggle account used for nothing else, and save only the plugin keys you need, scoped or read-only where the service allowsA hijacked agent reaches only the spend and services you set aside for it, not your own accounts C1
A private, authenticated entry pointKeep the backend and frontend ports on a private network behind an authenticating proxy, with one deployment per trusted group of usersOnly people you chose can reach the agent, and stored conversations and files stay within that group C1
The Docker code interpreterUncomment the code_interpreter service without its added capabilities and set CODE_EXECUTION_MODE=docker for the backendModel-written Python runs in a separate kernel container that never holds the OpenAI key C4
Only the tools neededIn the data agent's tool picker, select Python only for tasks that need codeConversations that don't need code never run model-written Python C3
The iteration capKeep the default max_iterations of 5Every agent turn ends after a small, fixed number of steps C10
A separate browser profileInstall the web agent's extension in a browser profile signed in to nothing you would not hand to the agentClicks and form fills the agent sends land only in sessions you set aside for it C2
A pre-fetched embedding modelDownload the embedding model at a revision you have checked into the backend's model cache before first start, and run with Hugging Face downloads turned offThe backend loads only model weights you chose, and they can't change between restarts C7
Its own VM with limited egressRun the whole stack on a VM that holds no other data, with outbound traffic limited to OpenAI and the plugin hosts you useAn outer boundary around in-process code and plugins, and a narrow path for data to leave C5

Handling data

  • Request bodies and generated code are logged at DEBUG and TRACE by default; store runtime.log and container output like the conversations they hold.
  • Plugin keys users save are kept in plaintext in Redis and MongoDB; protect and back up those stores like a secrets store.
  • Copy MongoDB conversation records regularly to storage outside the stack, so the record survives anything the agent's own code changes.

Key gaps (4)

  1. Model-generated Python runs in-process in the backend by default. C4 · Code-execution isolation
  2. Code execution (the most powerful path) has no approval gate. C2 · Approval gates
  3. Hijacked sessions can exfiltrate secrets and take irreversible actions unattended. C5 · Untrusted input blast radius
  4. Unpinned Hugging Face model is downloaded and deserialized in-process at startup; plugins run in-process. C7 · Third-party extensions

Criteria

C1 Identity & least privilege

0.05 / 1.00

Access control on the backend API is not locked down. Every tool runs with the operator's own OpenAI key, Kaggle key, unauthenticated MongoDB/Redis, and any third-party plugin API keys users saved, all as root in the backend container. There is no per-request authorization of tool use.

C2 Approval gates

0.00 / 1.00

There is no human approval step anywhere in the backend. Model-generated Python and SQL run as soon as the model emits them, plugin API calls (including Zapier actions and a Netlify deploy endpoint) fire directly, and the web agent returns click and type actions for the user's live browser without a confirmation step in the server. The most powerful action, arbitrary code execution, is ungated by default.

C3 Tool & action scoping

0.25 / 1.00

The data agent's main tools accept arbitrary model-written Python and SQL with no argument validation. Plugins are narrower: each one only calls fixed endpoints on a fixed host, and the model's chosen endpoint must exist in the plugin's table; web-agent actions are type-checked. Python is selected by default in the shipped frontend, and the tool set is chosen per request by the client rather than restricted to read-only.

C4 Code-execution isolation

0.40 / 1.00

In the default configuration (CODE_EXECUTION_MODE=local, set in both app.py and docker-compose.yml) model-generated Python runs through IPython's run_cell in the backend's own worker process. A code-safety check exists but is not a strict boundary. The code therefore runs as root in the backend container with the OpenAI key in its environment, full network access, unauthenticated MongoDB/Redis, and write access to the application source and every user's files. An optional Docker code-interpreter mode sends code to a separate kernel container, but it is commented out in the compose file, uses an image not in this repo, adds NET_ADMIN/SYS_PTRACE capabilities, and shares the backend data volume.

C5 Untrusted input blast radius

0.00 / 1.00

The agents read plenty of content their user did not write: uploaded files and databases, Kaggle datasets, third-party plugin API responses, and arbitrary web pages in the web agent. None of it is marked or treated differently; tool results go straight back into the model context. A hijacked session can run arbitrary Python with network access and the OpenAI key, call write-capable plugins, and drive the user's browser, with no human in the loop; frontend output rendering is not hardened either.

C6 Memory, context & configuration integrity

0.07 / 1.00

Conversation history, including tool outputs that may carry injected text, is stored in MongoDB/Redis and reloaded as chat memory each time the conversation continues, with no validation or provenance. Uploaded and generated files persist in the backend data folder and can be reused as grounding data later. Per-user isolation of stored history and files is not a complete boundary. There are no auto-loaded instruction or config files from a workspace.

C7 Third-party extensions

0.07 / 1.00

The 232 plugins are vendored Python modules shipped in the repository and loaded in-process with importlib; they are part of the pinned code rather than downloaded at runtime, though each one sends data to a third-party API. At startup the plugin selector downloads the hkunlp/instructor-large embedding model from Hugging Face with no pinned revision or hash, and (through the sentence-transformers/InstructorEmbedding loader) deserializes its weights in the backend process. Runtime pip installs of helper packages are also unpinned. Nothing runs third-party code in a separate or confined process.

C8 Secrets & sensitive-data protection

0.15 / 1.00

Secrets come from environment variables and files: the OpenAI key is set in the compose file, the Kaggle key is written into the image at build time, and third-party plugin API keys are stored in plaintext in Redis/MongoDB. The backend API's handling of stored plugin keys is not locked down. Full request bodies and generated code are logged at DEBUG/TRACE by default, and the only protection is loguru's diagnose=False on file sinks. Model-run code can read every secret from the process environment.

C9 Audit & traceability

0.33 / 1.00

Each finished chat turn is written to MongoDB with the intermediate steps (tool used, generated code, results) and the final answer, and loguru writes runtime logs. This gives a usable transcript, but it is written only when the stream completes, carries no real actor identity, and lives in an unauthenticated database and log directory that the model's own code can modify.

C10 Limits & kill switch

0.50 / 1.00

The agent loop stops after 5 iterations by default and runs in a child process that is terminated after a period without output (90 s for the data agent) or when the user hits stop. There is no wall-clock limit on the loop itself, no token or cost budget, no rate limiting, and the web agent's step loop is driven by the browser extension with no server-side cap. Termination kills the worker process but not anything it spawned.