Skip to main content

egress-guard

Deterministic, dependency-free detection of two things a task run inside a sandbox has no legitimate reason to do:

  • reaching for the host — the container runtime socket, host memory, the cloud metadata endpoint, the orchestrator's credentials; and
  • contacting a host it never declared — any external host outside the run's own egress allowlist.

It is defensive. It recognises these patterns in order to flag them and stop a run. It performs none of them, and it executes nothing it inspects — every rule is a regular expression over the text of an agent's tool calls and transcript.

from egress_guard import run_detectors

hits = run_detectors(tool_calls, egress_allowlist=["*.example.com"], messages=transcript)
for hit in hits:
    print(hit.category, hit.rule, hit.evidence)

The one rule that matters

Internal is fine; external is not.

A run whose task is to probe or attack its own declared target inside the sandbox is working correctly and must never be flagged — otherwise the guard gets switched off, which is worse than no guard. The alarm is only for reaching outside the declared boundary. So the caller's egress allowlist is not just the enforcement boundary; it is the definition of "external" that the library tests against. With an empty allowlist, every external host is flagged — the correct default for a run that declared no egress.

Offensive-shaped tooling is judged by where it points, not by its name: the same scanner aimed at a declared internal target and at a public address are different events, and only the second is a hit.

Why deterministic, not a model

These behaviours are not subtle. They are enumerable, and a named rule for each has no false-negative rate from model weakness and needs no calibration. That is the opposite regime from catching subtle deception, where rules are useless and you need a model. Use the right instrument for each: this is the cheap, exhaustive one for the blatant cases.

Evasion is handled before matching

Anything that changes a command's spelling without changing its effect is normalised first, so a literal rule sees through it:

written as normalised to
curl http://2852039166/ 169.254.169.254 (integer-encoded IP)
curl http://0xa9fea9fe/ hex-encoded IP
n''m''a''p -p- … nmap … (shell-quote splitting)
echo <base64> | base64 -d | sh the decoded payload, appended

API

  • run_detectors(tool_calls, egress_allowlist=(), messages=()) → list[Hit] — the main entry point; scans both what the agent did and what came back, and labels anything found only in the transcript as a mention rather than an action.
  • detect_host_escape(tool_calls) → list[Hit]
  • detect_undeclared_egress(tool_calls, egress_allowlist=()) → list[Hit]
  • is_internal(host) → bool
  • normalise(text) → str

Each Hit carries a detector_id, a category (sandbox_escape or external_attack), a human-readable rule, the matched evidence, and the index of the tool call it was found in.

The names run_containment_detectors, detect_sandbox_escape, and detect_external_attack are kept as aliases for callers migrating from an in-tree copy.

Scope, honestly

This is a tripwire, not a sandbox. It tells you an agent reached for the exit; it does not contain anything, and a determined adversary who knows the exact rules can craft around them. Its value is catching the blatant, enumerable cases cheaply and without a false-negative rate — pair it with a real sandbox and, for subtle cases, a model-based monitor. Do not rely on it as your only boundary.

Licence

Apache-2.0. Built for AnyEval; useful anywhere agent traces need a cheap, deterministic boundary check.

Metadata

Release files for egress-guard 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for egress-guard 1.0.0
File Size Uploaded Provenance Actions
egress_guard-1.0.0.tar.gz 15.4 kB Without provenance Details for egress_guard-1.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for egress-guard 1.0.0
File Interpreter ABI Platform Actions
egress_guard-1.0.0-py3-none-any.whl Python 3 none any Details for egress_guard-1.0.0-py3-none-any.whl

Total release size: 27.7 kB

Release files / egress_guard-1.0.0.tar.gz

Download URL egress_guard-1.0.0.tar.gz
Size 15.4 kB
Tags Source
SHA-256 checksum
How to use checksums
4f2fd8937e7972e6a1c8d9e9af342f50458a9ef7d821e2de1035244ad6826f92
BLAKE2b-256 checksum
How to use checksums
0525d16fd1e38c1de608b710680f4e932222b5506598996a69641e021365bd6c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / egress_guard-1.0.0-py3-none-any.whl

Download URL egress_guard-1.0.0-py3-none-any.whl
Size 12.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cc486210bd233ac255f374daf644a9236e8bce5a542caa73b9357d6478085799
BLAKE2b-256 checksum
How to use checksums
823317a55950dd3a0cb3b0412a3f8090366ae5e384ce01e454c3bebbfe734978
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for egress-guard 1.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page