skip to content
Unforeseen Consequences
Table of Contents

Every Ethereum validator needs a way to sign attestations and proposals. The private key that signs those messages is worth its weight in staked ETH — lose control of it, and you lose your stake. Remote signers exist to isolate that key from the validator client, but isolation is only as strong as the trust model behind it.

This post examines three remote signers — Web3Signer, Dirk, and Containment Chamber — through the lens of a single question: who do you actually trust, and what happens when that trust is misplaced?

The Trust Problem

A remote signer sits between your validator client and your private keys. The validator client sends “please sign this attestation” over the network, and the signer checks it against slashing protection rules, signs it, and returns the signature. Simple enough.

But this architecture introduces a trust boundary. Someone — a person, a team, an infrastructure — now holds your keys. The security of the entire system depends on who that is and how the keys are protected.

The uncomfortable truth: most remote signing setups trust a single team with full access to all keys. Whether that team runs one process or ten distributed nodes, if they control the infrastructure, they control the keys.

Web3Signer: Trust the Network

Web3Signer trust model diagram showing validator client traffic, host runtime boundary, key sources, slashing protection, and persistent Key Manager imports

Web3Signer by Consensys is the de facto standard. It loads BLS private keys into process memory and exposes an HTTP REST API for signing.

What it gets right

  • PostgreSQL-backed slashing protection with advisory locks — supports multi-instance HA
  • Multiple key storage backends (filesystem, HashiCorp Vault, Azure Key Vault, AWS Secrets Manager)
  • Battle-tested, widely deployed, well-documented
  • Optional TLS client authentication for transport-level access control

Where the trust model breaks

No per-key application policy. Web3Signer relies on transport and network controls — bind addresses, TLS, and optional client-certificate allowlists or CA-authorized clients. Those controls can decide which clients reach the service, but they do not express signing policy at the validator-key or operation level. Once a client is admitted to the signing API, Web3Signer does not attach that request to a scoped token policy such as “this caller may sign only for these keys and never request voluntary exits.”

Keys live in process memory. Regardless of which vault backend you use to store keys at rest, every BLS private key must be loaded into memory before it can sign. If the host is compromised while the signer is running, runtime key material is in scope.

Key Manager API writes keystores to disk. Until recently, when you imported a keystore via the Key Manager API (POST /eth/v1/keystores), Web3Signer would write both the encrypted keystore and its password to the local filesystem. The password — in plaintext. This meant that any process with filesystem read access on the Web3Signer host could extract every imported key.

This was addressed in Web3Signer 25.11.0 via PR #1118 (commit 8d3db2c), which added an experimental, hidden CLI flag (--Xkey-manager-skip-keystore-storage) to keep imported keys in memory only. As of Web3Signer 26.4.2, the flag is still marked EXPERIMENTAL in the source and the default behavior on POST /eth/v1/keystores remains “write keystore to disk.” Notably, Consensys’s own distroless --read-only Docker image (shipped in 26.4.1) explicitly recommends enabling this experimental flag at runtime — meaning the hardened-deployment path now requires operators to opt into an explicitly experimental, restart-fragile import mode.

Web3Signer trust summary

You trust:

  • The host machine completely (memory, disk, network)
  • The network and TLS perimeter to admit only clients that should have broad signing access
  • The operators who manage the server
  • That no one reads persistent Key Manager imports unless skip-storage mode is deliberately enabled

Compromise model: gain access to the host → extract all keys from memory or disk.

Dirk: Trust the Ceremony

Dirk trust model diagram showing validator client traffic, mTLS, distributed key generation, three signer nodes, key shares, permissions, and threshold signing

Dirk by Attestant takes a fundamentally different approach. Instead of storing complete keys, it uses distributed key generation (DKG) to split each validator key into N shares, where any T shares can produce a valid signature (threshold signing). The full private key never exists in one place — not even during generation.

What it gets right

  • Threshold signing (t-of-n): With a 2-of-3 setup, you need two Dirk instances to cooperate for a valid signature. One compromised instance doesn’t compromise the key.
  • mTLS everywhere: All communication — client to Dirk, Dirk to Dirk — uses mutual TLS with certificate-pinned identities.
  • Fine-grained permissions: Per-client, per-wallet, per-account, per-operation authorization with explicit deny support.
  • Slashing protection: Dirk tracks proposal and attestation signing state and supports EIP-3076 slashing-protection import/export.
  • No full key materialization: During DKG, each instance generates its own randomness. The composite key is a mathematical construct — no single process ever holds it.

The single-operator problem

Dirk’s strongest security model depends on a critical assumption: the N Dirk instances are operated by independent, mutually distrusting parties. The strongest key-custody benefit of threshold signing comes from distributing trust — an attacker must compromise T separate organizations to reconstruct a key.

But in practice, most Dirk deployments are run by a single team. The same organization sets up all three instances, controls the certificate authority, manages all servers, and holds all key shares on their own infrastructure.

When this happens, threshold signing no longer distributes key custody across organizations:

  • Key shares: All on one team’s infrastructure. A breach of that operating boundary can reach enough shares to reconstruct the key.
  • Insider threat: Any team member with sufficient access can reconstruct the full key.
  • Certificate authority: One entity controls the CA, all server certs, and all client certs.
  • DKG ceremony: The same team runs all participants. The “distribution” is architectural, not organizational.

What remains is availability and threshold-gated signing safety: any t-of-n instances can produce a signature, so you survive node failures, and a slashable signature still requires enough participants to approve the signing request. Those are valuable properties. The issue is narrower: if one team controls every participant, the threshold no longer distributes organizational trust.

The Dirk documentation acknowledges this partially:

“In a real deployment the Dirk instances should be on different servers for both security and availability purposes.”

But “different servers” is a physical/availability concern. The documentation never explicitly states that different servers must be controlled by different entities for the key security benefit to hold.

Single-operator Dirk keeps threshold signing’s safety and availability properties but loses its trust-distribution property. The DKG math still requires multiple instances to cooperate on every signature and still survives node failures, but when one team administers every share, the organizational boundary protecting the key is that one team.

Dirk trust summary (multi-operator)

You trust:

  • That < T operators collude (the core security assumption)
  • The certificate authority that issues all certs
  • That each operator’s infrastructure is independently secure
  • That the DKG ceremony was honest
  • That Dirk’s slashing-protection state is preserved and enforced by the participating signers

Dirk trust summary (single-operator)

You trust:

  • The single team that controls all instances (same as Web3Signer)
  • That team’s slashing-protection state and operational discipline
  • Plus additional complexity, latency, and operational burden

Compromise model (multi-operator): compromise T independent organizations → reconstruct key. Compromise model (single-operator): compromise the operating boundary that controls enough shares → reconstruct key.

Containment Chamber: Trust the Boundary You Choose

Containment Chamber standard mode diagram showing host process trust boundary, scoped auth policies, anti-slashing backend, sealed boot, KMS unseal, operator quorum, and encrypted DynamoDB key storage

Containment Chamber takes a different approach to the trust problem, but its security model should not be flattened into a single claim. It has two deployment modes with different trust boundaries:

  • Standard mode: a hardened Web3Signer-compatible signer running as a normal Linux process or container.
  • Nitro Enclave mode: the same signing pipeline running inside an AWS Nitro Enclave, with attested KMS decrypts and attestation-bound TLS.

Architecture

Containment Chamber is a Web3Signer-compatible remote signer. It provides the same HTTP API, so it’s a drop-in replacement for any validator client that supports Web3Signer.

The signing path is the same in both modes:

  1. A validator client sends a Web3Signer-compatible signing request.
  2. Backpressure rejects overload before expensive work starts.
  3. Auth policies check route scope, validator key, source constraints, and operation.
  4. The network guard rejects wrong-genesis requests.
  5. Anti-slashing checks run before every signature.
  6. BLS signing happens only after the key is found and every check passes.

What changes between modes is not the signing logic. What changes is where the trust boundary sits.

Standard mode: a hardened remote signer

In standard mode, Containment Chamber runs as a normal process or container. This is the direct replacement path for Web3Signer deployments on bare metal, Docker, Kubernetes, or conventional TLS.

Compared with Web3Signer, standard mode adds several meaningful controls:

  • Application-layer authorization: tokens can be scoped by route family, validator key, signing operation, and optional source constraints.
  • Check-before-sign anti-slashing: every signing request is checked against the slashing-protection backend before BLS signing.
  • No plaintext token storage: auth tokens are stored as HMAC hashes rather than raw bearer tokens.
  • DynamoDB + KMS key source: validator keys can be stored encrypted with AES-256-GCM under a master key protected by KMS-wrapped Shamir shares.
  • Runtime import discipline: Web3Signer-compatible Key Manager API imports are memory-only and vanish on restart.
  • Canary keys for misuse detection: designated public keys that should never sign in normal operation emit a warning log and increment a Prometheus metric (containment_canary_signing_total) the moment any signing attempt references them. Signing isn’t blocked — it’s a tripwire.

This is already a materially stronger model than “anyone who reaches the signing port can sign with any key.” But it does not remove the host from the trust boundary.

In standard mode, the host running the signer is trusted. A compromised kernel, root account, container runtime, or malicious replacement binary can still read process memory while the chamber is unsealed. KMS and Shamir improve at-rest custody; they do not make runtime memory invisible to the host.

Auth policies and token boundaries

Containment Chamber’s auth model is an architectural difference from Web3Signer, not just an implementation detail. A token can be tied to one or more policies, and policies can allow or deny by:

  • API scope, such as signing, public-key discovery, key import, or chamber management.
  • Validator public key.
  • Ethereum signing operation, such as attestations or voluntary exits.
  • Optional source CIDR for stable validator-client networks.

That enables one signer to serve multiple validator clients or tenants without giving every caller access to every loaded key. A monitoring token can see status without signing. A validator-client token can sign only for its assigned keys. A dedicated exit workflow can be allowed to request voluntary exits without broad management access.

The important trust point is that network access is no longer equivalent to signing access. A caller must still match the policy attached to its token.

Standard mode trust summary

You trust:

  • The host runtime that runs the signer.
  • The operators who can deploy, configure, and restart that runtime.
  • The anti-slashing backend to preserve signing history.
  • The KMS keys and IAM policies that wrap the master-key shares.
  • The auth policy database and management tokens.

Compromise model: compromise the running host while the signer is unsealed → runtime key exposure is possible. Compromise enough KMS-wrapped Shamir shares → persistent DynamoDB-stored keys can be decrypted.

Nitro Enclave mode: move the key boundary into attested hardware

Containment Chamber Nitro Enclave mode diagram showing parent EC2 or Kubernetes forwarding, enclave trust boundary, aTLS, NSM attestation, attested KMS decrypt, and isolated enclave memory

Nitro Enclave mode changes the trust story. The parent EC2 instance or Kubernetes pod no longer sits inside the key-material trust boundary. It runs nitro-cli, ingress and egress proxies, config bootstrap, credential forwarding, and log forwarding, but the signer itself runs inside the enclave.

Inside the enclave live the sensitive parts:

  • the signing pipeline,
  • decrypted validator keys,
  • the reconstructed master key,
  • the AWS Nitro Security Module handle,
  • the aTLS listener,
  • and the attested KMS client.

Enclave memory is isolated from the parent host and is not exposed through normal host memory inspection or core dumps. The parent can run the enclave and forward traffic, but cannot dump the enclave process to recover plaintext keys.

KMS decrypts are different in this mode. The AttestedKmsClient attaches an NSM attestation document to each KMS decrypt request as RecipientInfo. That document contains a fresh RSA public key generated inside the enclave. KMS validates the enclave attestation and returns the plaintext in a CMS envelope encrypted to that RSA key. The envelope is unwrapped inside the enclave.

That means the parent can forward KMS traffic, but it should not receive the plaintext KMS share.

aTLS: proving which signer you reached

Nitro mode also requires tls.mode: atls. File-based TLS is rejected because mounting a certificate private key into the parent would weaken the enclave boundary.

With aTLS, the enclave generates an ephemeral TLS key, asks the Nitro Security Module for an attestation document bound to that key, and embeds the attestation document in the X.509 certificate. A client that verifies aTLS gets proof that:

  • the server is a genuine AWS Nitro Enclave,
  • the enclave measurements match the expected binary and environment,
  • and the TLS session terminates at that specific enclave rather than an interceptor.

The implementation uses a TOFU model for client verification: the first trusted connection records PCR measurements, and future connections reject a different measured enclave unless trust is intentionally re-established.

Nitro mode trust summary

You trust:

  • AWS Nitro attestation and the Nitro Security Module.
  • AWS KMS policy enforcement, including kms:RecipientAttestation conditions.
  • PCR pinning for the expected enclave image, signing certificate, and optional IAM role binding.
  • M-of-N KMS key holders if KMS shares are split across accounts or administrators.
  • The enclave binary and its reproducible build story.

You do not trust the parent host with plaintext key material. The parent can still deny service, reorder or drop traffic, observe timing and metadata, and forward encrypted traffic. It should not be able to read enclave memory, the reconstructed master key, decrypted validator keys, or KMS plaintext shares released to the enclave.

Compromise model: compromise the parent host → traffic forwarding and availability impact, but not direct plaintext key recovery. Persistent key recovery requires enough KMS shares and a valid enclave attestation accepted by the KMS policies.

Sealed at boot, unsealed by quorum

Both standard and Nitro modes boot in a sealed state when the DynamoDB key source is configured. The master key does not exist in memory at startup, validator keys cannot be decrypted, and every signing request is rejected. The signer leaves the sealed state in one of two ways:

  • KMS auto-unseal: at boot, the signer decrypts each Shamir share via KMS (in Nitro mode, via attested KMS), reconstructs the master key in memory, and finalizes to Unsealed. No operator interaction. This is the deployment shape when the trust story is “KMS + IAM” — and, in Nitro mode, ”+ enclave attestation.”
  • Operator quorum: M-of-N registered operators each submit an unseal share, encrypted under their own credential. Each operator can register multiple credentials — passphrases and YubiKey HMAC-SHA1 are both supported. The master key is reconstructed only after the M-th share is accepted.

The master key only exists in memory while the signer is Unsealed (or briefly AwaitingRotation during share rotation). Restarting the process puts it back into Sealed and forces the unseal flow again. This is structurally similar to Dirk’s “must cooperate to sign” property, but applied at the unseal boundary rather than per-signature — and it does not require the participating operators to be independent organizations for the per-restart gating to hold.

Key protection in both modes

When the DynamoDB key source is used, the key-storage model is:

  1. Validator BLS keys are encrypted with AES-256-GCM and stored in DynamoDB.
  2. The encryption master key is split via Shamir secret sharing into N shares.
  3. Each share is encrypted by a different AWS KMS key, potentially in different AWS accounts.
  4. M-of-N shares reconstruct the master key in memory.
  5. The reconstructed master key exists only at runtime after the chamber is unsealed.

In standard mode, KMS decrypt is a normal AWS SDK decrypt call. In Nitro mode, KMS decrypt is attested and returns ciphertext-for-recipient to the enclave.

The “potentially in different AWS accounts” in step 3 is doing real work. The M-of-N threshold only distributes organizational trust if the KMS shares are actually split across separate AWS accounts and administrators. If every wrapping KMS key lives under one IAM principal in one account, the threshold collapses to “compromise one set of AWS credentials” — the same single-operator problem Dirk faces, in a different form. What Containment Chamber retains over single-operator Dirk in that degenerate case is hardware-backed KMS HSM custody of the shares and an IAM audit trail of every decrypt — not the threshold itself.

The Comparison

Neutral comparison diagram showing Web3Signer, Dirk multi-operator, Dirk single-operator, Containment Chamber standard, and Containment Chamber Nitro Enclave trust boundaries
Web3SignerDirk (multi-op)Dirk (single-op)CC standardCC Nitro Enclave
Runtime trust boundaryHost + networkT independent operatorsOne operating teamHost processNitro Enclave + attested KMS
Boot-state gatingNonePer-signature threshold (DKG)Per-signature threshold (single org)Sealed at boot; KMS or M-of-N operator quorumSealed at boot; attested KMS or M-of-N operator quorum
AuthenticationNetwork/TLS client auth onlymTLS certsmTLS certsBearer tokens (HMAC-stored) + per-key ACL + CIDR bindingBearer tokens (HMAC-stored) + per-key ACL + CIDR binding + aTLS
Key protection at restKeystore files (+passwords on disk)DKG shares on each instanceAll shares on same infraAES-256-GCM + KMS ShamirAES-256-GCM + attested KMS Shamir
Key protection in memoryPlaintext in process memoryShares in process memoryShares in process memoryPlaintext in host process memory while unsealedPlaintext in isolated enclave memory
Parent/host compromiseTotal runtime compromiseDepends on operator independenceTotal share accessRuntime key exposure possible while unsealedParent cannot directly read enclave memory
Hardware root of trustNoneNoneNoneAWS KMS HSMs for sharesNitro Enclave + AWS KMS attestation
Slashing protectionPostgreSQL-backedThreshold-gated Dirk stateThreshold-gated Dirk state under one operatorPostgreSQL / DynamoDBPostgreSQL / DynamoDB via vsock egress
Persistent key recovery modelHost/storage accessT orgs compromisedOne team owns all sharesKMS threshold / state compromiseKMS threshold + valid enclave attestation
Operational complexityLowHigh (needs multiple orgs)MediumMediumHigh
Web3Signer compatible(is Web3Signer)No (gRPC, needs Vouch)No (gRPC, needs Vouch)Yes (drop-in)Yes (drop-in, via parent ingress/vsock)

The Bottom Line

The question isn’t “which signer has the most features” — it’s “which boundary has to fail before keys are exposed?”

  • Web3Signer assumes your network, TLS perimeter, and host are secure. If the host is compromised, runtime key material and persistent imports are in scope.
  • Dirk is strongest when the threshold participants are operated by independent parties. If one team controls every participant, threshold signing still provides signing discipline and availability, but it no longer distributes trust across organizations.
  • Containment Chamber standard mode improves the Web3Signer-compatible model with application auth, scoped keys, runtime-only imports, and encrypted persistent storage, but it still trusts the host at runtime.
  • Containment Chamber Nitro mode moves the runtime key boundary into an attested enclave. The parent host can forward bytes and break availability, but it should not see decrypted validator keys or KMS plaintext shares.

No system is perfect. But when you’re choosing where to place your trust, the real distinction is not “centralized versus distributed.” It is which boundary has to fail before keys are lost: the network perimeter, an operator set, a conventional host, or an attested hardware-backed enclave.


Containment Chamber is open source. The code and docs are available at github.com/unforeseen-consequences/containment-chamber.