> ## Documentation Index
> Fetch the complete documentation index at: https://yukta.infenia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Security reference

> API key fields, roles and what each allows, response codes, Host and Origin checks, response headers, audit actors, filters and the safety settings that bound what a workflow may do.

# Security reference

The access rules and safety settings of the server. Setting defaults are in the [Configuration reference](https://yukta.infenia.com/reference/configuration.md); how to apply them is in [Secure the server](https://yukta.infenia.com/guides/operate/secure-the-server.md); the reasoning is in [Security model](https://yukta.infenia.com/concepts/security-model.md).

## Default posture

| Aspect | Default |
| - | - |
| Bind address | `127.0.0.1`; a non-loopback `server.address` without any key stops start-up. |
| Authentication | None while no key is configured. |
| Host and Origin check | On while no key is configured. |
| Actuator | `/actuator/**` except `/actuator/health` is refused with `403` while no key is configured. |
| `PROCESS_EXECUTOR` | Runs nothing until `yukta.process.allowed-commands` is set. |
| TLS | None; Yukta serves plain HTTP. |

## API keys

One key list guards REST (`/api/**`), MCP (`/mcp`) and `/actuator/**` (except `/actuator/health`). A client sends the key in `Authorization: Bearer <key>` or `X-API-Key: <key>`.

| Field | Type | Default | Description |
| - | - | - | - |
| `name` | string | `unnamed` | Name used in the audit as `key:<name>`. |
| `key` | string | required | Plain text or `sha256:<64 hex digits>`, the digest of the real key. Compared as digests in constant time. |
| `role` | enum | `VIEWER` | `VIEWER`, `OPERATOR`, `ADMIN`. |
| `sessions` | list | required unless `ADMIN` | Session ids the key may reach, or `*`. A `VIEWER` or `OPERATOR` key with none is refused at start-up. |
| `expires` | ISO-8601 instant | never | After it the key is refused with `401`. Revoking a key needs a configuration change and a restart. |

```properties theme={"system"}
yukta.api-keys[0].name=ci
yukta.api-keys[0].key=sha256:e79b3879e5d133ee9c794ffa3bdbc6411d054cf5929542c7f844b45801907a58
yukta.api-keys[0].role=OPERATOR
yukta.api-keys[0].sessions[0]=build
```

### Responses

These refusals have no JSON body.

| Status | Meaning |
| - | - |
| `401` with `WWW-Authenticate: Bearer` | No key, or a key that does not match or has expired. |
| `403` | The key is valid but its role or sessions do not allow the request. |
| `400` | The path is ambiguous: parameters (`;`), `//`, dot segments, a backslash or an encoded slash, dot or percent sign. Checked while a key is set. |
| `429` with `Retry-After` | A rate limit was exceeded; see [Limits](#limits). |

## Roles

| Role | Allows |
| - | - |
| `VIEWER` | `GET`, `HEAD`, `OPTIONS` on any `/api` path. |
| `OPERATOR` | Everything a viewer may, plus any method on paths under `/api/executions/` and `/api/workflow/` (start, stop, pause, resume, restart, recover, retry, skip, breakpoints, answers to input requests, priority of a queued run). |
| `ADMIN` | Everything, including defining sessions and workflows, validating drafts, scheduler limits (`POST /api/scheduler/limits`), `/actuator/**`, and the `yukta.priority` and `yukta.version` start options. |

A key limited to sessions reaches only `/api/sessions/{session}/...`, `/api/workflow/{session}/...` and `/api/executions/{executionId}/...` of its own sessions. Every other path is refused with `403`, including the global event stream, the worker list and the audit list; it never reaches `/actuator/**`.

`POST /api/inputs/token-answer` needs no key: it takes a one-time token made for one request and one tier, and answers `403` for a replayed, changed, expired or unknown token and `429` once an address has had 30 refused calls in a minute (or one request 10).

### MCP tool roles

Each `tools/call` is checked against the key's role; a tool not in the role table needs `ADMIN`. A session-limited key must pass a `sessionId` it may reach, except for the tools that name no session (`list_plugins`, `list_ai_backends`, `get_plugin_details`, `get_session_creation_instructions`, `get_plugin_creation_guide`, `list_supervisor_engines`, `get_supervisor_engine`, `get_supervisor_contract`, `list_supervisor_presets`, `whoami`). For a key that is not an unrestricted `ADMIN`, an unparsable `POST` body is refused with `403` and one above 1 MiB with `413`. The role of each tool is listed in the [MCP tools reference](https://yukta.infenia.com/reference/mcp-tools.md).

## Host and Origin checks

Active only while no key of any kind is configured.

| Check | Rule |
| - | - |
| `Host` | Must be `localhost`, `127.0.0.1`, `[::1]` or in `yukta.allowed-hosts`. |
| `Origin` | On a changing request (any method except `GET`, `HEAD`, `OPTIONS`), must match the request host or be in `yukta.allowed-origins`. |

A refused request gets `403` with no body.

## Response headers

| Header | Value | When |
| - | - | - |
| `X-Content-Type-Options` | `nosniff` | Always. |
| `Referrer-Policy` | `no-referrer` | Always. |
| `Strict-Transport-Security` | `max-age=31536000` | The request is HTTPS or carries `X-Forwarded-Proto: https`. |

## Audit actors

Control commands are recorded in the execution log with their sender; read them with `GET /api/control/audit` (`limit` 1 to 500, default 100; `executionId`).

| Sender | Actor |
| - | - |
| A named key | `key:<name>` |
| A supervisor | The supervisor id |
| A webhook receiver answering with a one-time token | `token:<tier>` |
| The single key, with no named keys defined | none recorded |

Only control commands are audited, not ordinary reads and starts.

## Input request authorisation

| Rule | Detail |
| - | - |
| Who may answer | A target of the request's current tier, inside its scope (a key's sessions, a supervisor's scope). |
| `HIGH` risk | Answered by a person (an API key) or a tier of type `HUMAN`; never by a supervisor or a model. |
| Supervisor answers | Need `canAnswer` and a `maxRisk` at or above the request's risk, and only commands the profile allows. |
| Self-answer | The run that asked cannot answer; a supervisor cannot answer a request raised by a run it started. |
| No key configured | Every caller counts as a person. |
| Redaction | Prompts and context are redacted before they are stored, put on the event feed, logged or sent to a webhook. |

## Agent credentials

A supervisor of type `http` is operated with its own credential, made by `POST /api/supervisors/{id}/credential` (ADMIN), shown once and kept as a SHA-256 hash. It works only on `/api/agent/v1`; no person's key works there, and its actor kind is `SUPERVISOR`. `GET` on the same path shows issue time and last use, never the secret; `DELETE`, or disabling the supervisor, cuts it at once. Limits are `yukta.agent.*` in the [Configuration reference](https://yukta.infenia.com/reference/configuration.md).

## Process execution

| Setting | Effect |
| - | - |
| `yukta.process.allowed-commands` | Executables a workflow may run, matched by exact name; while set, shell mode (`useShell`) is refused. |
| `yukta.process.allow-any` | Any executable; only while the list is empty. |
| `yukta.process.allowed-env` | Names a node may set although they change what an allowed program runs. While `allowed-commands` is set, `PATH`, `HOME`, `LD_*`, `DYLD_*`, `GIT_*`, `XDG_*`, `NODE_*`, `PYTHON*`, `PERL*`, `RUBY*`, `*_OPTIONS`, `*_OPTS`, `BASH_ENV`, `CLASSPATH` and similar are refused; the list is best-effort, not isolation. |
| `yukta.process.working-dir-root` | While `allowed-commands` is set, `workingDir` is taken from this directory and must stay inside it (`..` and escaping links refused). |

The allow-list names an executable, not what it does with its arguments; it is not a sandbox. A supervisor of engine type `process` also needs its executable in the list and runs with an empty environment, reading one output line of at most 64 KB.

## Outbound hosts

| Setting | Applies to |
| - | - |
| `yukta.http.allowed-hosts` | `HTTP_REQUEST` |
| `yukta.mcp-client.allowed-hosts` | `MCP_TOOL_CALL`, `MCP_LIST_TOOLS` |
| `yukta.egress.allowed-hosts` | `HTTP_REQUEST`, `MCP_TOOL_CALL`, `MCP_LIST_TOOLS`, `NOTIFY_TERMINAL`, and an `http` supervisor's posts |
| `yukta.egress.by-workflow.<id>`, `yukta.egress.by-session.<id>` | Narrow the egress list per workflow or session |

Entries are host names or IP addresses (case-insensitive) or `*.example.com` (subdomains, not `example.com`). A call must pass the plugin's list and every applicable egress list; an empty list does not restrict. The host is read from the URL, so `https://good.com@evil.com/` counts as `evil.com`; names are not resolved. Link-local and metadata addresses (`169.254.0.0/16`, `fe80::/10`, `metadata.google.internal`, and their numeric spellings) are refused unless listed by name.

## Model and tool call filters

Applied to every `LLM_CALL` and `MCP_TOOL_CALL` node; a refused call fails as bad input and is not retried.

| Setting | Effect |
| - | - |
| `yukta.llm.deny-input-patterns` | Regexes the prompt must not match. |
| `yukta.llm.deny-output-patterns` | Regexes the answer and tool-call arguments must not match. |
| `yukta.llm.max-input-chars` | Most prompt characters; `0` no limit. |
| `yukta.llm.rate-limit.<provider>` | Requests per minute. |
| `yukta.mcp-client.allowed-tools` | Tools a workflow may call; empty allows any. |
| `yukta.mcp-client.max-argument-bytes` | Largest arguments, `65536`. |
| `yukta.mcp-client.deny-argument-patterns` | Regexes arguments must not match. |

A pattern containing a comma (`a{1,3}`) must be an indexed entry: `yukta.llm.deny-input-patterns[0]=...`.

## Secrets and variables

| Rule | Detail |
| - | - |
| Secret syntax | `decrypted:name` reads `YUKTA_SECRET_<NAME>`; scoped forms `YUKTA_SECRET_S_<SESSION>__<NAME>` and `YUKTA_SECRET_T_<TENANT>__<NAME>`. See [Expressions reference](https://yukta.infenia.com/reference/expressions.md#secrets). |
| Literal secrets | A definition holding a literal in a field the plugin declares secret, or named like password, token, api key, authorization or credential, is refused when saved or run, with the path of each value. There is no switch to allow literals. |
| Masking | `GET /api/sessions/{id}/config`, `GET /api/sessions/{id}/workflows/{wf}` and the MCP tool `get_workflow_details` return `******` for literal secret values; references are not masked. A definition still holding `******` is refused when saved. |
| Readable variables | Allow-list in [Expressions reference](https://yukta.infenia.com/reference/expressions.md#readable-environment-values). |

## Limits

| Limit | Value |
| - | - |
| `/api` requests per key and minute | `1200` (`yukta.rate-limit-per-minute`) |
| Wrong keys per address and minute | `20` (`yukta.auth-failures-per-minute`) |
| `/mcp` requests per caller and minute | `600`; costly calls `60` |
| Agent API requests per credential and minute | `600`; wrong credentials `20`; body `65536` bytes |
| Open streams | `500` total, `50` per key |
| Request body | `1MB` |
| Script run time, statements | `10000` ms, `50000000` |
| Expression run time, length | `1000` ms, `10000` characters |

Expressions and scripts are written by trusted authors: whoever can save a definition (ADMIN) can already run code on the server.

## Workers

Workers connect over plain TCP unless TLS is configured; both sides refuse that mode off the local machine unless `yukta.workers.allow-insecure=true`. A worker runs only the plugin types in its own `yukta.workers.plugin-types`.

## Related

* [Configuration reference](https://yukta.infenia.com/reference/configuration.md)
* [MCP tools reference](https://yukta.infenia.com/reference/mcp-tools.md)
* [Supervisor shell reference](https://yukta.infenia.com/reference/supervisors/shell.md)
* [Security model](https://yukta.infenia.com/concepts/security-model.md)
* [Secure the server](https://yukta.infenia.com/guides/operate/secure-the-server.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.