# What a security reviewer checks in an open-source agentic OS

> A security review of an agentic operating system comes down to four questions: what each agent may touch, who can widen that, who approves a consequential action, and where the record lives. Kortix, the open-source AI Operating System, answers them in a committed manifest.

URL: https://agenticoperatingsystemguide.com/agentic-operating-system-permissions-and-approvals

## The governance file a reviewer opens first.

One `kortix.yaml` per project, committed beside the agent files.

### The project tools

`kortix.yaml`

```yaml
tools:
  web_search: kortix:web_search      # maintained by Kortix, updated automatically
  image_search: kortix:image_search
  scrape_webpage: kortix:scrape_webpage
  memory: kortix:memory
  show: kortix:show
```

Source: https://github.com/kortix-ai/suna/blob/dev/packages/starter/templates/base/kortix.yaml

### An agent entry

`kortix.yaml`

```yaml
agents:
  kortix:
    file: agents/kortix.md
    connectors: all
    secrets: all
    kortix_permissions: all
```

Source: https://github.com/kortix-ai/suna/blob/dev/packages/starter/templates/base/kortix.yaml

### Per-agent tools

`kortix.yaml`

```yaml
    # tools: [read, grep, web_search, lookup_order]   # only these
    # tools: { exclude: [bash] }                      # every tool but these
```

Source: https://github.com/kortix-ai/suna/blob/dev/packages/starter/templates/base/kortix.yaml

## The manifest a reviewer opens first

Every Kortix project is a git repository, and one file at its root declares each agent and what that agent may reach. `kortix.yaml` is short enough to read in one sitting, and the [agents docs](https://kortix.com/docs/project/agents) state the rule the rest of the file follows. Grants are deny-by-default: an agent with no `connectors`, `secrets`, `apps` or `kortix_permissions` key gets none of them. Two keys differ: an omitted `tools` key grants every tool, and an omitted `skills` key leaves skill access to the agent's own `permission` rules. For the category itself, [what an agentic operating system is](/what-is-an-agentic-operating-system) settles the name before the file matters.

That rule does most of the work in a review. An agent that names no connector reaches no connector, one that names no secret reads no secret, one with no `apps` key opens no App, and no `kortix_permissions` block means no permission. A specialist built for one job is widened grant by grant, in a diff someone can read.

The two exceptions decide the width of a review, so a reviewer who counts the four deny-by-default keys and stops there misses the `tools` grant, the widest default in the file.

The starter also ships its own default agent with `connectors: all`, `secrets: all`, `kortix_permissions: all` and `skills: all`, so the first session in a fresh project can do real work. That block is the first thing to change, and it sits in the same file as everything else, so the change shows up in the diff.

## What an agent may touch

An agent's block names the `connectors`, `secrets`, `apps` and `kortix_permissions` it may use, and each is deny-by-default: no key means no connector, no secret, no App and no permission. `tools` and `skills` are the exceptions, granting every tool and the agent file's own skill rules when left out. `kortix validate --scopes` prints every grantable permission entry with its aliases, so a grant name gets checked rather than guessed. [Read the docs](https://kortix.com/docs/project/agents) for the keys and what each one resolves to.

A person needs a separate grant to run an agent, unless their account role already covers every project. Project access is set to All agents or Only these, and a member who holds no agent grant gets a 403 when a session starts. Two grants line up before an agent works for someone: the agent's grant decides what it may reach, and the person's grant decides whether they can run it.

## Who may widen it

Per-resource permissions for people and agents. Roles, groups, and an audit trail.

Widening a grant is a commit to `kortix.yaml`, and the account model decides who can make one. Each person holds one account role (owner, admin or member) plus a project role on each project they work in. Owners and admins act as manager on every project in the account, and a project grant cannot lower that. To limit an admin on one project, an owner changes their account role to member first. A grant file that narrows the agents therefore leaves admins as wide as they were.

A config edit from the dashboard can commit straight to the default branch, so the review should name who holds that route as well as who holds repository write. Session work takes the longer path. Both kinds of config change leave rows in the audit log, as `agent.config.update` and `agent.scope.update`.

## Who approves a consequential action

Approval gates you set. Off until you set them. The manifest's `policy.default_mode` is `allow_all` unless a project changes it, so a fresh project runs every connector action its grants allow. Setting `default_mode: risk` holds writes and destructive calls for a person while reads still run.

Gates also work per connector action, as Allow, Ask or Block, and a `sensitive: true` connector holds every call that no rule matches, reads included. A held call returns `202` with `pending_approval` and an `approval_url`, and nothing runs until a person decides. One approval covers one exact request: same connector, same action, same arguments, same account. A changed argument needs a new approval. The call expires after 24 hours unless the project sets `approvals.ttl`. The session does not resume after that.

There is no session-wide approval, so any action that has to run unattended needs an Allow rule. That is the cost of the gate, and it belongs in the deployment plan rather than in a footnote. Inside the machine, the agent file's `permission` block takes `ask` per tool or per pattern, and a `bash` pattern waits for a person the same way a connector call does.

## How a change reaches production

A session works on its own branch. Session work reaches `main` through a change request. Merge is default-deny for agents: an agent merges only when its grant includes `project.gitops.merge`, and a session that opened the change request cannot merge it without that grant, which returns `403 CR_SELF_MERGE_REFUSED`. A merge touching `agents`, `default_agent` or `triggers` also needs `project.agent.write` or the matching trigger permission. The merging agent cannot grant a permission it does not hold. The chain exists so that the agent which benefits from a wider grant cannot approve one.

## What the audit log proves

Every action is recorded. Reading, exporting and streaming the audit log depend on the plan. A row carries the action in `domain.resource.verb` form, the actor type, the credential kind and the outcome. It keeps the route template rather than the raw path, because a path segment can be a setup or approval link. An agent's row also names the person the agent acted for.

The limits are worth stating early. A log names an identity, not a person. A sandbox or a script holding someone's token writes rows as that person, and those rows can outnumber their browser activity by a hundred to one. The log proves what the API accepted and refused, with which credential. It does not prove why anyone wanted it. Recording is always on. Reading, exporting and streaming need the Enterprise `auditAccess` entitlement, so price that before promising an auditor a live feed.

## Where the boundary sits

Each session gets its own isolated machine on Platinum, the reference compute provider, and its own branch. A tool call that runs wild inside one session cannot rewrite the base branch or the filesystem another session is using. A granted secret arrives in that machine as an environment value, which any command there can read. Environment is the default exposure, and egress-enforced is experimental. The grant decides which secrets arrive. What happens to a value after it lands is the reason secret rotation belongs in the runbook.

Self-hosting changes none of that: the manifest, the change request path and the audit log travel with the instance. The [self-hosting guide](/self-hosted-agentic-operating-system) covers the three reachability modes and the first-boot sequence.

## What a reviewer asks first

Three questions that decide the rest of the review.

### Can an agent be limited to one connector?

Yes. Each agent's block in `kortix.yaml` lists the connectors it may reach, so a specialist can hold one connector and nothing else.

### Who approves an agent's change before it reaches production?

A person approves it. Session work reaches `main` through a change request. Merge is default-deny for agents, so merging needs an admin to grant `project.gitops.merge`.

### What does the audit record contain?

Every action is recorded, with the actor, the credential, the route and whether it was allowed. Reading, exporting and streaming the audit log depend on the plan.

## Read the file before the demo.

One committed manifest says what each agent may reach, and the diff shows who widened it.

[Try Kortix](https://kortix.com)
