- The operator. Whoever runs the cyrnel process. They choose the env vars, the modules on disk, the key material, and what to expose.
- The API caller. Anyone with a valid
CYRNEL_API_KEY(or any caller if the API runs anonymously). They can install services, write secrets, toggle modules, and run code. - The end services. Whatever the adapters reach. They are downstream of cyrnel and largely outside its control.
API Surface
- Authentication is one static bearer token (
CYRNEL_API_KEY). No scopes, no expiry. Anonymous mode is intended for127.0.0.1only. - No rate limiting is enforced by the API. A noisy or hostile caller will be felt directly by adapters and end services.
- Error envelopes are intentionally terse (
{ "error": "..." }). They do not leak stack traces, but5xxmessages occasionally include exception text. Don’t proxy them to untrusted users verbatim.
Modules
Adapter modules
Adapter modules are the most security-sensitive component cyrnel loads, for three reasons:- They run with full host privileges. Custom adapters loaded via execute() run in the API’s Node.js process. They can read environment variables, open files, make arbitrary network requests, and call native code. There is no sandbox between an adapter and the host. Adapter modules also have access to service secrets and keys as they are required to function.
- They receive decrypted secrets.
ServiceState.secretsis the plaintext secret document the operator stored for a given service. Every enabled adapter sees every secret of every service it owns. - They can choose what to persist. Adapters are expected to keep per-service state in memory, a malicious or careless adapter can write that state anywhere it pleases.
Operator guidance
- Treat
modulesas part of the program. Review additions with the same scrutiny you give to anode_modulesor any program installed your device. - Disable adapters you aren’t actively using. A disabled adapter still has
its row in
modules, but itssetup()is never called. - Don’t share secrets across deployments. A leaked key plus a stolen db is equivalent to leaking every credential the deployment has stored.
- If you’re integrating a third-party adapter, verify what it does with secrets, at minimum, that it does not log them, persist them to disk, or forward them anywhere outside the target service.
Environment modules
The active environment owns the sandbox user code runs inside. The bundledtypescript-ivm:
- Must run each execution in an isolate.
- Should provide no module loader, no filesystem, no network, and no Node built-ins. The only outbound channel is the small set of references from cyrnel.
- Timeouts are enforced at two layers:
the API hard-kills via
setTimeoutusingtimeoutMs(API-level), and the sandbox enforces its own limit viaenvConfig.timeoutMs(environment-level). The worker slot is recreated after either fires.
- Tool invocations bypass the sandbox. When client code calls an invoke, the request leaves the isolate and runs in the host through the adapter. The sandbox limits what code can do directly, not what tools it can ask cyrnel to call.
Secrets
Secrets live inservice_secrets.payload as ciphertext with a
fresh 12-byte IV per write. The auth tag is stored alongside.
- The key is
CYRNEL_SECRETS_KEY, base64-encoded, decoded to 32 bytes. Anything else (missing, short, long, non-base64) fails the request with500 Secrets key is not configured. - The example key in
.example.env(AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=) decodes to 32 NUL bytes. It is not a secret. Anything encrypted with it is effectively in plaintext as soon as the database leaves the machine. Replace it before storing anything. - Key rotation is supported via the key ring mechanism:
CYRNEL_SECRETS_PREVIOUS_KEYSholds old keys (comma-separated, base64). Decryption falls back through the previous keys if the primary key doesn’t match. Each encrypted payload records its key ID (kid) so the system can look up the correct key. When a record is read that was encrypted with a previous key, it is silently re-encrypted with the primary key and persisted. See the key rotation procedure below. - Secrets never leave the API in plaintext. There is no
GET /services/.../secretsendpoint. Patches operate against the decrypted document in memory.
Service & Module Installation (Definition/Archive Fetching)
POST /services, POST /modules (direct install), POST /services/install,
POST /modules/install (registry install), PATCH /services/:serviceId,
PATCH /modules/:moduleId (direct update), and
POST /services/:serviceId/update, POST /modules/:moduleId/update
(registry update) all fetch a URL supplied by or resolved from caller
input, hash the content, and pass it to the adapter’s generateDefinition
(or extract and register the module archive). The fetcher has a few guards:
- Hard timeout of 10 seconds per request.
- Maximum response body of 30 MiB.
- IP-literal hostnames whose range is not
unicastare rejected (loopback, link-local, multicast, private-v4 ranges).
-
DNS names are resolved. If the hostname is not an IP literal, the
guard resolves it via
dns.lookupand checks every returned address against the same range filter.http://internal.example.com/is blocked if it resolves to10.0.0.5.http://localhost/is blocked because it resolves to127.0.0.1. - There is no domain allowlist. The guard only checks IP ranges, not the hostname itself. A hostname that resolves to public unicast addresses will pass.
-
Configurable IP controls. Registry downloads support CIDR-based
allow and block lists:
CYRNEL_REGISTRY_BLOCKED_IPSdenies matching addresses and takes highest priority.CYRNEL_REGISTRY_ALLOWED_IPSallows matching addresses and bypasses the default SSRF guard.CYRNEL_BLOCK_ALL_REGISTRIES=truedenies all registry downloads unless an address matchesCYRNEL_REGISTRY_ALLOWED_IPS.
- Blocked CIDRs
- Allowed CIDRs
- Block-all mode
- Default unicast SSRF guard
- Allow
Operator guidance
- Treat the API key as the security boundary. Do not expose
/services/installor/modules/install(or the API at all) to clients you wouldn’t trust to make outbound network requests from the host. - Use
CYRNEL_REGISTRY_ALLOWED_IPS,CYRNEL_REGISTRY_BLOCKED_IPS, andCYRNEL_BLOCK_ALL_REGISTRIESto restrict which registry addresses may be contacted. - Use
CYRNEL_ALLOWED_IPSandCYRNEL_BLOCKED_IPSto control inbound API access. - For stricter controls (e.g. domain allowlists or network-level restrictions), run cyrnel inside a network namespace or egress firewall that restricts which hosts it can reach.
Data at Rest
If the db leaks, the encrypted secrets are protected by the key only.
Configuration is not, operators must avoid storing credentials in
config blocks. The secretsSchema exists for that exact reason; use it.
Key Rotation Procedure
-
Record the current key and generate a new one:
-
Set the old key as a fallback and replace the primary:
- Restart the server: Existing secrets continue to decrypt using the old key in the fallback list.
- Verify: All existing endpoints work, secrets are readable.
- Optional: Accelerate the transition by touching all records: Iterate over services and modules and call their secrets presence endpoint to trigger re-encryption. Otherwise records are re-encrypted naturally on first read.
-
After all records have been re-encrypted (confirmed by checking
kidin the JSON payload), remove the fallback:Then restart again. Old ciphertext without akidfield (from before the upgrade) are automatically stamped on first read.
Multi-instance rollout
During a rolling update, both old and new instances must be able to decrypt all records. This works because:- Old instances have
CYRNEL_SECRETS_KEY= old key, they decrypt everything natively. - New instances have
CYRNEL_SECRETS_KEY= new key andCYRNEL_SECRETS_PREVIOUS_KEYS= old key, they decrypt with fallback. - After full rollout, old instances can be retired.
Defaults Worth Hardening
- Replace
CYRNEL_SECRETS_KEYbefore first use. - Set
CYRNEL_API_KEYwhenever the API listens on anything other than127.0.0.1. - Restrict the host’s outbound network if
/services/installor/modules/installis reachable by untrusted callers. - Don’t deploy the web UI publicly with credentials baked into the bundle.
- Review adapters before installing them`.