Skip to main content
AFK implements security through four boundaries — policy engine, tool runtime, A2A/MCP bridges, and sandbox. Each boundary enforces least-privilege defaults and requires explicit opt-in for elevated permissions.

Security boundaries

Gate tool calls and agent actions with configurable rules.
from afk.agents import PolicyEngine, PolicyRule

policy = PolicyEngine(rules=[
    PolicyRule(
        rule_id="deny-admin",
        condition=lambda e: e.tool_name and "admin" in e.tool_name,
        action="deny",
        reason="Admin tools are disabled",
    ),
    PolicyRule(
        rule_id="approve-writes",
        condition=lambda e: e.tool_name and "write" in e.tool_name,
        action="request_approval",
        reason="Write operations need human approval",
    ),
])

runner = Runner(policy_engine=policy)
Actions: allow (default), deny, request_approval, request_user_input
Every tool call passes through validation, policy checks, and output sanitization.
runner = Runner(
    config=RunnerConfig(
        sanitize_tool_output=True,        # Strip prompt injection vectors
        tool_output_max_chars=8000,       # Truncate oversized responses
    ),
)
Sandbox profiles are configured at the runner level, not per-tool:
class CodeArgs(BaseModel):
    code: str

@tool(args_model=CodeArgs, name="run_code", description="Execute code.")
def run_code(args: CodeArgs) -> dict:
    # Execution constraints are enforced by the runner and policy engine
    ...
External communication requires authentication and per-caller authorization.
from afk.a2a import TokenAuthProvider

auth = TokenAuthProvider(
    valid_tokens={"system-a": "token-abc"},
    allowed_agents={"system-a": ["analyzer"]},
)

server = A2AServer(agents={"analyzer": agent}, auth_provider=auth)
Hard limits prevent runaway agents.
from afk.agents import FailSafeConfig

agent = Agent(
    ...,
    fail_safe=FailSafeConfig(
        max_steps=10,
        max_tool_calls=5,
        max_total_cost_usd=0.50,
        max_wall_time_s=60.0,
    ),
)

Default posture

AFK defaults to least privilege:
SettingDefaultMeaning
Tool policyallowTools run unless explicitly denied
Tool output sanitizationTrueOutput is sanitized by default
A2A authenticationRequiredNo unauthenticated A2A
MCP authenticationRequiredNo unauthenticated MCP
Cost limitsNone ()You must set max_total_cost_usd
SandboxNoneTools run in the host process
Cost limits are not set by default. Always configure max_total_cost_usd in production to prevent runaway spending.

Production hardening checklist

AreaActionStatus
CostSet max_total_cost_usd on all agents
CostSet max_steps and max_tool_calls
PolicyAdd deny rules for admin/destructive tools
PolicyAdd request_approval for mutating operations
ToolsEnable sanitize_tool_output=True
ToolsSet tool_output_max_chars
ToolsUse sandbox profiles for code execution
A2A/MCPConfigure auth providers with valid tokens
A2A/MCPSet per-caller agent access lists
A2A/MCPEnable rate limiting
SecretsStore API keys in environment variables
SecretsUse secret scope isolation per tool call
MonitoringConfigure telemetry exporter (OTEL)
MonitoringSet up alerts for error rate and cost anomalies

Secret isolation

AFK recommends isolating secrets at the environment level. Use separate environment scopes and the runner’s ToolContext.metadata to control which credentials are available to each tool:
from pydantic import BaseModel
from afk.tools import tool, ToolContext

class QueryArgs(BaseModel):
    sql: str

@tool(args_model=QueryArgs, name="query_db", description="Query the database.")
def query_db(args: QueryArgs, ctx: ToolContext) -> dict:
    db_url = ctx.metadata.get("db_url")  # ← Injected via runner context
    return execute_query(db_url, args.sql)

Threat model overview

ThreatMitigation
Prompt injectionOutput sanitization, input validation
Runaway agentsCost limits, step limits, wall time
Tool abusePolicy engine, sandbox profiles
Unauthorized accessA2A/MCP auth, per-caller authorization
Secret leakageSecret scope isolation, output sanitization
Cost explosionmax_total_cost_usd, circuit breakers

Next steps