Skip to main content

Contextual Security Policies (CSP)

Contextual Security Policies (CSP) are Zihin's policy engine for AI agents — the layer that provides runtime governance over what an agent is allowed to do. A CSP is a named, versioned policy resource, scoped and inherited across tenant → team → agent → user, that the runtime applies on every execution.

CSPs act through two distinct mechanisms:

  • Runtime enforcement — behavior guardrails such as a tool blocklist (must_not_tools), iteration and token caps, and human approval gates are enforced in the agent loop itself, not merely suggested to the model.
  • Contextual injection — schedule, data, and origin rules are injected into the prompt-building process so the agent operates within them.

Policy Types

TypeDescription
scheduleTime-based restrictions (allowed hours, days)
behaviorAgent behavior rules (tone, must_do, must_not)
dataData access restrictions (sensitive fields, entities)
originRequest origin restrictions (IPs, domains)
customCustom rules (flexible JSON)

Scopes

Policies are inherited from broader to narrower scope. More specific scopes override broader ones.

tenant → team → agent → user
ScopeDescription
tenantApplies to entire tenant
teamApplies to a specific team
agentApplies to a specific agent
userApplies to a specific user

Authentication

MethodAccess
JWT (Authorization: Bearer <jwt> + x-tenant-id)RBAC by user role
API Key (X-Api-Key: YOUR_API_KEY)RBAC by API key role
RBAC Enforcement

Both JWT and API Key are subject to the same role-based permission check. The role determines which operations are allowed (e.g., editor can read and create but cannot delete CSPs). See API Keys - Role System for the full permission matrix.


GET /api/csp

List all CSPs for the tenant.

Query Parameters:

ParamTypeDescription
scopestringFilter by scope
policy_typestringFilter by type
is_activebooleanFilter active only
scope_target_idUUIDFilter by target ID

Response:

{
"data": [
{
"id": "uuid",
"name": "Business Hours Only",
"policy_type": "schedule",
"scope": "tenant",
"rules": {
"allowed_hours": { "start": "08:00", "end": "18:00" }
},
"is_active": true,
"priority": 10
}
],
"total": 5
}

GET /api/csp/effective

Get effective CSPs for a context, resolving the inheritance hierarchy.

Query Parameters:

ParamTypeDescription
team_idUUIDTeam context
agent_idUUIDAgent context
user_idUUIDUser context

Response:

{
"data": [
{ "id": "uuid", "name": "Tenant Rules", "policy_type": "behavior", "scope": "tenant" },
{ "id": "uuid", "name": "Agent Rules", "policy_type": "data", "scope": "agent" }
],
"resolution_chain": ["tenant", "agent"]
}

GET /api/csp/:id

Get CSP by ID.

POST /api/csp

Create a new CSP.

Request Body:

{
"name": "Business Hours Only",
"policy_type": "schedule",
"scope": "tenant",
"rules": {
"allowed_hours": { "start": "08:00", "end": "18:00" },
"allowed_days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"timezone": "America/Sao_Paulo"
},
"is_active": true,
"priority": 10
}

PUT /api/csp/:id

Update a CSP (partial update).

PATCH /api/csp/:id/toggle

Toggle CSP active status.

DELETE /api/csp/:id

Delete a CSP.


Policy Rule Examples

Schedule Policy

{
"policy_type": "schedule",
"rules": {
"allowed_hours": { "start": "08:00", "end": "18:00" },
"allowed_days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"timezone": "America/Sao_Paulo"
}
}

Behavior Policy

{
"policy_type": "behavior",
"rules": {
"tone": "professional",
"language": "pt-BR",
"must_do": ["greet_user", "confirm_before_delete", "provide_sources"],
"must_not": ["share_competitor_data", "execute_without_confirmation"],
"max_iterations": 10,
"must_not_tools": ["dangerous_tool"],
"max_tokens_per_request": 4096
}
}

Behavior Guardrails (runtime enforcement)

The following behavior rules are runtime-enforced — applied in the agent loop itself, not just injected into the prompt. must_not_tools acts as a tool blocklist, preventing named tools from ever being called even if the model plans to use them (mitigating tool injection via a compromised plan):

FieldEffect
max_iterationsLimits the number of agent loop iterations
must_not_toolsTool blocklist — blocks specific tools from being called by the agent
max_tokens_per_requestLimits max tokens per LLM request

These guardrails are extracted from the behavior policy in the policy-gate and propagated to the agent loop configuration.

Data Policy

{
"policy_type": "data",
"rules": {
"sensitive_fields": ["cpf", "cnpj", "password"],
"mask_pattern": "[REDACTED]",
"never_expose": ["api_key", "secret_token"],
"restricted_entities": ["Competitor Inc"],
"restriction_message": "You don't have access to this data."
}
}

Origin Policy

{
"policy_type": "origin",
"rules": {
"allowed_origins": ["https://app.zihin.ai", "https://*.zihin.ai"],
"blocked_origins": ["http://*"],
"allowed_ips": ["192.168.1.0/24"],
"reason": "Only HTTPS origins allowed"
}
}

Action Approvals

Action approvals elevate human-in-the-loop from a static per-tool flag to a governance rule plus approval by another user, mediated by the agent inside the conversation. When a sensitive action is triggered, the agent pauses and asks a designated approver to sign off before the action runs.

Native chat only

Action approvals apply only in the native chat (chat.zihin.ai). For the operator-facing walkthrough of the approval flow, see Agents → Action Approvals.

Configuration has two parts: a trigger in the behavior policy that declares which tools need approval, and an approval policy that declares who approves.

Trigger: require_approval_for

Add require_approval_for inside the behavior policy. It is an array whose items are either a plain tool name (string) or an object selecting a group of tools. Any tool that matches requires approval before it runs.

{
"policy_type": "behavior",
"rules": {
"behavior": {
"require_approval_for": [
"create_deal",
{ "tool_name": "send_invoice" },
{ "mcp_server_id": "erp-protheus" },
{ "source": "db" }
],
"approval_policy_id": "b1a2c3d4-..."
}
}
}
Item formMatches
"create_deal" (string)The tool with that exact name
{ "tool_name": "..." }The named tool
{ "mcp_server_id": "..." }All tools exposed by that MCP server (precise)
{ "source": "mcp" }All MCP tools (precise)
{ "source": "api" | "db" }The underlying schema tools for that source
Fail-safe matching

source: mcp matches precisely. For source: api and source: db, matching resolves to the underlying schema tools and errs toward over-approving — if in doubt, it will ask for approval rather than skip it.

Link one approval policy per scope with approval_policy_id (referencing an approval_policies record described below).

Approval policies

An approval policy is a tenant-owned data resource (approval_policies) that decides who approves. A policy has stages, and each stage lists approvers.

{
"name": "Finance sign-off",
"stages": [
{
"type": "approval",
"approvers": [
{ "type": "user", "id": "e9b94898-..." },
{ "type": "role", "role": "admin" }
]
}
]
}
Approver formResolves to
{ "type": "user", "id": "<uuid>" }That specific user
{ "type": "role", "role": "<role>" }Every tenant user with that role
Supported today

Configure a single stage (its type must be "approval") with any-one-approver semantics — when any listed approver decides, the decision applies. Multi-stage approvals, requiring more than one approval (min_approvals > 1), and timeouts are reserved in the schema for the future and are not active yet.

The member → member flow

  1. A user chats with an agent and triggers a matching (sensitive) action.
  2. The agent pauses and delivers an approval card to the approver's own chat session, with a push notification. The approver may be a different user (e.g. a manager).
  3. The approver approves or declines in their chat.
  4. On approval, the action runs outside the agent loop with its arguments frozen; the result flows back to the original requester (receipt + push).

Safe by default

  • A policy with no valid approver blocks the action with a clear message — never a zombie card that nobody can resolve.
  • Sensitive argument keys are redacted in the card.
  • The pending-approvals list is scoped by role: a regular member sees only their own; admin/owner see all.
  • Decisions are atomic — the first decision wins.

Endpoints

EndpointMethodPermissionDescription
GET /api/v1/approvalsGETsessions:approve-actionPending-approvals list (kanban). Scoped by role — member sees only their own. Optional status filter: awaiting_user (default), approved, rejected, expired, or all
GET /api/v1/approval-policiesGETcsp:readList approval policies
POST /api/v1/approval-policiesPOSTcsp:createCreate an approval policy
PUT /api/v1/approval-policies/:idPUTcsp:updateUpdate an approval policy

All endpoints accept hybrid authentication (JWT or API Key).