{"id":48443830,"url":"https://github.com/webpro255/agentlock","last_synced_at":"2026-04-06T17:01:09.575Z","repository":{"id":345337979,"uuid":"1185342065","full_name":"webpro255/agentlock","owner":"webpro255","description":"The Open Authorization Standard for AI Agents. Framework-agnostic tool permissions, identity verification, scoped access control, and audit logging for any AI agent.","archived":false,"fork":false,"pushed_at":"2026-03-18T18:09:28.000Z","size":86,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-19T06:50:52.167Z","etag":null,"topics":["access-control","ai-agents","ai-safety","authorization","guardrails","llm","owasp","permissions","security","tool-calling"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/webpro255.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-18T13:39:32.000Z","updated_at":"2026-03-19T00:05:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/webpro255/agentlock","commit_stats":null,"previous_names":["webpro255/agentlock"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/webpro255/agentlock","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webpro255%2Fagentlock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webpro255%2Fagentlock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webpro255%2Fagentlock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webpro255%2Fagentlock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webpro255","download_url":"https://codeload.github.com/webpro255/agentlock/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webpro255%2Fagentlock/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31481238,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-06T14:34:32.243Z","status":"ssl_error","status_checked_at":"2026-04-06T14:34:31.723Z","response_time":112,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["access-control","ai-agents","ai-safety","authorization","guardrails","llm","owasp","permissions","security","tool-calling"],"created_at":"2026-04-06T17:00:23.088Z","updated_at":"2026-04-06T17:01:09.563Z","avatar_url":"https://github.com/webpro255.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ch1 align=\"center\"\u003eAgentLock\u003c/h1\u003e\n  \u003cp align=\"center\"\u003e\n    \u003cstrong\u003eAuthorization framework for AI agent tool calls\u003c/strong\u003e\n  \u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    Your AI agent needs a login screen. AgentLock is that login screen.\n  \u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/webpro255/agentlock/actions\"\u003e\u003cimg src=\"https://github.com/webpro255/agentlock/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/agentlock/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/v/agentlock.svg\" alt=\"PyPI\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/agentlock/\"\u003e\u003cimg src=\"https://img.shields.io/pypi/pyversions/agentlock.svg\" alt=\"Python\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/webpro255/agentlock/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-Apache%202.0-blue.svg\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/p\u003e\n\n---\n\n## The Problem\n\nEvery major AI agent framework LangChain, CrewAI, AutoGen, and others treats tool calls as trusted function invocations with **no identity verification, no scope constraints, and no access control**.\n\n```json\n{\n  \"name\": \"send_email\",\n  \"description\": \"Sends an email to a recipient\",\n  \"parameters\": { \"to\": \"string\", \"subject\": \"string\", \"body\": \"string\" }\n}\n```\n\nThis tool will send an email to **anyone**, with **any content**, at **any time**, for **any reason**, initiated by **any user**  or attacker  who can communicate with the agent.\n\nThis is the equivalent of giving every application on a computer full root access and hoping it behaves.\n\n## The Solution\n\nAgentLock adds a `permissions` block to every tool. Two fields provide immediate value. The full spec covers everything.\n\n```bash\npip install agentlock\n```\n\nOr install from source (before PyPI publish):\n\n```bash\npip install git+https://github.com/webpro255/agentlock.git\n```\n\n### Protect your first tool in 5 minutes\n\n```python\nfrom agentlock import AuthorizationGate, AgentLockPermissions\n\ngate = AuthorizationGate()\n\n# Define permissions — deny by default\ngate.register_tool(\"send_email\", AgentLockPermissions(\n    risk_level=\"high\",\n    requires_auth=True,\n    allowed_roles=[\"account_owner\", \"admin\"],\n    rate_limit={\"max_calls\": 5, \"window_seconds\": 3600},\n    data_policy={\n        \"output_classification\": \"contains_pii\",\n        \"prohibited_in_output\": [\"ssn\", \"credit_card\"],\n        \"redaction\": \"auto\",\n    },\n))\n\n# Every call goes through the gate\nresult = gate.authorize(\n    \"send_email\",\n    user_id=\"alice\",\n    role=\"account_owner\",\n    parameters={\"to\": \"bob@company.com\", \"subject\": \"Q3 Report\"},\n)\n\nif result.allowed:\n    output = gate.execute(\"send_email\", my_send_func, token=result.token,\n                          parameters={\"to\": \"bob@company.com\", \"subject\": \"Q3 Report\"})\nelse:\n    print(result.denial)\n    # {\"status\": \"denied\", \"reason\": \"insufficient_role\", ...}\n```\n\n### Or use the decorator\n\n```python\nfrom agentlock import AuthorizationGate, agentlock\n\ngate = AuthorizationGate()\n\n@agentlock(gate, risk_level=\"high\", allowed_roles=[\"admin\"])\ndef send_email(to: str, subject: str, body: str) -\u003e str:\n    return f\"Email sent to {to}\"\n\n# Call with auth context\nsend_email(to=\"bob@co.com\", subject=\"Hi\", body=\"Hello\",\n           _user_id=\"alice\", _role=\"admin\")\n```\n\n## Core Principles\n\n| Principle | What It Means |\n|-----------|--------------|\n| **Deny by default** | No permissions defined = denied. Always. |\n| **Tool-level enforcement** | Each tool enforces its own permissions. |\n| **Identity-bound access** | Every call tied to verified identity. Agent cannot assert identity. |\n| **Least privilege** | Minimum access for the specific operation. |\n| **Framework-agnostic** | Zero framework dependencies in core. |\n| **Auditable** | Every call generates an audit record. No exceptions. |\n\n## The Schema\n\nAn AgentLock-compliant tool extends the standard definition with a `agentlock` block:\n\n```json\n{\n  \"name\": \"send_email\",\n  \"description\": \"Sends an email to a recipient\",\n  \"parameters\": { \"to\": \"string\", \"subject\": \"string\", \"body\": \"string\" },\n  \"agentlock\": {\n    \"version\": \"1.0\",\n    \"risk_level\": \"high\",\n    \"requires_auth\": true,\n    \"allowed_roles\": [\"account_owner\", \"admin\"],\n    \"scope\": {\n      \"data_boundary\": \"authenticated_user_only\",\n      \"max_records\": 1,\n      \"allowed_recipients\": \"known_contacts_only\"\n    },\n    \"rate_limit\": { \"max_calls\": 5, \"window_seconds\": 3600 },\n    \"data_policy\": {\n      \"output_classification\": \"contains_pii\",\n      \"prohibited_in_output\": [\"ssn\", \"credit_card\"],\n      \"redaction\": \"auto\"\n    },\n    \"audit\": { \"log_level\": \"full\", \"retention_days\": 90 },\n    \"human_approval\": { \"required\": false }\n  }\n}\n```\n\n### Risk Levels\n\n| Level | Description | Default Behavior |\n|-------|-------------|-----------------|\n| `none` | Read-only, non-sensitive | Auto-allow, minimal logging |\n| `low` | Read-only, potentially sensitive | Auto-allow with auth, standard logging |\n| `medium` | Write operations, limited scope | Auth + scope check + full logging |\n| `high` | Write to external systems or PII | Auth + scope + rate limit + full logging |\n| `critical` | Financial, destructive, or bulk | Auth + approval + full logging |\n\n## Three-Layer Enforcement\n\n```\n┌──────────────────────────────────────────────┐\n│  Layer 1: Agent (Conversation)               │\n│  - Reads/writes messages                     │\n│  - Decides which tool to call                │\n│  - CANNOT authenticate, see credentials,     │\n│    or access backends                        │\n├──────────────────────────────────────────────┤\n│  Layer 2: Authorization Gate (AgentLock)      │\n│  - Validates permissions                     │\n│  - Verifies identity, role, scope            │\n│  - Enforces rate limits                      │\n│  - Issues single-use execution tokens        │\n│  - Generates audit records                   │\n├──────────────────────────────────────────────┤\n│  Layer 3: Tool Execution (Infrastructure)     │\n│  - Validates token                           │\n│  - Executes within scoped boundaries         │\n│  - Enforces data policy / redaction          │\n│  - Token is single-use, time-limited         │\n└──────────────────────────────────────────────┘\n```\n\n**Key constraint:** The agent never receives execution tokens. Layer 2 passes directly to Layer 3. The agent gets only the result.\n\n## Security Note\n\nAgentLock authorizes tool calls. It does not authenticate users. The web framework integrations (FastAPI, Flask) trust upstream headers for identity. Deploy behind an authenticated API gateway or reverse proxy.\n\n## Security Hardening\n\nAgentLock assumes the authorization gate runs in a trusted compute environment. These recommendations strengthen the enforcement boundary in production deployments:\n\n- Deploy the gate on a separate machine or container from the agent. A compromised agent cannot tamper with a gate it cannot reach.\n- The agent should communicate with the gate over an authenticated API, not shared memory or local function calls.\n- The gate host should run only the gate service with minimal attack surface.\n- Apply standard infrastructure security: encrypted transport, restricted network access, audit logging at the OS level.\n\n\n## Framework Integrations\n\nAgentLock is framework-agnostic. Optional integrations for popular frameworks:\n\n```bash\npip install agentlock[langchain]    # LangChain\npip install agentlock[crewai]       # CrewAI\npip install agentlock[autogen]      # AutoGen\npip install agentlock[mcp]          # Model Context Protocol\npip install agentlock[fastapi]      # FastAPI\npip install agentlock[flask]        # Flask\npip install agentlock[crypto]       # Ed25519 signed receipts\npip install agentlock[all]          # Everything\n```\n\n### LangChain\n\n```python\nfrom agentlock.integrations.langchain import AgentLockToolWrapper\n\nprotected_tool = AgentLockToolWrapper(\n    tool=my_langchain_tool,\n    gate=gate,\n    permissions=AgentLockPermissions(risk_level=\"high\", allowed_roles=[\"admin\"]),\n)\n```\n\n### FastAPI\n\n```python\nfrom agentlock.integrations.fastapi import AgentLockMiddleware, require_agentlock\n\napp = FastAPI()\napp.add_middleware(AgentLockMiddleware, gate=gate)\n\n@app.post(\"/api/send-email\")\nasync def send_email(request: Request, auth=Depends(require_agentlock(gate, \"send_email\"))):\n    ...\n```\n\n## CLI\n\n```bash\nagentlock init                      # Generate starter tool definition\nagentlock validate tool.json        # Validate against schema\nagentlock inspect tool.json         # Display permissions summary\nagentlock schema                    # Print JSON schema\nagentlock audit --tool send_email   # Query audit logs\n```\n\n## What AgentLock Prevents\n\nBased on empirical research: multi-turn adversarial attack testing across 35 categories, tested against multiple frontier AI models.\n\n| Attack Category | Prevention |\n|----------------|-----------|\n| Prompt injection | Permissions enforced at infrastructure layer, not content layer |\n| Social engineering | Identity verified cryptographically, not conversationally |\n| Data exfiltration | max_records + rate_limit + data_boundary |\n| Privilege escalation | Role checked on every call |\n| Tool abuse | Scope constraints + rate limiting |\n| Token replay | Single-use, time-limited, operation-bound |\n| Agent impersonation | Out-of-band identity verification |\n| Memory poisoning | Infrastructure-enforced, not content-dependent |\n\n**The central finding:** adversarial and legitimate tool requests are semantically identical — content-based detection cannot reliably distinguish them. The correct defense is **architectural access control**, not smarter AI-based detection.\n\n## v1.1: Memory \u0026 Context Permissions\n\nAgentLock v1.1 extends tool-level permissions to cover the agent's **context window** and **memory**. Not all context is created equal — a system prompt and a web search result should not have the same authority over agent behavior.\n\n### Context Authority\n\nEvery context entry is classified by source and assigned an authority level:\n\n```python\nfrom agentlock import (\n    AuthorizationGate, AgentLockPermissions,\n    ContextPolicyConfig, TrustDegradationConfig, DegradationTrigger,\n    ContextSource, DegradationEffect,\n)\n\ngate = AuthorizationGate()\n\ngate.register_tool(\"web_search\", AgentLockPermissions(\n    risk_level=\"low\",\n    requires_auth=True,\n    allowed_roles=[\"analyst\"],\n    context_policy=ContextPolicyConfig(\n        trust_degradation=TrustDegradationConfig(\n            enabled=True,\n            triggers=[\n                DegradationTrigger(\n                    source=ContextSource.WEB_CONTENT,\n                    effect=DegradationEffect.REQUIRE_APPROVAL,\n                ),\n            ],\n        ),\n    ),\n))\n```\n\nOnce web search results enter context, all subsequent tool calls require human approval. Trust degrades per-session and never escalates — only a new session restores full trust.\n\n### Memory Access Control\n\n```python\nfrom agentlock import MemoryPolicyConfig, MemoryWriter, MemoryPersistence\n\ngate.register_tool(\"assistant\", AgentLockPermissions(\n    risk_level=\"medium\",\n    requires_auth=True,\n    allowed_roles=[\"user\"],\n    memory_policy=MemoryPolicyConfig(\n        persistence=MemoryPersistence.SESSION,\n        allowed_writers=[MemoryWriter.SYSTEM, MemoryWriter.USER],\n        prohibited_content=[\"credentials\", \"pii\"],\n        require_write_confirmation=True,\n    ),\n))\n```\n\n### Provenance Tracking\n\nEvery write to context generates a `ContextProvenance` record with source, authority, writer identity, timestamp, and content hash. Audit records now include `trust_ceiling`, `context_provenance_ids`, and `memory_operation` fields.\n\n## v1.2: Adaptive Hardening \u0026 New Decision Types\n\nAgentLock v1.2 adds four capabilities that close the gap between authorization and runtime defense.\n\n### Adaptive Prompt Hardening\n\nWhen the gate detects suspicious activity, it generates defensive instructions for the agent's system prompt. A pre-LLM prompt scanner analyzes user messages before the model processes them, enabling hardening on the first turn of an attack. Four signal detectors (velocity, tool combination, response echo, prompt scan) feed into a monotonic session risk score.\n\n### Five Decision Types\n\nv1.0/v1.1 supported ALLOW and DENY. v1.2 adds three more:\n\n| Decision | When | Effect |\n|----------|------|--------|\n| **ALLOW** | Call is authorized | Token issued, tool executes normally |\n| **DENY** | Call is not authorized | No token, structured denial returned |\n| **MODIFY** | Call is authorized but output must be transformed | Token issued, PII redacted from output before LLM sees it |\n| **DEFER** | Context is ambiguous, gate cannot decide | Action suspended, resolves via human review or timeout |\n| **STEP_UP** | Session state indicates elevated risk | Action paused, human approval required |\n\n### MODIFY: Output Transformation\n\n```python\ngate.register_tool(\"query_database\", AgentLockPermissions(\n    risk_level=\"high\",\n    requires_auth=True,\n    allowed_roles=[\"admin\", \"support\"],\n    modify_policy=ModifyPolicyConfig(\n        enabled=True,\n        transformations=[\n            TransformationConfig(field=\"output\", action=\"redact_pii\"),\n            TransformationConfig(\n                field=\"to\", action=\"restrict_domain\",\n                config={\"allowed_domains\": [\"company.com\"]},\n            ),\n        ],\n    ),\n))\n\nresult = gate.authorize(\"query_database\", user_id=\"alice\", role=\"admin\")\n# result.decision == DecisionType.MODIFY\n# result.modify_output_fn strips PII from tool output before the LLM sees it\noutput = gate.execute(\"query_database\", db_func, token=result.token,\n                      modify_output_fn=result.modify_output_fn)\n# output: {'name': 'Jane Doe', 'email': '[REDACTED:email]', 'ssn': '[REDACTED:ssn]'}\n```\n\nThe tool still executes. The admin still gets the answer. But PII never enters the LLM context where it can be weaponized by injection attacks.\n\n### Signed Receipts (AARM R5)\n\nEvery authorization decision can produce a cryptographically signed receipt, verifiable offline without access to the gate. Tampered receipts fail signature verification.\n\n```python\nfrom agentlock import AuthorizationGate, ReceiptSigner, ReceiptVerifier\n\nsigner = ReceiptSigner(signing_method=\"ed25519\")\ngate = AuthorizationGate(receipt_signer=signer)\n\nresult = gate.authorize(\"query_database\", user_id=\"alice\", role=\"admin\")\n# result.receipt is a SignedReceipt with Ed25519 signature\n\nverifier = ReceiptVerifier(signing_method=\"ed25519\", verify_key=signer.verify_key_bytes)\nassert verifier.verify(result.receipt)  # True\n```\n\nHMAC-SHA256 is available as a fallback when PyNaCl is not installed. Install Ed25519 support with `pip install agentlock[crypto]`.\n\n### Hash-Chained Context (AARM R2)\n\nContext entries form a tamper-evident append-only chain. Each entry includes the hash of the previous entry. Modifying any entry invalidates all subsequent entries.\n\n```python\ngate.notify_context_write(session_id, source=ContextSource.TOOL_OUTPUT,\n                          content_hash=\"abc123...\")\n\nvalid, broken_at = gate.context_tracker.verify_context_chain(session_id)\n# (True, None) if intact, (False, index) if tampered\n```\n\n## Standards Alignment\n\n| Standard | Coverage |\n|----------|----------|\n| **OWASP Top 10 for LLM (2025)** | LLM01 Prompt Injection, LLM05 Insecure Output, LLM06 Excessive Agency |\n| **OWASP Top 10 for Agentic Apps (2026)** | Goal hijacking, excessive agency, unauthorized tool use |\n| **NIST AI RMF (AI 100-1)** | Govern, Map, Measure, Manage functions |\n| **NIST SP 800-53 Rev. 5** | AC, AU, IA, SI control families |\n| **MITRE ATLAS** | AML.T0051 Prompt Injection, AML.T0054 Jailbreak |\n| **EU AI Act** | Transparency (audit), human oversight (approval), risk classification |\n\n## Roadmap\n\n| Version | Focus |\n|---------|-------|\n| **v1.0** | Core schema, tool permissions, enforcement architecture |\n| **v1.1** | Memory/context permissions, trust degradation, provenance tracking |\n| **v1.2** | Adaptive hardening, MODIFY/DEFER/STEP_UP decisions, signed receipts, hash-chained context (847 tests) |\n| **v1.3** | Output destination control, data flow policies |\n| **v2.0** | Execution scope, behavioral policy, anomaly detection, compliance templates |\n\n## Contributing\n\nContributions welcome. Please open an issue first to discuss what you'd like to change.\n\n```bash\ngit clone https://github.com/webpro255/agentlock.git\ncd agentlock\npip install -e \".[dev]\"\npytest\n```\n\n## License\n\nApache 2.0 — see [LICENSE](LICENSE).\n\n## Author\n\n**David Grice** — [agentlock.dev](https://agentlock.dev)\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003cem\u003eAI tools are the only category of programmable system access in modern computing with no permission model. AgentLock changes that.\u003c/em\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebpro255%2Fagentlock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebpro255%2Fagentlock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebpro255%2Fagentlock/lists"}