You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
archive_failover rows hold guest: false env in plaintext #423
With archive_failover, the row of an archived or replicated claim holds the claim's env in its claim column, and that includes guest: false values in plaintext. Those values are the tenants' own credentials: the egress proxy injects them so that guest code never sees them.
token_sha256: d3a6267f… the sandbox token: a hash only
claim: {"env":{"GH_TOKEN":{"value":"ghp_…","guest":false}}, …} the credential: as written
An adopter needs the value to go on injecting after node loss, which is why the row carries it. The cost is that the credential now sits wherever that database does: every node's DSN holder, its administrators, its backups and its snapshots.
Today
Plaintext is accepted for now. The docs state it and docs/security.md says to treat that database like backups (#420). A rotation now reaches the row (#422).
Options
Encrypt the values in the row with a key every node of the cell holds and the database does not.
It needs a place for the key (a node env var, as cluster_key and preview_secret are configured), and a rotation story: rows written under an old key must stay readable until they are rewritten.
It adds one AEAD operation per row write, and none on the claim path.
Keep the values out of the row. An adopter serves the claim with no credential until someone resends the env. The database then holds no secret, but a failover silently degrades egress for that claim until the write, so callers must handle it.
Stay as today, for deployments where the database is already trusted with the credentials.
To decide
Is there a deployment where the database's readers should not see tenant credentials? If not, option 3 stands and this closes.
For option 1: one cell-wide key, or derived per tenant?
Decision for now: option 3 stands and plaintext stays. This issue stays open for when a deployment needs otherwise.
State after #420 and #422: docs/security.md says to treat this database like backups. A rotation on an archived or hibernated replicated claim rewrites its row, a running replicated claim's row follows on the next round, and a renew rewrites the row too.
The one rotation gap left is in #433: a write in the milliseconds between an archive's row write and the claim taking its checkpoint id reaches the journal but not the row.
The rotation gap named in the last comment is closed. #437 rewrites the row when an env write lands while the archive intent is set (TestAnEnvWriteDuringTheArchiveReachesItsRow), and #433 records that. Plaintext stays as decided; this issue stays open for a deployment that needs otherwise.
host_env_memory_only (#499) implements option 2 as an opt-in, for a deployment whose database readers must not see tenant credentials. With it on, claims.json and the archive and replica rows store guest: false entries without their values, marked missing. The control plane sends them again with PATCH after a hibernate, a restart or an adoption (sandboxd/pool/failover.go; docs/deploy.md, host_env_memory_only; docs/security.md). The default stays option 3, as decided. A row written before the flag is turned on keeps its values until it is next written. Option 1, encrypting the values in the row, is not built. A deployment that needs credentials to survive failover with no plaintext in the database would reopen this. Closing.
Activity
CMGS commentedon Nov 3, 2026
Decision for now: option 3 stands and plaintext stays. This issue stays open for when a deployment needs otherwise.
State after #420 and #422:
docs/security.mdsays to treat this database like backups. A rotation on an archived or hibernated replicated claim rewrites its row, a running replicated claim's row follows on the next round, and a renew rewrites the row too.The one rotation gap left is in #433: a write in the milliseconds between an archive's row write and the claim taking its checkpoint id reaches the journal but not the row.
CMGS commentedon Nov 4, 2026
The rotation gap named in the last comment is closed. #437 rewrites the row when an env write lands while the archive intent is set (
TestAnEnvWriteDuringTheArchiveReachesItsRow), and #433 records that. Plaintext stays as decided; this issue stays open for a deployment that needs otherwise.CMGS commentedon Nov 8, 2026
host_env_memory_only(#499) implements option 2 as an opt-in, for a deployment whose database readers must not see tenant credentials. With it on,claims.jsonand the archive and replica rows storeguest: falseentries without their values, markedmissing. The control plane sends them again withPATCHafter a hibernate, a restart or an adoption (sandboxd/pool/failover.go;docs/deploy.md,host_env_memory_only;docs/security.md). The default stays option 3, as decided. A row written before the flag is turned on keeps its values until it is next written. Option 1, encrypting the values in the row, is not built. A deployment that needs credentials to survive failover with no plaintext in the database would reopen this. Closing.