This template shows the smallest useful shape of a confidential CRE workflow: register a handler that runs in a TEE, pull a secret inside the enclave, make a capability call from inside the enclave, then hand only the non-sensitive result back to the Workflow DON for consensus-backed operations.
Quick navigation:
What This Template Does
By default, a CRE workflow callback runs on Workflow DON nodes, where node operators can inspect what it is computing. That is acceptable for many workflows, but not for when sensitive or proprietary data is required for workflows.
A Confidential Workflow executes the logic requiring confidential inputs in a hardware-isolated enclave. This template demonstrates the minimal end-to-end shape in four steps:
| Step | What it demonstrates | API |
|---|---|---|
| 1 | Register a handler that runs inside a TEE | cre.handlerInTee(trigger, fn, tees) |
| 2 | Fetch a secret inside the enclave | runtime.getSecret({ id }) / runtime.GetSecret() |
| 3 | Make a capability call from inside the enclave | HTTPClient.sendRequest(runtime, req) |
| 4 | Cross back to the DON for anything needing consensus | runtime.usingTheDons() |
Architecture
โโโโโโโโโโโโโโโโ
โ CronTrigger โ fires on schedule (runs on the Workflow DON)
โโโโโโโโฌโโโโโโโโ
โ DON hands the triggered request to an enclave
v
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ENCLAVE โ
โ โ
โ Step 2: runtime.getSecret({ id: 'API_TOKEN' }) โ
โ โฒ โ
โ โโโ released by Vault DON, decrypted in-enclave โ
โ โ
โ Step 3: HTTPClient.sendRequest(runtime, { ... }) โ
โ Authorization: Bearer <secret> โ
โ โฒ trust from enclave attestation, not consensus โ
โ โ
โ Logic with confidential data: score(response) vs. scoreThreshold โ
โ -> verdict = APPROVE | REJECT โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโคโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Step 4: runtime.usingTheDons()
โ ONLY the verdict + score cross out
v
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ WORKFLOW DON - donRuntime.report({ ... }) โ
โ BFT consensus verifies the enclave attestation, then signs โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
How It Works
my-workflow/workflow.ts and my-workflow/workflow.go follow the same confidential pattern:
- Register the cron handler with
cre.handlerInTee, constrained to[{ tee: 'nitro', regions: ['us-west-2'] }] - Fetch
API_TOKENinside the enclave - the Vault DON releases it only into an attested enclave - Call the configured URL from inside the enclave, sending the secret in the
Authorizationheader - Score the response against
scoreThreshold- this represents the private policy you want to keep hidden - Cross back with
usingTheDons()and report only the verdict and score - never the secret or raw response
TypeScript Implementation
Getting Started with TypeScript
1 Install dependencies
cd my-workflow && bun install && cd ..
2 Configure secrets
cp .env.example .env
Set SECRET_API_TOKEN in .env. secrets.yaml maps the workflow-facing secret ID API_TOKEN to that environment
variable:
secretsNames:
API_TOKEN:
- SECRET_API_TOKEN
With the default echo endpoint, any non-empty value works.
3 Run tests
cd my-workflow && bun test
4 Simulate
cre workflow simulate my-workflow --target staging-settings --non-interactive --trigger-index 0
Expected output:
[SIMULATION] Running trigger trigger=cron-trigger@1.0.0
โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ Trigger requested TEE Execution your trigger will run in one of the following Tees: โ
โ - AWS Nitro in us-west-2 โ
โ The simulator is not a real TEE, and is meant to debug. โ
โ Do not use it for sensitive information. โ
โ During real execution, user logs for this trigger will not be visible, and will not leave the TEE. โ
โ They are presented in the simulator for debugging only. โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
[USER LOG] Enclave computation complete. verdict=REJECT
โ Workflow Simulation Result:
"REJECT (score: 371, secret reached API: true)"
Three things to notice:
- The simulator confirms the TEE constraint it resolved (
AWS Nitro in us-west-2) and warns that it is not a real enclave. In real execution those logs never leave the TEE. secret reached API: truemeans the Vault DON secret was fetched inside the enclave and arrived in the outbound request'sAuthorizationheader.- The verdict flips between
APPROVEandREJECTfrom run to run. That is expected: the score is derived from the live response body, and the echo endpoint includes a per-request trace ID.
Go Implementation
Getting Started with Go
1 Install dependencies
cd my-workflow && go mod tidy && cd ..
2 Configure secrets
cp .env.example .env
Set SECRET_API_TOKEN in .env. secrets.yaml maps the workflow-facing secret ID API_TOKEN to that environment
variable:
secretsNames:
API_TOKEN:
- SECRET_API_TOKEN
With the default echo endpoint, any non-empty value works.
3 Run tests
cd my-workflow && go test ./...
4 Simulate
cre workflow simulate my-workflow --target staging-settings --non-interactive --trigger-index 0
Expected output:
[SIMULATION] Running trigger trigger=cron-trigger@1.0.0
โญโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฎ
โ Trigger requested TEE Execution your trigger will run in one of the following Tees: โ
โ - AWS Nitro in us-west-2 โ
โ The simulator is not a real TEE, and is meant to debug. โ
โ Do not use it for sensitive information. โ
โ During real execution, user logs for this trigger will not be visible, and will not leave the TEE. โ
โ They are presented in the simulator for debugging only. โ
โฐโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฏ
[USER LOG] Enclave computation complete. verdict=REJECT
โ Workflow Simulation Result:
"REJECT (score: 371, secret reached API: true)"
The Go and TypeScript versions share the same confidential workflow shape. The main differences are the language
tooling and the SDK surface: Go uses runtime.GetSecret() and the Go HTTPClient implementation, while TypeScript
uses runtime.getSecret() and the TypeScript SDK.
Configuration
my-workflow/config.staging.json:
| Field | Description |
|---|---|
schedule | Cron expression (6 fields, seconds first) |
url | Endpoint called from inside the enclave |
secretId | Secret ID fetched with runtime.getSecret() / runtime.GetSecret(); must match secrets.yaml |
scoreThreshold | Threshold the confidential scoring compares against |
TEE Constraints
The third argument to handlerInTee declares which enclaves the handler accepts:
{
} // any registered TEE, any region
{
regions: ["us-west-2"]
} // any TEE, restricted to a region
;[{ tee: "nitro", regions: ["us-west-2"] }] // specific TEE types and regions
AWS Nitro in us-west-2 is currently the only registered TEE type and region.
Confidentiality Boundary
Understanding what is and is not protected matters more here than in a regular workflow.
| Protected by default | Not automatically protected |
|---|---|
| Secrets the Vault DON releases into the enclave | Triggers, chain reads, and chain writes - these always run on Workflow DON nodes |
| Sensitive inputs and intermediate values you do not share outside the enclave | Your workflow's source code and deployed binary |
| Capability calls made from inside the enclave | Capability calls not routed through the enclave |
| Enclave execution memory, while your computation runs | Reports, calldata, and any output you deliver outside the enclave |
Consequences worth internalizing:
- Your handlerโs source code and compiled binary are not confidential just because part of its logic runs inside an enclave. Confidential Workflows protect only the confidential data processed during execution inside the enclave, including Vault DON secrets (such as API keys), HTTP response, and intermediate values that are not explicitly shared outside the enclave. Support for confidential logic or workflow is planned as a future enhancement, not part of the current beta.
usingTheDons()is a one-way door. Anything you pass into a capability call on that runtime executes on Workflow DON nodes like any non-confidential call. Cross over only what does not need to stay hidden.- Do not log from inside the enclave in production. Logs leave the confidentiality boundary. This template logs only the verdict, and the comment marks it for removal before deploying.
- Keep enclave logic deterministic. The enclave result is attested and verified by DON consensus.
- Multiple confidential workflows may execute within the same enclave. Workflows are isolated from one another by the wasmtime. Dedicated per workflow enclave isolation is planned as a future enhancement.
Which Secrets Belong in an Enclave?
Not every secret needs enclave-level protection.
Higher value - consider enclave execution: wallet and CA private keys; exchange, custody, payment-processor, banking, or LLM-provider credentials; OAuth client secrets, JWT signing keys, KMS keys; payment data, health data, other PII.
Lower value - regular DON execution is usually fine: API keys for publicly available data (weather, explorers, public price feeds, public RPCs); public wallet addresses.
The common thread: a secret belongs in the enclave if disclosure would expose more than the workflow needs.
Customization
- Put your real logic in the enclave - replace
scoreResponseinworkflow.tsorworkflow.gowith the policy, threshold, or model you need to keep private - Deliver the report onchain - pass the report from Step 4 to
evmClient.writeReport(donRuntime, report); the RPCs inproject.yamlare already set up for Sepolia. See the Keeper Bot or Event Reactor templates for the full write path - Change the trigger -
handlerInTeeaccepts any CRE trigger, same ashandler; swap cron for a log trigger to react to onchain events confidentially - Fetch more secrets - call
runtime.getSecret()/runtime.GetSecret()once per secret
Security
- Never commit
.envfiles or secrets -.gitignorecovers*.env - Remove or gate every
runtime.log()inside the TEE handler before deploying - Audit what crosses
usingTheDons(); that data is no longer confidential
Further Reading
- Confidential Workflows in CRE - concepts and use cases
- Making a Workflow Confidential - step-by-step guide
- Confidential Workflows Client SDK Reference - full API
- Confidential HTTP - for a single outbound request, without a full confidential handler
- confidential-compute-examples - production-shaped reference workflows
CREATED BY CHAINLINK LABS