Skip to main content
A fresh Yukta server is reachable only from the machine it runs on. This page covers how to open it to a network, how API keys and roles work, and the settings that bound what a workflow may do.
Yukta is pre-beta (0.0.1-SNAPSHOT). Setting names and access rules may change before v0.1.0.

Default posture

  • The server listens on 127.0.0.1 and takes no key. Only processes on the same machine can reach it.
  • With no key set, a host and origin check protects the local server from other web pages (see Host and Origin protection).
  • PROCESS_EXECUTOR runs nothing until you allow commands.
  • Workflows can read only a short list of environment variables.

Exposing the server

To listen on another address, set both of these: The server refuses to start on a non-loopback address with no key. The container image binds 0.0.0.0, so it needs -e YUKTA_API_KEY=<key> even when you publish the port on loopback only. Yukta serves plain HTTP. Put a reverse proxy that terminates TLS in front of it when clients are not on the same host, because keys travel in request headers. See Deployment.
Setting only yukta.mcp.api-key satisfies the start-up check but protects /mcp alone. The REST API stays open. Set yukta.api-key or yukta.api-keys whenever the server is reachable from a network.

API keys

A client sends the key on every request in one of two headers:
The same keys guard REST (/api/**), the MCP endpoint (/mcp) and the management endpoints (/actuator/**, except /actuator/health). These refusals carry no JSON body. Handle them by status code.

One key

yukta.api-key defines a single key with the ADMIN role.

Named keys

For several people or agents, define a list. Each entry has a name, a key, a role and optional sessions.

Hashed keys

A key that starts with sha256: is the SHA-256 digest of the real key, in 64 hexadecimal digits. The server then never holds the plain key. Clients still send the plain key.
The first example entry above uses the digest of example-ci-key-123. Use long random keys. Keys are compared as digests in constant time.

Rotation

Several keys can be valid at once. To rotate without downtime, add the new key as another entry, move clients to it, then remove the old entry.

Roles

Defining a workflow is an ADMIN action because a workflow can run commands, scripts and SQL. See Workflow authorship.

MCP

The MCP endpoint uses the same keys. Each tool call is checked against the key’s role: A key limited to sessions must pass a sessionId argument that it may reach. For any key that is not an unrestricted ADMIN key, a POST body that cannot be parsed is refused with 403 and one larger than 1 MiB with 413. See MCP.

Session-limited keys

A key with sessions reaches only these /api paths, and only for its own sessions:
  • /api/sessions/{session}/...
  • /api/workflow/{session}/...
  • /api/executions/{executionId}/... when the execution belongs to one of its sessions
Every other path is refused with 403, including the global event stream, the worker list and the audit list. A session-limited key never reaches /actuator/**.

Host and Origin protection

While no key of any kind is set, the server checks every request to protect a local server from other web pages and DNS rebinding:
  • The Host header must be localhost, 127.0.0.1, [::1] or listed in yukta.allowed-hosts.
  • A changing request (any method except GET, HEAD and OPTIONS) that carries an Origin header must come from the same host as the request, or the origin must be listed in yukta.allowed-origins.
A refused request gets 403 with no body. If you reach the server through a proxy under another host name and no key is set, list that name:
The check is off once any key is configured.

Audit actor naming

Control commands (pause, stop, skip, signal, restart, limit and priority changes and others) are recorded in the execution log with who sent them: List recent commands, newest first, with GET /api/control/audit. The query parameters are limit (1 to 500, default 100) and executionId. Entries show the command, whether it was applied or refused, and the reason for a refusal. The audit covers control commands only. Ordinary reads and starts are not audited by key.

Process execution

PROCESS_EXECUTOR refuses every command until you configure it.
Use allow-any only when every workflow author is fully trusted.

Script limits

JavaScript scripts run with a time limit and a statement limit. Both are system properties: Scripts can reach only a short list of date, time and basic value types from the host. They have no memory limit.

Variables and secrets

Placeholders such as ${env.NAME} and ${sys.name} in a node’s configuration read the server’s environment, but only from an allow-list:
  • Environment variables starting YUKTA_VAR_, and system properties starting yukta.var..
  • A short list of harmless names: HOME, USER, LANG, TZ, HOSTNAME, PWD, PATH, and a few system properties such as user.name and os.name.
  • Names listed in YUKTA_VARIABLES_ALLOWED (environment) or yukta.variables.allowed (system property), separated by commas.
Any name containing PASSWORD, PASSWD, SECRET, TOKEN, CREDENTIAL, PRIVATE or KEY stays blocked, even when listed. A blocked or unlisted name fails the message like a plugin error. Secrets are written decrypted:name in a node’s configuration, so the value never appears in a stored workflow. The server reads the value from the environment variable YUKTA_SECRET_ followed by the name in upper case, with every character other than letters and digits replaced by _. For example decrypted:db.password reads YUKTA_SECRET_DB_PASSWORD. See Variables and expressions.

Request size limit

The server reads request bodies up to spring.codec.max-in-memory-size (YUKTA_LIMITS_MAX_BODY), 1MB by default. A larger body is answered with 413. The limit covers start payloads, workflow definitions and MCP calls.

LLM and MCP call filters

These settings apply to every LLM_CALL and MCP_TOOL_CALL node, whatever the node says, so a model cannot choose its way around them. A refused call fails as bad input and is not retried. A pattern that contains a comma, such as a{1,3}, must be written as an indexed entry: yukta.llm.deny-input-patterns[0]=.... Per-run token, cost and call budgets are set in the node. See AI and agents.

TLS for workers

Remote workers connect to the control plane over a persistent connection that is plain TCP unless you configure TLS. Use a shared token and mutual TLS on both sides:
The worker checks the control plane’s host name against its certificate. A worker also runs only the plugin types in its own yukta.workers.plugin-types, so a compromised control plane cannot make it run other types. See Remote workers.

Workflow authorship is a trusted operation

Anyone who can define or change a workflow decides what its nodes do. Nodes can run commands, scripts and SQL, call HTTP endpoints, read and write files inside a configured directory, and call models and tools. HTTP_REQUEST and SQL_QUERY connect to whatever address or database the workflow names; there is no allow-list setting for them. The settings above limit the largest risks, but they do not make an untrusted author safe. Give the ADMIN role, and with it the right to define workflows, only to people you would let run code on the server. Keep secrets out of workflow definitions: use decrypted:name references. Without any key, everyone who can reach the server has this right. That is why the default is loopback only.

Not covered by keys

These parts of the server need no key:
  • /actuator/health
  • The interactive API documentation, /swagger-ui.html and /v3/api-docs
  • The web UI’s static files and pages
Restrict them at the proxy if the API description should not be public.

Reporting vulnerabilities

Report a vulnerability privately to the maintainers. Use the repository’s security policy. Do not open a public issue for it.