Skip to Content
GovernanceAuthorization Verification

Authorization Verification

Verify your agents check permissions before executing privileged actions.

Authorization verification detects OWASP LLM06: Excessive Agency - when agents perform actions without proper permission checks.

The Problem

AI agents often have access to powerful tools. Without authorization checks, any caller can invoke any action - including destructive operations like data deletion or financial transactions.

# VULNERABLE: No authorization check def delete_customer(customer_id: str) -> str: database.execute(f"DELETE FROM customers WHERE id = '{customer_id}'") return f"Deleted customer {customer_id}"

What Inkog Detects

Inkog’s universal_missing_authz rule detects tool calls without preceding authorization checks.

Detection Rule

id: universal_missing_authz title: Missing Authorization Check Before Tool Execution severity: HIGH category: governance compliance_mapping: owasp: ["LLM06"] nist_ai_rmf: ["GOVERN 1.2"] iso_42001: ["6.3"]

Supported Auth Patterns

Inkog recognizes 10+ authorization patterns:

TypePatterns Detected
RBACuser.role, has_permission(), check_role()
OPAopa.query(), @opa_authorized, policy.check()
OpenFGAfga.check(), openfga.allowed()
AuthZenauthzen.evaluate(), pdp.access_check()
Django@permission_required, user.has_perm()
Flask@login_required, current_user.can()
FastAPIDepends(verify_token), @requires()
Genericauthorize(), check_access(), is_authorized()

Framework Examples

Python (Generic)

Vulnerable Pattern

from crewai import Tool def delete_customer(customer_id: str) -> str: # VULNERABLE: No authorization check! database.execute(f"DELETE FROM customers WHERE id = '{customer_id}'") return f"Deleted customer {customer_id}" delete_tool = Tool( name="delete_customer", func=delete_customer, description="Delete a customer" )

Compliant Pattern (Simple RBAC)

from crewai import Tool def delete_customer(customer_id: str, caller: User) -> str: # COMPLIANT: Authorization check before action if not caller.has_permission("delete_customer"): raise PermissionDenied("Not authorized to delete customers") database.execute(f"DELETE FROM customers WHERE id = '{customer_id}'") return f"Deleted customer {customer_id}"

Compliant Pattern (OPA)

from crewai import Tool from opa_client import OPAClient opa = OPAClient() def delete_customer(customer_id: str, caller: User) -> str: # COMPLIANT: OPA policy check decision = opa.query("data.customers.allow_delete", { "user": caller.id, "customer": customer_id }) if not decision.allow: raise PermissionDenied(f"OPA denied: {decision.reason}") database.execute(f"DELETE FROM customers WHERE id = '{customer_id}'") return f"Deleted customer {customer_id}"

Compliant Pattern (OpenFGA)

from openfga_sdk import OpenFgaClient fga = OpenFgaClient() def delete_customer(customer_id: str, caller: User) -> str: # COMPLIANT: OpenFGA relationship check allowed = fga.check( user=f"user:{caller.id}", relation="can_delete", object=f"customer:{customer_id}" ) if not allowed: raise PermissionDenied("Not authorized for this customer") database.execute(f"DELETE FROM customers WHERE id = '{customer_id}'") return f"Deleted customer {customer_id}"

LangChain

Vulnerable Pattern

from langchain.tools import Tool delete_tool = Tool( name="delete_record", func=delete_record, description="Delete a database record" # VULNERABLE: No permission check )

Compliant Pattern

from langchain.tools import Tool from functools import wraps def requires_permission(permission: str): """Decorator that checks permission before tool execution.""" def decorator(func): @wraps(func) def wrapper(*args, caller=None, **kwargs): if not caller or not caller.has_permission(permission): raise PermissionDenied(f"Requires {permission}") return func(*args, **kwargs) return wrapper return decorator @requires_permission("delete_record") def delete_record(record_id: str) -> str: # COMPLIANT: Permission checked by decorator return database.delete(record_id) delete_tool = Tool( name="delete_record", func=delete_record, description="Delete a database record" )

Salesforce Agentforce

Vulnerable Pattern

<objectPermissions> <!-- VULNERABLE: Wildcard permissions --> <object>*</object> <allowDelete>true</allowDelete> </objectPermissions>

Compliant Pattern

<objectPermissions> <!-- COMPLIANT: Scoped to specific objects --> <object>Account</object> <allowRead>true</allowRead> <allowDelete>false</allowDelete> </objectPermissions> <objectPermissions> <object>Opportunity</object> <allowRead>true</allowRead> <allowEdit>true</allowEdit> <allowDelete>false</allowDelete> </objectPermissions>

Best Practices

1. Use Decorators/Middleware

Centralize authorization logic rather than scattering checks:

@requires_auth("admin") def dangerous_operation(): ...

2. Principle of Least Privilege

Grant minimum necessary permissions:

# BAD: Broad permissions tools = [all_database_tools] # GOOD: Specific, limited permissions tools = [read_customer_tool, update_email_tool]

3. Separate Read and Write

Distinguish between read-only and write operations:

# Read operations - lower authorization bar @requires_permission("view_customers") def get_customer(id): ... # Write operations - higher authorization bar @requires_permission("delete_customers") def delete_customer(id): ...

4. Log Authorization Decisions

Audit both grants and denials:

def check_permission(user, action, resource): allowed = evaluate_policy(user, action, resource) audit_log.record(user, action, resource, allowed) return allowed

Compliance Evidence

Inkog generates authorization compliance reports:

{ "framework_mapping": { "OWASP LLM06": { "status": "PASS", "finding_count": 0, "details": { "tools_with_auth_checks": 12, "tools_total": 12, "auth_patterns_detected": ["rbac", "opa"] } } } }
Last updated on