Skip to main content

ASO Security: Fail-Closed Protection for AI Agents

ASO is a Python security orchestration library for AI agents, memory systems, tool execution, and secrets. It gives developers a structured, fail-closed boundary for protecting agent workloads before they reach privileged resources.

ASO is designed for projects where an agent can read/write memory, call tools, and access credentials. In those environments, a single prompt classifier is not enough. ASO adds an explicit decision layer that inspects intent, validates context, authorizes access, and quarantines suspicious activity before execution continues.

Source code: ASO on GitHub

Why ASO exists

Modern AI agents often need to:

  • read and write memory
  • call external tools
  • retrieve credentials and tokens
  • work with multi-step task flows
  • operate in enterprise or production contexts

Without a hardened security boundary, these operations can be abused by prompt injection, unsafe tool invocation, model misalignment, or untrusted memory content.

ASO helps by enforcing a clear policy:

  • inspect the request
  • validate trusted host context
  • authorize the requested resource
  • execute only through guarded gateways
  • deny or quarantine when the request is suspicious

Core idea

ASO separates concerns into different application layers:

  • Prompt inspection and intent analysis
  • Central orchestration and decision handling
  • Memory protection
  • Tool execution protection
  • Secret and credential access control

This design keeps security decisions auditable and avoids trusting agent-controlled request data as proof of authorization.

Installation

pip install aso-security

Optional integrations:

pip install "aso-security[openai]"
pip install "aso-security[google]"
pip install "aso-security[huggingface]"
pip install "aso-security[langchain]"

Quick start

from MemoryGuard.config import SecurityContext, StoreConfig, MemoryRequest, Operation
from MemoryGuard.memory_access_layer import StoreRegistry
from DecisionEngine.aso_core import AgentSecurityOrchestrator
from ToolGuard.tool_guard import ToolGuard, ToolRegistry, ToolDefinition
from SecretGuard.config import SecretAccessRequest, SecretSecurityContext, SecretPermissions
from SecretGuard.secret_gateway import SecretBroker

# 1. Memory setup
registry = StoreRegistry()
registry.register(StoreConfig(
    store_id="agent-profile",
    store_type="sqlite",
    provider="sqlite",
    adapter=SQLITE(database_path="agent_memory.db"),
    memory_types=frozenset({"profile"}),
    capabilities=frozenset({"read", "write", "update", "delete"}),
))

memory_context = SecurityContext(
    agent_id="agent-42",
    tenant_id="tenant-7",
    allowed_stores=frozenset({"agent-profile"}),
    permissions=frozenset({"read", "write"}),
    session_id="session-100",
)

# 2. Tool setup

def lookup_ticket(ticket_id: str) -> dict:
    return {"ticket_id": ticket_id, "status": "open"}


tool_registry = ToolRegistry()
tool_registry.register(
    ToolDefinition(
        tool_id="lookup_ticket",
        name="Lookup ticket",
        description="Read a ticket status.",
        purpose="Check the status of a ticket requested by the user.",
        operations=frozenset({"lookup"}),
        allowed_resources=frozenset({"T-100"}),
        output_schema={"type": "object"},
    ),
    lookup_ticket,
)

tool_context = ToolSecurityContext(
    agent_id="agent-42",
    session_id="session-100",
    authorized_tools=frozenset({"lookup_ticket"}),
)

# 3. Secret setup
secret_repo = SecretRepository("secret_guard.db")
secret_vault = SecretVault(secret_repo, LocalDevelopmentKeyManager())
secret_broker = SecretBroker(secret_repo, secret_vault, permissions=SecretPermissions())

secret_context = SecretSecurityContext(
    tenant_id="tenant-7",
    requester="service-account",
    agent_id="agent-42",
    session_id="session-100",
    authorized_tools=frozenset({"lookup_ticket"}),
)

# 4. Orchestrator
orchestrator = AgentSecurityOrchestrator(
    framework=Framework.LANGCHAIN,
    llm="security-model",
    prompt_template="Follow the ASO security policy.",
    M_Definition=memory_context,
    T_Definition=None,
    S_Definition=None,
    memory_access_layer=GuardedMemoryAccessLayer(registry),
    tool_guard=ToolGuard(registry=tool_registry, trusted_context=tool_context),
    secret_broker=secret_broker,
    tool_context=tool_context,
    secret_context=secret_context,
    agent_name="support-agent",
    developer_name="Example Engineering",
    agent_description="Handles support requests using guarded memory, tools, and secrets.",
)

# The orchestrator creates its framework agent during initialization.
agent = orchestrator.agent

# Create another agent explicitly when the application needs one.
another_agent = orchestrator.create_agent(
    agent_name="billing-agent",
    model_name="security-model",
    developer_name="Example Engineering",
    description="Handles billing questions.",
)

# 5. Memory request
memory_result = orchestrator.process(
    MemoryRequest(
        agent_id="agent-42",
        operation=Operation.WRITE,
        store_id="agent-profile",
        payload={"preference": "concise answers"},
        memory_type="profile",
        metadata={"memory_id": "answer-style"},
    ),
    context=memory_context,
)
print(memory_result.decision)

# 6. Tool request
result = orchestrator.process(
    ToolRequest(
        request_id="req-tool-1",
        agent_id="agent-42",
        session_id="session-100",
        task_id="task-1",
        tool_id="lookup_ticket",
        purpose="Read the status of ticket T-100.",
        reason="The user asked for the status of a valid ticket.",
        arguments={"operation": "lookup", "ticket_id": "T-100"},
    ),
    context=tool_context,
)
print(result.decision)

Main library entry points

AgentSecurityOrchestrator.process(...)

This is the primary unified entry point for the ASO runtime. It accepts a typed request and dispatches it to the appropriate guard based on the request type.

Supported request types:

  • MemoryRequest
  • ToolRequest
  • SecretAccessRequest

The orchestrator validates prompt content and trusted host context before dispatching. If the request is suspicious, it returns a deny or quarantine result instead of continuing execution.

Creating the framework agent

AgentSecurityOrchestrator creates its initial framework agent during initialization and exposes it as orchestrator.agent. Set agent_name, developer_name, and agent_description to provide its metadata; if omitted, ASO generates a name and uses default metadata. The required llm argument supplies the model identifier used to create the framework agent.

Call orchestrator.create_agent(agent_name, model_name, developer_name, description) to create an additional agent explicitly. It returns the framework-specific agent and records its metadata. This method does not register tools; register tools separately through ToolGuard and provide trusted context for guarded calls.

GuardedMemoryAccessLayer.execute(...)

This is the memory-specific gateway. It ensures:

  • the store is known and enabled
  • the agent identity matches the trusted context
  • the requested memory scope is permitted
  • the operation is allowed by both the context and the store configuration
  • post-read inspection checks retrieved memory

ToolGuard.execute(...)

This gate protects external tool execution. It verifies:

  • the tool is registered
  • the request is from a trusted agent/session/tool context
  • the operation is declared in the tool definition
  • the tool usage is in scope
  • the tool result itself is safe before returning it to the agent

SecretBroker

This is the secret/credential gateway. It enforces:

  • tenant and agent identity matching
  • allowed secret type and destination checks
  • purpose-based access policy
  • read-only or bounded secret callbacks
  • encrypted storage and metadata-only request handling

Trust boundaries matter

ASO deliberately requires trusted host-created context. This is not a library that trusts the agent to say, "I am authorized". Instead, the application creates and provides the authenticated security context.

Examples of host-controlled values:

  • agent ID
  • tenant ID
  • session ID
  • authorized tools
  • allowed memory stores
  • secret policy metadata

Agent-controlled text is never treated as authorization.

Guard behavior

ASO uses a fail-closed style of enforcement:

  • if prompt inspection fails, the request is blocked
  • if the trusted context is missing or mismatched, execution is denied
  • if the tool result is suspicious, it is quarantined
  • if a secret operation breaks policy, it is denied

A quarantine result means the app should notify a human operator or incident system, because the request or output was not accepted for normal execution.

Example: memory protection

from MemoryGuard.config import SecurityContext, MemoryRequest, Operation
from MemoryGuard.memory_gateway import GuardedMemoryAccessLayer

context = SecurityContext(
    agent_id="agent-42",
    tenant_id="tenant-7",
    allowed_stores=frozenset({"agent-profile"}),
    permissions=frozenset({"read", "write"}),
    session_id="session-1",
)

request = MemoryRequest(
    agent_id="agent-42",
    operation=Operation.WRITE,
    store_id="agent-profile",
    payload={"preference": "be concise"},
    memory_type="profile",
)

result = GuardedMemoryAccessLayer(registry).execute(request, context)
print(result.decision)

Example: tool protection

from ToolGuard.config import ToolRequest, ToolSecurityContext
from ToolGuard.tool_guard import ToolGuard, ToolRegistry, ToolDefinition

registry = ToolRegistry()


def get_status(ticket_id: str) -> dict:
    return {"ticket_id": ticket_id, "status": "open"}

registry.register(
    ToolDefinition(
        tool_id="get_status",
        name="Status lookup",
        description="Fetch ticket status",
        purpose="Check the user's requested ticket status.",
        operations=frozenset({"lookup"}),
        allowed_resources=frozenset({"T-100"}),
        output_schema={"type": "object"},
    ),
    get_status,
)

context = ToolSecurityContext(
    agent_id="agent-42",
    session_id="session-1",
    authorized_tools=frozenset({"get_status"}),
)

request = ToolRequest(
    request_id="tool-1",
    agent_id="agent-42",
    session_id="session-1",
    task_id="task-1",
    tool_id="get_status",
    purpose="Check the status of the user's ticket.",
    reason="This is required to answer the user request.",
    arguments={"operation": "lookup", "ticket_id": "T-100"},
)

result = ToolGuard(registry=registry, trusted_context=context).execute(request, context)
print(result.decision)

Example: secret protection

from SecretGuard.config import SecretAccessRequest, SecretSecurityContext, SecretPermissions
from SecretGuard.secret_gateway import SecretBroker

context = SecretSecurityContext(
    tenant_id="tenant-7",
    requester="service-account",
    agent_id="agent-42",
    session_id="session-2",
    authorized_tools=frozenset({"get_status"}),
)

request = SecretAccessRequest(
    request_id="secret-1",
    secret_id="secret-abc",
    tenant_id="tenant-7",
    requester="service-account",
    agent_id="agent-42",
    session_id="session-2",
    tool_id="get_status",
    purpose="Run the API call needed for the current user request.",
    operation="read",
    destination="external-api",
)

result = secret_broker.execute_with_secret(
    request,
    context,
    lambda value: "token-ok",
)
print(result)

Production guidance

For production deployment, ASO should be used with:

  • authenticated host-side identity
  • KMS-backed secret management
  • explicit tool registry policies
  • explicit tenant/session scoping
  • activity logs and audit review
  • alerting for quarantined events
  • tested security policy defaults

License

ASO is licensed under the Apache License 2.0.

Metadata

Release files for aso-security 0.1.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 aso-security 0.1.0
File Size Uploaded Provenance
aso_security-0.1.0.tar.gz 80.1 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for aso-security 0.1.0
File Interpreter ABI Platform
aso_security-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 147.5 kB

Release files / aso_security-0.1.0.tar.gz

Download URL aso_security-0.1.0.tar.gz
Size 80.1 kB
Tags Source
SHA-256 checksum
How to use checksums
05e457aa5b3e1a1b5b980f2b8c6b234e05a3d2541be72239021ddb2b240816a2
BLAKE2b-256 checksum
How to use checksums
a8b116a7158d3abe2f6e886eacedebb7d64d34ee5526401ffe7d86fa1bfc2804
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.5

Release files / aso_security-0.1.0-py3-none-any.whl

Download URL aso_security-0.1.0-py3-none-any.whl
Size 67.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2b49b252bcb8234858222acbf198477ca1f488b2ff646b3744c0df0e5129b8ff
BLAKE2b-256 checksum
How to use checksums
fcd36fbc9d5d32bf8cbf76f262855d012f8b51eed84c47df888f6cca02f4df19
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.5

Security for aso-security 0.1.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

0.1.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