Skip to main content

Deterministic runtime security layer for AI agents. Enforces policies for file access, network requests, process execution, and tool invocation.

Project description

IronGate

Experimental v0.1.0. Local deterministic runtime security for Python AI agents.

IronGate is a local, in-process policy enforcement layer for Python-based AI agents. It intercepts file, network, process, and tool operations at the Python API level and applies deterministic allow/review/block decisions based on a JSON policy file.

Experimental Release Warning

This is an experimental release for evaluation and feedback. Important limitations:

  • Deterministic, deny-by-default enforcement — no AI/ML inside IronGate
  • Local runtime only — all enforcement in-process or in a child process
  • Known bypass boundaries documented in SECURITY_MODEL.md
  • Not a substitute for OS-level sandboxing — use containers or seccomp for untrusted code
  • Hash-chained audit log for tamper evidence, not cryptographic proof

What it does

  • Intercepts standard Python APIs via two enforcement layers:
    • Audit hooks (sys.addaudithook): Observes file open, subprocess, socket, OS operations at the CPython level. Harder to bypass than monkeypatching. Cannot be removed once installed.
    • Monkeypatch interception: Replaces standard library functions with policy-enforcing wrappers.
  • Evaluates each operation against a JSON policy (first-match-wins rule engine)
  • Enforces allow, review (human-in-the-loop via local dashboard), or block decisions
  • Logs all operations to a local SQLite audit trail with hash chaining for tamper evidence
  • Defaults to deny — unknown action types and unmatched operations are blocked

Intercepted APIs

File: builtins.open, io.open, os.open, os.fdopen, os.remove, os.unlink, os.rename, os.link, os.symlink, os.mkdir, os.makedirs, os.rmdir, os.removedirs, shutil.rmtree, shutil.copy, shutil.copy2, shutil.move, shutil.copytree, pathlib.Path.open/read_text/write_text/read_bytes/write_bytes/unlink/rename/replace/mkdir

Network: requests.*, httpx.*, urllib.*, aiohttp.*, http.client.HTTPConnection/HTTPSConnection, ssl.wrap_socket/SSLContext.wrap_socket, socket.socket, socket.create_connection

Process: subprocess.run/Popen/call/check_call/check_output, os.system (with Python child vs binary classification). Audit hooks also cover os.exec*, os.spawn*.

What it does NOT do

  • It does not sandbox native code, C extensions, or ctypes/cffi calls
  • It does not use machine learning, AI-based detection, or heuristics
  • It does not provide network-level firewalling or OS-level syscall interposition
  • It does not prevent an agent from saving a reference to builtins.open before shield.protect() is entered
  • It is not a cloud service — everything runs locally in your process

See SECURITY_MODEL.md for the full list of known limitations and bypass boundaries.

Status: Experimental Local Runtime

This release focuses exclusively on the local deterministic runtime. The following are out of scope:

  • Enterprise platform features
  • Distributed trust networks
  • Cloud integration
  • Compliance frameworks
  • Backend services
  • ML/AI-based detection

Supported version: 0.1.0 experimental. Local Python runtime only.

Install

pip install -e .

Requires Python 3.8+ (audit hooks require 3.8+).

Quick start

Protect a script

irongate run my_agent.py

All file, network, process, and tool operations inside my_agent.py will be intercepted and enforced.

Options

irongate run my_agent.py --profile sandboxed    # default — restrictive capabilities
irongate run my_agent.py --profile read_only    # read files + HTTP only
irongate run my_agent.py --profile trusted      # broad capabilities
irongate run my_agent.py --policy custom.json   # custom policy file
irongate run my_agent.py --isolate              # run in child process
irongate run my_agent.py -v                     # verbose output

Child-process isolation

irongate run my_agent.py --isolate

Runs the agent in a separate Python interpreter with its own IronGate bootstrap. If the agent crashes, the parent is unaffected. The child process inherits the policy and capability profile via environment variables.

Use as a library

from agentshield import shield, protect_agent

# Context manager
with shield.protect():
    agent.run(query)

# Decorator
@protect_agent
def run_my_agent():
    with open('data.csv') as f:
        return f.read()

Start the local dashboard

irongate dashboard

The dashboard starts on http://127.0.0.1:9123 and prints an auth token to the console. All endpoints require this token as Authorization: Bearer <token>.

Remote binding requires explicit opt-in via the IRONGATE_ALLOW_REMOTE=1 environment variable.

Policy format

Policies are JSON files with a rules array. Rules are evaluated in order; first match wins. The default policy ends with a deny-all fallback.

{
  "rules": [
    {
      "type": "file",
      "path_contains": [".env", ".ssh/", "id_rsa"],
      "decision": "review",
      "reason": "Sensitive file access requires approval"
    },
    {
      "type": "process",
      "cmd_contains": ["rm -rf", "shutdown"],
      "decision": "block",
      "reason": "Dangerous commands blocked"
    },
    {
      "decision": "block",
      "reason": "default_deny"
    }
  ]
}

Supported match predicates:

  • Exact match: "type": "file" matches action.type == "file"
  • Substring list: "path_contains": [".env", ".ssh"] matches if path contains any
  • Regex: "cmd_pattern": "^sudo" matches if cmd matches the regex
  • Prefix: "path_startswith": "/sensitive"

Custom policies can be placed at ~/.irongate/policies.json or passed via --policy.

Capability profiles

Profiles restrict what classes of operations an agent can perform, enforced before policy rules:

Profile Capabilities
sandboxed (default) file.read, network.dns, process.env_access, tool.invoke
read_only file.read, network.dns, network.http, process.env_access, tool.invoke
trusted file., network., process., tool., credential.read
minimal tool.invoke only

If an action requires a capability the profile doesn't grant, it is blocked before policy evaluation. Unknown action types require an impossible capability and are always blocked.

Architecture

Agent code
    |
    v
sys.addaudithook (audit hook layer — permanent, hard to bypass)
    |
    v
RuntimeInterceptor (monkeypatch layer — secondary enforcement)
    |
    v
PolicyEngine (capability check + rule matching)
    |
    |-- allow --> proceed
    |-- review --> log + wait for dashboard approval
    +-- block --> raise PermissionError
    |
    v
LocalStorage (SQLite + WAL mode + hash-chained audit log)

All components run in-process (or in a child process with --isolate). No external services required.

Project structure

irongate/
  __init__.py          # Global runtime instance
  audit_hooks.py       # sys.addaudithook enforcement (PEP 578)
  interceptor.py       # Monkeypatch-based interception
  policy.py            # Rule engine + capability enforcement
  capabilities.py      # Capability profiles and checks
  storage.py           # SQLite event storage (WAL + hash chaining)
  dashboard.py         # Local FastAPI dashboard (all endpoints authenticated)
  cli.py               # CLI entrypoint
  runtime_launcher.py        # Script execution (in-process or child-process isolation)
  startup_checks.py          # Startup safety validation (fail closed)
  environment_sanitizer.py   # Environment sanitization for --isolate mode
  models.py                  # Pydantic action models
  approvals.py               # Approval queue management
  notifier.py                # Local notification log
  default_policy.json        # Default deny-by-default policy
  integrations/              # LangChain and generic wrappers

License

See LICENSE file.

Release Validation (v0.1.0)

To verify IronGate is working correctly:

# Install from source
pip install -e .

# Run test suite
pytest -q

# Run example agent with default sandboxed profile
irongate run examples/safe_agent.py

# Run example agent in isolated child process
irongate run --isolate examples/safe_agent.py

# Start local dashboard (requires auth token)
irongate dashboard

Expected behavior:

  • Tests pass
  • Example agent blocks access to .ssh/ files and dangerous commands
  • Allowed operations (safe file reads, local network) proceed
  • Dashboard starts on http://127.0.0.1:9123
  • All dashboard endpoints require Authorization: Bearer <token>

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

irongate-0.0.1.tar.gz (68.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

irongate-0.0.1-py3-none-any.whl (62.5 kB view details)

Uploaded Python 3

File details

Details for the file irongate-0.0.1.tar.gz.

File metadata

  • Download URL: irongate-0.0.1.tar.gz
  • Upload date:
  • Size: 68.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.11

File hashes

Hashes for irongate-0.0.1.tar.gz
Algorithm Hash digest
SHA256 c00c564674107999411531a8c5db045de01212e5a55f43f7cb4597caac82eee4
MD5 d02068c34c0f640789c84190208bedd7
BLAKE2b-256 342e4302dad425f9df98a543aa226c444911cf4b2e2fe5edbf02ece2f89558cb

See more details on using hashes here.

File details

Details for the file irongate-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: irongate-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 62.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.11

File hashes

Hashes for irongate-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 752fb0de4eb43561ffdf02759b34633217ac6220d1581d1a1660189bb6b96583
MD5 3b8444b01fd93e6b858283b2e227d448
BLAKE2b-256 2c192b17c598ad8ec7da4bdbf73bf01f33ca6284528f21cb6d0f1f59b5c0f456

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page