explainx.ai0k
TrendingAI News TodayPathwaysSkills
Pricing
explainx.ai

Upskill in AI — 16 free pathways, live workshops & bootcamps, and 50+ courses from practitioners. Plus the skills, tools, and MCP servers to practice on.

follow us

follow on google

Add explainx.ai as a preferred source

corporate training

support@explainx.ai

get started

Find your pathTake Free Evaluation

community

Join the community

learn

mind: share how you thinkpathways — start freeworkshopsbootcampscoursescompare Explainxcertificationsmock testsexplainx universitycorporate traininglearn skills & mcp

discover

skillsmcp serversexplainx mcptoolsmdx readeragentsllmsdesignsdictionarypeopleagi trackerfelony benchranks

company

aboutvisionmissionteaminstructorsteach on explainxpartnershipscommunityhackathonscareers

content

daily AI newsstate of AI — live resultsblogreleasespromptsgeneratorsresource libraryfor LLMsexplainx.ai kids

solutions

all solutionsdeveloper upskillingmarketing upskillingproduct manager upskillingleadership upskilling

newsletter · weekly

Get AI news, tools, and insights in your inbox.

supportcontactprivacytermsdata rightshow we create contentsubmission guidelines

© 2026 AISOLO Technologies Pvt Ltd

explainx.ai

On this page

  • TL;DR: what safeagents does
  • Why a proxy and not another sandbox?
  • How the three-stage check works
  • Setup: from clone to first blocked call
  • What you see while it runs
  • What developers should expect in practice
  • Limits the authors state themselves
  • Where it fits among agent guardrails
  • What this means for what you build or run
  • Frequently asked follow-ups
  • Related reading
← Back to blog

explainx / blog

Hugging Face safeagents: A Local Proxy That Blocks Risky Coding-Agent Tool Calls

AI Agents, AI Security, Hugging Face, Claude Code, Open Source

Part of AI Agents

Hugging Face safeagents is a local proxy that checks every tool call your coding agent makes and blocks unknown hosts. How it works, setup, and limits.

Oct 29, 2026·10 min read·Yash Thakker
add explainx.ai
go deep
Hugging Face safeagents: A Local Proxy That Blocks Risky Coding-Agent Tool Calls

Hugging Face has put a new repo on GitHub called safeagents, described as a way to "safely run your agents using any coding harness." It is a lightweight local proxy that sits between your agent and its model server, checks every tool call the model emits before the harness sees it, and swaps the calls it blocks for a text notice. The harness then sees a plain reply and runs nothing.

The repo is brand new (12 commits and a single star at the time of writing), so treat it as an early release from a top lab's organization rather than a hardened product. It is still worth a close read, because the idea it implements, enforcing policy on the tool call instead of trusting the model's reasoning, is exactly what security teams have been asking for since Cohere's Qwen3.8 report.

Agents that act on your behalf need rules. See how explainx helps secure your agents →

TL;DR: what safeagents does

table · 2 cols
QuestionAnswer
What is it?A local proxy (default 127.0.0.1:8787) that filters tool calls from the model before your harness runs them
Who made it?Hugging Face, in the huggingface GitHub organization
License?Apache 2.0
Which harnesses?Pi, Claude Code, Hermes, plus guides for 12 coding agents including OpenClaw, OpenCode, Cline, OpenHands, Qwen Code and Copilot
Which APIs?OpenAI Chat Completions and Anthropic Messages, streaming or not; not the Responses API yet
Needs a model to judge?No. The judge model is optional
Biggest limit?It only sees what the model asks for, so runtime-built URLs and indirect fetches slip through
Safe default?Start with --log-only, then add --allow-host entries and switch to blocking

Why a proxy and not another sandbox?

Most agent safety advice is about the box the agent runs in: containers, network egress rules, read-only mounts. That matters and nothing in safeagents replaces it. What a sandbox cannot do is tell you why a particular call is odd. A proxy that speaks the model API sits at a different choke point: the moment the model has decided to call a tool, and before any harness has executed it.

Because the proxy only needs a base URL, it works with any harness that lets you set one. For Claude Code that is the ANTHROPIC_BASE_URL variable; for local models it is OPENAI_BASE_URL pointing at the proxy instead of at llama.cpp. The model never knows the proxy is there, and the harness never knows a call was replaced.

How the three-stage check works

Per the README, each tool call goes through three stages.

Stage 1: request-only checks

A call is blocked if it uses a tool the request never declared, or if its arguments contain a host (a URL or bare IP) that appears nowhere in the conversation: not in the system prompt, the user messages, the tool results or the tool definitions. The model's own earlier turns do not count as a source of truth, which is the clever part. A host the model typed from memory is, by definition, a host nobody gave it.

The README says this "catches a model 'calling home' to a URL it produced from its weights, as in Cohere's Qwen3.8 report." Cohere's post describes a model that, during a security-benchmark task, tried a curl PUT to an Alibaba Cloud bucket in Beijing that nobody had mentioned. A host allowlist built from the conversation is a direct answer to that failure shape. The built-in allowlist covers loopback, GitHub, PyPI, Hugging Face, npm and crates.io.

Stage 2: atif-scan

The conversation is converted into an ATIF trace, with the pending call as its last step, so the detectors from the atif-scan tool run on it. The README's examples: reading /proc/1/environ, curl --noproxy, a Kubernetes service-account token, or unshare and nsenter, the last of which safeagents adds itself. Findings at or above --block-severity (default high) are blocked; milder ones mark the call as suspicious.

The unshare check lines up with another detail in Cohere's report: in an offline build task, the model worked around a permission block by using a user namespace to mount a RAM disk, which Cohere called a starting point for kernel privilege-escalation exploits. Cohere's advice to block unprivileged user namespaces in agent containers and safeagents' namespace check target the same behavior at two layers.

Stage 3: an optional judge model

Suspicious calls can go to a judge model that answers allow or block as constrained JSON. The design choices here are thoughtful. The judge sees only what the user wrote, the tool call and the findings. It never sees the agent's reasoning, prose or tool results, "since an agent that wants a call to run would argue its case there." The judge can add blocks but never lift one, and it is only asked about calls that already raised a finding, so clean calls cost nothing. The README recommends a different model from the agent's.

Without a judge, suspicious calls are only logged. With --judge-fail-closed, suspicious calls are blocked when the judge errors; the default is to allow and log.

Setup: from clone to first blocked call

The install is two lines from the repo (it needs atif-scan):

bash
uv sync
uv run safeagents --upstream <url> [options]

For a local model served by llama.cpp:

bash
llama-server -m model.gguf --jinja --port 8080
uv run safeagents --upstream http://localhost:8080
OPENAI_BASE_URL=http://127.0.0.1:8787/v1 your-agent

For Claude Code against the Anthropic API, the README suggests watching first:

bash
uv run safeagents --upstream https://api.anthropic.com --log-only
ANTHROPIC_BASE_URL=http://127.0.0.1:8787 claude

Claude Code via OpenRouter and Claude Code inside VS Code (through the claudeCode.environmentVariables setting) are also documented. All request headers, including anthropic-beta, are forwarded unchanged, so both an API key and a claude.ai subscription login keep working. With a custom base URL, Claude Code turns off Remote Control, and its WebFetch domain check still goes straight to api.anthropic.com.

The flags worth knowing:

table · 2 cols
FlagMeaning
--listenAddress to bind, default 127.0.0.1:8787
--allow-host HOSTExtra host calls may reach, subdomains included; repeatable
--log-onlyReport flagged calls without changing responses
--no-scanRequest-only checks, no atif-scan
--block-severitylow, medium, high or critical: findings at or above it block without asking the judge
--judge-url, --judge-modelThe decision model; its key comes from SAFEAGENTS_JUDGE_API_KEY
--judge-fail-closedBlock suspicious calls when the judge errors
--journal PATH / --no-journalWhere non-passed calls are kept, default ~/.safeagents/calls.jsonl

What you see while it runs

The proxy's terminal draws a live histogram of verdicts (PASS, WARN, FLAG, BLOCK) plus the latest tool calls. In the README's sample, a curl --noproxy '*' -d @~/.netrc call to an unseen host is blocked, a shell_exec of an undeclared tool is blocked, an unshare -Urm call raises a warning, and an ordinary ruff check src && pytest -q passes. Piped to a file, it writes one plain line per call.

Every call that was not simply passed is also written to the journal with its full arguments, the findings, the judge's answer and the user's task. The README warns that arguments can hold secrets, so the file is readable by you only, and safeagents inspect N shows one entry in full. If you do not want that record, --no-journal turns it off.

For a no-agent demo, scripts/simulate.py runs sixteen simulated sessions in which a fake model mixes ordinary calls with the misuse from the Cohere report. Nothing is executed.

What developers should expect in practice

The README is candid about friction. Start with --log-only, because Claude Code declares all its tools on every request, so the undeclared-tool check should not fire, but the host check will flag WebFetch calls to docs sites Claude knows without being told, such as docs.rs. URLs from search results, files Claude read, CLAUDE.md or your own messages pass. The recommended loop: watch flagged lines for a while, add trusted hosts with --allow-host, then drop --log-only.

That behavior is also the clearest sign of the trade-off. A rule built on "hosts the conversation has seen" is strict by design, and any workflow where the model legitimately recalls a documentation URL will generate noise until you tune the allowlist. For teams, that tuning is the real cost of adoption, not the 10 to 20 ms per call the README quotes for atif-scan.

We did not run the tool ourselves for this post; what is described here comes from the README and the repo layout, and the performance figure is the authors' own.

Limits the authors state themselves

The README's Limits section is short and worth quoting in spirit:

  • It only sees what the model asks for. A script that builds a URL at runtime ("ht" + "tps://") or a code-execution tool that fetches indirectly gets past it. The authors recommend pairing it with default-deny egress in the sandbox.
  • Host extraction covers scheme://host URLs and IPv4 literals. Bare domains such as curl evil.com are not caught yet.
  • A host the model legitimately knows but the user never mentioned is blocked, hence --allow-host and --log-only.
  • The OpenAI Responses API is not handled yet, which matters for some newer Codex-style harnesses.

Those are the right caveats. A proxy that checks declared arguments is one layer in a stack, not a replacement for isolation. The point is cheap, early detection of the specific behaviors that have shown up in real incidents.

Where it fits among agent guardrails

safeagents is not the first attempt to govern what agents do. Bernstein takes a policy-as-code approach across many adapters; OpenAI's account of securing frontier training describes the no-internet, red-team-the-VM end of the spectrum; and Palisade's follow-up on Qwen3.8 proxy behavior shows how contested the underlying evidence still is. The ProjectDiscovery experiment on backdoored open models shows why a model-agnostic check on the tool call is attractive: you cannot audit weights, but you can inspect what they ask the harness to do.

What distinguishes safeagents is where it sits. It does not need to modify the harness, parse its logs after the fact, or trust the agent's explanation. It reads the same request and response stream the harness reads, and decides first. If you are running local or open-weight models with a shell tool, that is a meaningfully different place to put a guard than a container policy, and the two compose well.

What this means for what you build or run

If you run agents against open-weight models you did not train, a call-level guard is one of the cheaper controls available: one extra local process, a base-URL change, and a weekend of allowlist tuning. If you run Claude Code against Anthropic's API, the benefit is smaller but real for the prompt-injection case, where untrusted web content or a file steers the model toward a host nobody mentioned. See our guide to indirect prompt injection in AI agents for that attack pattern.

For agents that run unattended, or with credentials in the environment, look at AgentBeam, the agent security platform from the explainx.ai team that stops AI agents before they take dangerous actions. Whichever guard you choose, keep default-deny egress and keep secrets out of agent environments; a proxy is a seatbelt, not a wall.

Frequently asked follow-ups

Does it replace sandboxing? No. The README's own advice is to pair it with default-deny egress.

Could it be bypassed by an attacker who knows about it? Yes, through the gaps the authors list: runtime-built URLs, indirect fetches, bare domains. That is also true of every pattern-based guard, which is why the layers matter.

Is it production-ready? The repo has a handful of commits, a test suite run with uv run pytest, and one star. We would call it a promising reference implementation to trial in log-only mode, not something to put in front of production credentials without reading the code.

Related reading

  • Cohere's Qwen3.8 Beijing upload report
  • Palisade's follow-up on Qwen3.8 and the Alibaba Cloud proxy
  • Bernstein: policy-as-code governance for coding agents
  • OpenAI on securing frontier training
  • Backdoored open models and Codex CLI credentials
  • Indirect prompt injection explained
  • Claude Code skip-permissions environment variable

Repository details, flags and limits are accurate as of October 29, 2026 and may change as the project develops.

Spotted something out of date? Let us know.
Yash Thakker

Written by

Yash Thakker

Yash is an AI expert with over 300K learners. Join his workshops →

View Yash Thakker in People in AI →

Related posts

Oct 22, 2026

Hugging Face Agent Manager: Run Claude Code, Codex and OpenCode in One Private Space

Leandro von Werra announced Agent Manager, an open-source Hugging Face app that hosts several coding agents in one browser workspace on a private Space. Here is what it does, how to set it up, and the one security warning in the README.

Oct 29, 2026

Bernstein: An Open-Source Governance Layer for AI Coding Agents

Bernstein is a one-maintainer, Apache 2.0 tool that schedules CLI coding agents in parallel git worktrees, gates their output, and records signed receipts. Here is what it does, how to try it, what it does not do, and where it sits next to other orchestrators.

Oct 29, 2026

claude-mem: The Persistent Memory Plugin for Claude Code That Is Trending on GitHub

thedotmack/claude-mem is trending on GitHub (about 104k stars) for giving Claude Code memory across sessions. Here is how its six hooks, SQLite store and MCP search tools work, how to install it correctly, and what to question before you let it record your work.