Sealed values authenticate their context, not who sealed them#4106
Ployz Cloud's security bar says a compromised Cloud can't take data off a Server. Sealed values today authenticate where a value goes, but not who wrote it, so that promise doesn't hold for sealed values.
What's possible.
- Anyone with the Cluster public key, Cloud included, can seal a value.
core/crates/ployz-core/src/sealed.rsbinds the Organization, Environment, scope and variable name, but carries no signature from whoever sealed it. - Machines open values in HPKE base mode (
core/crates/ployzd/src/sealing_key.rs), without checking a sender. - A deploy approval binds the exact ciphertext, but it shows only the sealed name.
- So before approval, Cloud can swap in its own sealed
DATABASE_URL, for example one pointing at a database it controls. The approval looks the same, and the app then writes customer data to Cloud's database.
Decision for 0.4. The operator accepted this as a residual. It is documented in the 0.4 docs and plan, and this issue tracks the fix.
Proposed fix. Use an authenticated sealed envelope, signed when the value is written: a Device signature from the CLI, or a passkey from the dashboard. The signature covers the recipient Cluster, the context, the variable name and the ciphertext. Machines verify it against trusted Devices before opening the value. Values that already exist get re-sealed once after the upgrade. Signing an envelope Cloud delivers at deploy time would not close the hole.
Related.
- The F3b slice: the CLI seals to a Cluster key the Device pinned itself.
- The accepted residual that a secret typed into the dashboard trusts the dashboard.