← All articles

How to prove to auditors that no employee can access your customers' keys

Here is how to set up key custody where no employee has a technical path to your customers' keys, the checks an auditor can run without trusting you, and the limits you should tell them about.

Lit Protocol

The strongest answer you can give an auditor is a design where no employee has a technical path to the keys, plus evidence the auditor can check without trusting you. On Lit Protocol, keys are derived inside an attested hardware enclave, and Lit's own code never stores or exports them. The rules for using them live in a contract on Base, and you can make your own multisig the only account the contract accepts rule changes from. An auditor can verify the code running in the enclave, read the rules, and see every change as a signed transaction.

I will go through what an auditor usually asks, how each answer works on Lit, the commands they can run, and the limits you should tell them about.

What the auditor will ask

The first question is where the key lives and who can get it. The second is who can change the rules for using the key. The third is how they can see every change that was made. A good answer to each one points to something the auditor can check for themselves.

Where the key lives

On Lit, a key is derived inside a trusted execution environment, an Intel TDX enclave, from a root key that the enclave only receives after it proves which code it is running. The key is never written to disk. Your applications do not hold it. They hold usage API keys, and a usage key can only run the specific Lit Actions you have approved for a wallet. A Lit Action is a JavaScript function, and Lit identifies it by a hash of its code.

This gives the question "who can use the key" a precise answer. It is the code whose hashes are in a group with the wallet. Check that no group containing the wallet is set to allow all actions. If one of the approved actions is written to return the private key, it can, so the actions themselves belong in your code review, the same way any code that touches customer keys would.

Who can change the rules

A new Lit account starts in API mode. In API mode Lit holds the account's owner credential and relays your changes to the contract, so you are trusting Lit's server to do what you ask. For an audit like this one you want ChainSecured mode, where a wallet you control owns the account on Base.

To switch, sign in to the Lit dashboard, open the account menu, and click Convert to ChainSecured. Connect the wallet that should own the account and sign the request. The wallet can be a Safe multisig, and for this use it should be. The Safe must already be deployed on Base, and its signers should be ready to sign within five minutes, because the signed request expires. The conversion cannot be undone. Your groups, wallets, and usage keys stay attached. After the conversion, you pay Base gas for every change, from the signer who executes each Safe transaction.

From then on, adding an action, adding a wallet to a group, or creating a usage key is a transaction your Safe has to approve. The old account API key can no longer change anything, and neither can a usage key. No single Lit employee can change your rules either. The contract only accepts rule changes from your Safe. Lit's own multisig can still upgrade that contract and approve the code the enclave runs, which I cover in the limits below.

How the auditor checks it

The auditor can check the enclave first. Phala's Trust Center publishes a report for Lit's production enclave that verifies the Intel hardware quote, the hash of the deployed code, the OS measurements, and that TLS ends inside the enclave. The Verify in 30 Seconds page links to it.

Next, they can confirm on Base that the code the API reports is the code governance approved.

COMPOSE_HASH=0x$(curl -sf https://api.chipotle.litprotocol.com/info \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["compose_hash"])')
cast call 0x3F91Deaf16FF7C823eE65081d6bAFA1cEea05FfC \
  "allowedComposeHashes(bytes32)(bool)" "$COMPOSE_HASH" --rpc-url https://mainnet.base.org
# true

This check only shows that the hash the server reports is approved. The Trust Center report, or Phala's verification steps linked from the full verification guide, is what shows the server is actually running it.

Then they can look at your Safe. Its signers and threshold are public.

cast call $YOUR_SAFE "getThreshold()(uint256)" --rpc-url https://mainnet.base.org
cast call $YOUR_SAFE "getOwners()(address[])" --rpc-url https://mainnet.base.org

Every change to your rules is a transaction from that Safe. Your Safe's history, together with the history of Lit's account contract at 0xaaaaa9120fe271f653cfdb6bf400db93d2dea7aa, is the full change log. The auditor does not need access to any of your systems to read it.

The limits to tell your auditor

There are limits, and an auditor will find them, so it is better to state them. A Lit Safe that needs 2 of its 4 signers approves the code that runs in Lit's enclave, and a release approved that way could read any key. The same Safe can upgrade the account contract that stores your rules. There is no timelock on either today, so a change takes effect when the signers approve it, but every such change is a public transaction on Base. The list of allowed OS images and key service instances is governed by a separate Safe that Phala controls.

If your auditor needs those decisions to sit with you, Lit is open source and you can run your own deployment with your own Safe approving releases. To also own the OS image list, you run it on your own TEE hardware with your own key service instead of Phala Cloud. The self-hosting page explains the options.

Working with Lit

Lit works with security and compliance teams to set up key custody that an auditor can check. To talk about your setup, use the Lit contact form. The two account modes are explained at developer.litprotocol.com/management/account_modes.