Skip to content

SECURITY AND GOVERNANCE

Nothing moves without permission

Security and governance are the same thing here, not two features that sit next to each other. A Grant is least privilege. Deny before I/O is access control. A receipt is the audit trail. Revoking a Grant is incident response.

This page is every security property EKKA has, and next to each one, the command that proves it.

  • Governed

    Every action is authorized before it happens. No Grant, no I/O.

  • Proven

    Every allowed action is signed after it happens, into a chain anyone can verify offline.

  • Private

    Your prompts, your rows, your files and your credentials never reach EKKA.


1. Authorized before it happens

An agent asks to do something. EKKA decides first, and a refusal is complete: no socket is opened, no DNS lookup is made, no secret is read from your vault.

The refusal itself is recorded as a signed event in your audit chain, the same chain an allowed action lands in. "It was blocked" is evidence, not a claim.

Read the decision with ekka run show <run-id>, and find the signed event with ekka audit list.

Preview any decision without executing it:

ekka gate postgres list --instance demoV1 --resource customers --check

Read the decision after the fact:

ekka run show <run-id>

A refusal and an allow are different shapes of the same evidence

An allowed action produces a signed receipt chain you verify offline against published keys. A refusal produces a signed deny event in your audit chain, carrying who was refused, what they asked for, and the reason code. There is no receipt for work that never ran.

Both are signed. Neither depends on our dashboard, or on us.

One thing we do not put in the chain: our own bugs. If EKKA cannot classify an operation or cannot parse a token it just issued, that is an error, not a decision about you. Recording it as a refusal would make "we were broken" indistinguishable from "you were not allowed".

--check reports ALLOWED or DENIED with no I/O and no cost. It is the same decision the real call gets.

2. Permission is a Grant, and it is live

You do not write access-control code. You set a Grant: this agent, this operation, this resource, through this gate, until you revoke it.

ekka gate grant list                 # what is authorized right now
ekka gate grant revoke <grant-id>    # the next attempt is refused, live

Revocation is not a deploy. The operation that worked a second ago is refused a second later, and the refusal is recorded like any other decision.

Grants are also time-boxed where you want them (--ttl), and the token a gate actually receives is minted just in time for one operation rather than held open.

3. What EKKA cannot see

Govern decides whether an action is allowed. It does that without seeing the content of the action. Prompts, model output, database rows, file contents: none of it reaches EKKA. What reaches EKKA is the shape of the request and cryptographic digests of the result.

We call this a No Knowledge Proof. It is not zero-knowledge cryptography, it is something blunter: we can prove it because we signed it, and we never saw it.

That property holds whether you run your own Enclave or use a hosted one. Where your data lives is a choice; not being read is not a choice.

What leaves your machine is the field-by-field detail, including the one thing we do receive when a run finishes and why.

4. Credentials stay on your machine

Secrets live in your Enclave's vault, encrypted at rest and sealed by your operating system's keychain. The gate injects a credential into the outbound call; nothing upstream of it ever holds one.

ekka secret list        # names and metadata. Never values

Three consequences worth stating, because each one is a real attack that does not work here:

  • A caller cannot set an authorization header. The gate refuses the request rather than letting a plan overwrite the credential it was given.
  • A refusal never quotes the request. Error text cannot leak a credential that was sitting in a query string, because the message names the field and never the value.
  • Copying the vault files off the machine gets you nothing. The sealing key is in the keychain, not in the files.

5. What an agent cannot do even with a Grant

Some limits are structural, which means they hold even if every other check somewhere failed.

  • A read cannot write. A read-class call has no slot on the wire for a method or a body. It is not that a check refuses the mutation, it is that there is nowhere to put one.
  • An origin is pinned. A connection reaches the host it was made for. It cannot be redirected to another.
  • Narrowing rules bind method and path together. A connection can be limited to GET /v1/messages and nothing else on the same host.
  • Network reach is declared. A connection states whether it may reach the public internet, your loopback, or your private network. The default refuses a local address outright.

6. Nothing changes quietly

  • A plan is frozen when you create it. It runs the steps it was created with. Publishing something new later does not change what it does.
  • A published skill version is never rewritten. Publishing the same name again makes the next version. A plan naming @1 keeps running @1.
  • Cataloged APIs are immutable. Changing an API means a new version beside the old one, so a connection pinned to the old one keeps behaving.
  • Connection records are fingerprinted. A record altered on disk by anything other than EKKA is refused before the call is considered.
  • The audit trail is append-only, enforced in the database rather than by convention: a REVOKE on the runtime role and a trigger on top of it, because a REVOKE does not bind a table's owner.

You cannot check our database privileges, so check the consequence

Append-only is enforced on our side, which means you cannot run a command against it, and a claim you cannot check is a claim you have to take on trust. That is not how the rest of this page works.

What you can check is the property it exists to produce: that nothing in your chain was altered after the fact. ekka audit verify recomputes every hash link and every signature. If a row had been edited or removed, that is what would catch it, whatever our privileges say.

Note what it does not tell you: whether something that happened is missing from the chain in the first place. Integrity and completeness are different properties. See the note in Governance receipts.

7. Proof anyone can check, with us switched off

ekka receipts verify

That recomputes the hash chain and checks every signature on your machine, with no EKKA service in the loop. If checking our proof needed us, it would not be proof.

An auditor does not need an EKKA account, and does not need to trust your screenshot. They need the chain and the public keys.

Governance receipts explains what a receipt contains and how to read one.

8. Nothing is watching you

The ekka binary contains no third-party analytics. No product analytics, no session recording, no activation telemetry. Check the binary you installed:

strings $(which ekka) | grep -icE 'posthog|sentry\.io|segment\.io|amplitude\.com|mixpanel|datadoghq'

That prints 0. It is the exact list our release pipeline checks on every build, so the command you run is the check that gates the release rather than a friendlier version of it.

Crash reports are first-party, minimal, and optional. The error text stays on your machine, because a crash message can contain whatever the program was holding at the time.

export DO_NOT_TRACK=1     # or EKKA_CRASH_REPORTS=0

Check it yourself

Every claim on this page, in one table.

The claim The command
A refusal happens before any I/O ekka gate <type> <op> --resource <name> --check
These are the permissions that exist right now ekka gate grant list
Revoking is live, not a deploy ekka gate grant revoke <grant-id>
Secrets are names to us, never values ekka secret list
This is every endpoint my Enclave contacts ekka enclave config
The proof verifies without EKKA ekka receipts verify
The decision record for one run, including a refusal ekka run show <run-id>
Nothing in my chain was altered after the fact ekka audit verify
There is no analytics vendor in the binary strings $(which ekka) \| grep -icE 'posthog\|sentry\.io\|segment\.io\|amplitude\.com\|mixpanel\|datadoghq'

Reporting a vulnerability

Found something? Write to [email protected], the address in our security.txt. Our full policy, including safe harbor and what to expect, is at ekka.ai/security.