> For the complete documentation index, see [llms.txt](https://docs.kyvvu.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kyvvu.com/policy-authoring/owasp-default.md).

# OWASP Default Template

**What you'll learn:** The 8 OWASP security policies in the `owasp_agentic_default` manifest, what each one does, which OWASP risks they cover, and how to customize them.

***

## Overview

The OWASP Top 10 for Agentic Applications (2026) manifest provides baseline security coverage for any Kyvvu agent. It is available in the default Kyvvu/manifests repository and is the recommended starting point for all new agents. Assign it via the Manifests page or CLI (`kyvvu assign-manifest`).

Design principles:

* **Immediate value** — every policy works on install with zero configuration.
* **Structural over content-based** — catches missing gates, runaway loops, and undeclared tools. Does not require environment-specific patterns (regex, domains, budgets).
* **Demonstrates path-dependence** — policies 7 and 8 read task history, showcasing the "policies on paths" model.

## The 8 policies

### Registration policies (3)

| # | Name                                           | Rule                  | Severity | OWASP risks                             |
| - | ---------------------------------------------- | --------------------- | -------- | --------------------------------------- |
| 1 | Agent must declare a substantive purpose       | `field_matches_regex` | high     | ASI01, ASI10                            |
| 2 | Agent must declare a tool allowlist            | `field_not_empty`     | high     | ASI02, ASI04                            |
| 3 | Agent must declare a valid risk classification | `field_in_list`       | critical | (enables classification-aware policies) |

**Policy 1** requires the `purpose` field to be at least 30 characters (`^.{30,}$`). Prevents placeholder values like "chat" or "assistant". Without an explicit purpose, goal drift cannot be detected and hijacking has no baseline to violate.

**Policy 2** requires the `declared_tools` field to be non-empty. This is the precondition for runtime policy 4 (tool allowlist enforcement). Together they implement least-agency.

**Policy 3** requires `risk_classification` to be one of `high`, `limited`, or `minimal`. Bridges to EU AI Act Article 6 for installations that add compliance templates.

### Runtime policies (5)

| # | Name                                                             | Rule                     | Severity | OWASP risks         |
| - | ---------------------------------------------------------------- | ------------------------ | -------- | ------------------- |
| 4 | Tool calls must be in the declared allowlist                     | `step_name_in_allowlist` | critical | ASI02, ASI04        |
| 5 | Code execution requires a preceding gate                         | `step_requires_gate`     | critical | ASI05               |
| 6 | Destructive resource operations require a gate                   | `step_requires_gate`     | critical | ASI09               |
| 7 | External content taint: high-impact actions require a fresh gate | `not(all_of(...))`       | critical | ASI01, ASI06, ASI09 |
| 8 | Bound resource calls per task to prevent runaway loops           | `execution_max_steps`    | high     | ASI08, ASI02        |

**Policy 4** blocks tool calls whose `step_name` is not in the agent's `declared_tools` allowlist. Catches typosquatting, supply-chain swap-ins, and silent capability creep.

**Policy 5** requires any `step.exec` to be preceded by a `step.gate` (human approval, static check, or sandbox dry-run) that **records `properties.guard.result: "pass"`** — a bare `step.gate`, or one whose result is anything else, does not clear the block. Direct mitigation for OWASP ASI05 (Unexpected Code Execution).

**Policy 6** requires `step.resource` with verb `DELETE` to be preceded by a `step.gate`. Narrows to DELETE only so development iteration isn't constantly blocked. Production deployments typically widen to include POST and PATCH.

**Policy 7** is a compound path-dependent policy — the headline demonstration of "policies on paths". See below.

**Policy 8** blocks tasks that issue more than 50 `step.resource` calls. Catches runaway loops, the most common dev-time issue.

## Policy 7: the taint policy explained

This policy enforces: **if the agent has fetched external content earlier in this task, any subsequent high-impact action must be immediately preceded by a `step.gate`.**

It addresses the indirect prompt injection pattern (EchoLeak): malicious instructions hidden in retrieved content silently redirect the agent's plan.

The logic uses `not(all_of(...))`:

```
not(
  all_of(
    # Current step IS a high-impact action
    any_of(
      current_is(step.exec),
      current_is(step.message, POST),
      current_is(step.resource, POST),
      current_is(step.resource, PATCH),
      current_is(step.resource, DELETE)
    ),
    # External content HAS been fetched earlier
    history_contains(step.resource, GET, target.trust="external"),
    # Current step is NOT directly preceded by a gate
    not(step_directly_preceded_by(step.gate))
  )
)
```

Why `not(all_of(...))` instead of just `all_of(...)`? Rule functions return `True` to pass and `False` to block. `all_of` returns `True` when all conditions match. If all three danger conditions are present, that means the situation is dangerous — but `all_of` would return `True` (pass). The `not` wrapper inverts it to `False` (block). See [Compound Policies](/policy-authoring/compound.md) for a full explanation of this pattern.

Key property convention: `step.resource` GETs must set `target.trust = "external"` when fetching from outside an internal allowlist. The SDK's behavioural templates default this property based on URL/domain heuristics.

## OWASP coverage summary

| OWASP Risk                       | Coverage     | Policies                                                              |
| -------------------------------- | ------------ | --------------------------------------------------------------------- |
| ASI01 Agent Goal Hijack          | Strong       | 1, 7                                                                  |
| ASI02 Tool Misuse                | Strong       | 2, 4, 6, 8                                                            |
| ASI03 Identity & Privilege Abuse | Gap          | (add credential-taint policy when deploying `step.credential` events) |
| ASI04 Agentic Supply Chain       | Partial      | 2, 4                                                                  |
| ASI05 Unexpected Code Execution  | Strong       | 5                                                                     |
| ASI06 Memory & Context Poisoning | Partial      | 7                                                                     |
| ASI07 Insecure Inter-Agent Comms | Out of scope | (transport-layer concern, not runtime policy)                         |
| ASI08 Cascading Failures         | Moderate     | 8                                                                     |
| ASI09 Human-Agent Trust Exploit  | Strong       | 5, 6, 7                                                               |
| ASI10 Rogue Agents               | Partial      | 1                                                                     |

## What the demo agent demonstrates

The demo agent from `kyvvu init` runs three steps:

1. `step.model` (POST) — model call. Passes: no policies restrict model calls in the default template.
2. `step.resource` (GET) — resource read. Passes: reading is allowed.
3. `step.exec` — code execution. **Blocked**: no passing `step.gate` precedes it (policy 5; a gate counts only when it records `guard.result: "pass"`).

This demonstrates that the same agent code is allowed or blocked depending on the task's history and the policies in effect.

## Customizing

### Disable a policy

```bash
curl -X PUT https://platform.kyvvu.com/api/v1/policies/{id} \
  -H "Authorization: Bearer <JWT>" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'
```

### Change severity

```bash
curl -X PUT https://platform.kyvvu.com/api/v1/policies/{id} \
  -H "Authorization: Bearer <JWT>" \
  -H "Content-Type: application/json" \
  -d '{"severity": "high"}'
```

### Expansion path

The template deliberately excludes rules that require environment-specific configuration. The recommended additions, in order of coverage value:

| Priority | Add                                                               | Covers                                        | When                                                   |
| -------- | ----------------------------------------------------------------- | --------------------------------------------- | ------------------------------------------------------ |
| 1        | Credential taint policy (`step_not_after` with `step.credential`) | ASI03                                         | Your deployment instruments `step.credential` events   |
| 2        | PII gate before model calls (`pii_in_request`)                    | ASI06, EU AI Act Art. 10                      | PII patterns are defined for your domain               |
| 3        | Domain allowlist for resource reads (`domain_allowlist`)          | Closes "what counts as external" for policy 7 | Internal/external domain split is known                |
| 4        | Cost ceiling (`usage_budget` over `usage.cost_usd`)               | ASI08 economic DoS                            | Cost properties are emitted on `step.model` behaviours |

***

## Next steps

* [Manifests](/policy-authoring/templates.md) — other available manifests (EU AI Act, data minimization)
* [Compound Policies](/policy-authoring/compound.md) — author your own `all_of` / `any_of` / `not` policies
* [Built-in Rules Reference](/policy-authoring/rules-reference.md) — all 27 rules
