Files
vercel__workflow/.changeset/encp-workflow-body-writable.md
Nathan Rajlich b8bcded9d9 fix(core): seal forwarded writes for workflow-body writables (#3155)
`getWritable()` resolves to two different functions. In a step it publishes the
run's X25519 public key on the handle; in a workflow body it returns only a
name, because the workflow VM holds no key material by design.

Forwarding a workflow-body handle to another run therefore produced a
descriptor with no public key, and the receiving run fell to tier 2/3 of
`getForwardedWritableEncryptionKey`: fetch the owner's symmetric key over the
`run-key` API. That is the round trip sealing exists to remove, and it also
hands the writer material that could decrypt — the tiers 2/3 comment calls that
an honor-system restriction, where sealing makes it cryptographic.

Nothing warned; the data was correct, just slower and over-privileged. The only
visible difference was an `encr` rather than `encp` prefix in storage.

Publish the key when a step revives such a handle. That is the first point
where the owning run's key is in scope, and it cannot be deferred to
serialization: `start()` dehydrates its arguments with the CHILD's runId and
key, so by then the owner's key is gone. Guarded on the stream belonging to the
current run — stamping our key onto another run's stream would make the
receiver seal to the wrong recipient and lock the real owner out.

This is the shape eve uses: a driver workflow takes a writable in its workflow
body and forwards it into per-turn child runs started with
`deploymentId: 'latest'`, so the sealed path was not engaging for the workload
that motivated it.
2026-07-28 07:50:42 -07:00

248 B

@workflow/core
@workflow/core
patch

Seal forwarded writes to streams taken with getWritable() in a workflow body, which previously fell back to fetching the owner's symmetric key because the workflow VM has no key material to publish on the handle.