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
Redis dials with no auth, no TLS and no keyspace scoping, and sessnap is plain JSON with no MAC.
It should land before any multi-tenant deployment, because it buys the same defence a signed chain
would buy against one specific adversary: someone holding a leaked store credential cannot forge
a MAC. It buys nothing against a compromised pod, and that qualifier is load-bearing.
mecatl, deployment work. Unblocked, independent of everything else in #377.
Hazards
Facts that were expensive to find and that nobody re-derives on the way to implementing. Each is verified against code.
The MAC key inherits Spike: can a model-spawned shell reach the key? #375. The MAC is applied where the snapshot bytes are produced and
consumed, which is the per-turn hot path inside the harness process, and that process is the parent
of the Bash tool (osfs.go:1167-1187 is a plain exec.CommandContext(ctx, r.shell, "-c", command),
same uid, no namespace, no path allowlist; the hardened runners differ only in cmd.Env and cmd.Dir). The key does not have to be read out of memory to be stolen: a flag lands in /proc/<pid>/cmdline, an env var is readable at the parent's /proc/<harness-pid>/environ because envscrub strips names from the child's environment only, and a mounted Secret file is a fixed
path that cat reaches under a read-only-by-verb classification with no path predicate, which an
isolated child auto-approves. Only /proc/pid/mem needs PTRACE_MODE_ATTACH, and no manifest here
sets ptrace_scope.
workspace is the field that escalates, not the owner label. The persisted string flows
verbatim into the workspace factory at run entry (service.go:2311) and becomes the osfs.NewWorkspace root for Read/Edit/Write/Grep/Glob, the Bash cmd.Dir, and the base the escape
classifier is constructed relative to (build.go:6784-6811). A stored "workspace":"/" is a
session rooted at the filesystem root with no escape left to detect. The same string pins the child
permission resolver (build.go:1757). profile is trusted the same way in rehydrateSession
(service.go:2403-2423), so flipping it off no-fs escalates a deliberately file-less session onto
the full FS tool set plus Bash.
The event log is a second authority path.approvalreplay.go:33-82 runs at every loadAndReopen: it reads the event log, filters EvApproval with AllowAlways, correlates each to
a ToolCall in the loaded conversation, and re-drives policy.Learn. Both inputs live in the same
open store. A writer forges a Bash call in the snapshot's messages plus a matching approval event,
and at the next resume the harness learns a durable permission allow the user never granted. The
replay code is fail-safe against every accident and defenceless against a writer.
A payload MAC does not survive the grpcdriver round trip. The driver server decodes and
re-encodes (sessnap.Unmarshal on Save at server.go:65, a fresh sessnap.Marshal on Load at server.go:93), and sessnap.Of() rebuilds from the live session, so a stored MAC has nowhere to
ride. Either the MAC is an envelope in the store adapter, in which case that backend has no MAC at
all, or the driver protocol carries it as an opaque field. One caller cannot reach another's work #368 already carries the adjacent
sentence about labels being dropped at the process boundary.
Auth, TLS and keyspace scoping stop the same adversary at the door and fix the confidentiality
half a MAC cannot touch. If this issue gets split, those go first.
The event log stays uncovered by decision, and one attack survives because of it. A per-record
MAC would have closed it, and the call is to ship the snapshot MAC first and close the event log
separately in Event-log integrity: a forged approval record still grants a durable permission #385. What remains open: an existing benign tool call in the conversation plus a forged EvApproval{AllowAlways} naming it is enough for approvalreplay to run policy.Learn, because
only the snapshot half is authenticated. Do not describe this issue as closing the approval-replay
path.
Acceptance criteria
Auth, TLS and keyspace scoping are supported and used by the shipped manifest.
A shared store with no auth produces a startup warning.
The MAC covers the whole snapshot, not a chosen subset of fields. Anything a resume trusts is
inside it, workspace, profile and mode included.
The MAC is an envelope in the store adapter, around the serialized snapshot. The remote driver
backend is therefore not covered, and that is a decided exclusion rather than an oversight: the
driver server decodes and re-encodes, so a payload MAC cannot survive it. The exclusion rests on One caller cannot reach another's work #368's deployment requirement that the driver endpoint is never tenant-reachable, which puts it out
of reach of the same adversary this MAC defends against.
A verification failure reads as an integrity error, distinguishable from a transient one.
The boundary is stated where an implementer reads it, in these words or equivalent: this MAC
detects tampering by an adversary who can write the store but cannot execute code in a mecatl pod.
It provides no integrity against a compromised pod or a prompt-injected model with Bash, because the
verifying key lives in the agent-loop process and is reachable from a child shell. It does not cover
the event log or the tool-call audit log. It is not confidentiality either; the snapshot stays
readable to anyone who can read the store.
Proof
The same properties, adversarially, with an actor and an ordering. A property-level criterion can go green while being false; these are what stop that.
Modify a stored row directly, then resume: refused. An unmodified snapshot still loads, so
"refuse everything" cannot pass.
Rewrite workspace to / in the store, then resume: refused, rather than a session whose file
tools are rooted at the filesystem root.
Flip profile off no-fs in the store, then resume: refused, rather than a file-less session
that comes back holding Bash.
Forge a tool call in the snapshot's messages, then resume: refused, so the snapshot half of the
approval-replay path is closed.
The same tampering is detected on both local backends. The remote driver backend is expected to
fail this and the test says so, rather than the gap being discovered later.
Slices
Decomposition is the implementer's job; these are the natural seams, not a mandate.
Auth, TLS and keyspace scoping, with the manifest that uses them.
The MAC envelope over the whole snapshot, and where its key comes from.
Redis dials with no auth, no TLS and no keyspace scoping, and
sessnapis plain JSON with no MAC.It should land before any multi-tenant deployment, because it buys the same defence a signed chain
would buy against one specific adversary: someone holding a leaked store credential cannot forge
a MAC. It buys nothing against a compromised pod, and that qualifier is load-bearing.
mecatl, deployment work. Unblocked, independent of everything else in #377.
Hazards
Facts that were expensive to find and that nobody re-derives on the way to implementing. Each is verified against code.
consumed, which is the per-turn hot path inside the harness process, and that process is the parent
of the Bash tool (
osfs.go:1167-1187is a plainexec.CommandContext(ctx, r.shell, "-c", command),same uid, no namespace, no path allowlist; the hardened runners differ only in
cmd.Envandcmd.Dir). The key does not have to be read out of memory to be stolen: a flag lands in/proc/<pid>/cmdline, an env var is readable at the parent's/proc/<harness-pid>/environbecauseenvscrubstrips names from the child's environment only, and a mounted Secret file is a fixedpath that
catreaches under a read-only-by-verb classification with no path predicate, which anisolated child auto-approves. Only
/proc/pid/memneedsPTRACE_MODE_ATTACH, and no manifest heresets
ptrace_scope.workspaceis the field that escalates, not the owner label. The persisted string flowsverbatim into the workspace factory at run entry (
service.go:2311) and becomes theosfs.NewWorkspaceroot for Read/Edit/Write/Grep/Glob, the Bashcmd.Dir, and the base the escapeclassifier is constructed relative to (
build.go:6784-6811). A stored"workspace":"/"is asession rooted at the filesystem root with no escape left to detect. The same string pins the child
permission resolver (
build.go:1757).profileis trusted the same way inrehydrateSession(
service.go:2403-2423), so flipping it offno-fsescalates a deliberately file-less session ontothe full FS tool set plus Bash.
approvalreplay.go:33-82runs at everyloadAndReopen: it reads the event log, filtersEvApprovalwithAllowAlways, correlates each toa
ToolCallin the loaded conversation, and re-drivespolicy.Learn. Both inputs live in the sameopen store. A writer forges a Bash call in the snapshot's messages plus a matching approval event,
and at the next resume the harness learns a durable permission allow the user never granted. The
replay code is fail-safe against every accident and defenceless against a writer.
re-encodes (
sessnap.Unmarshalon Save atserver.go:65, a freshsessnap.Marshalon Load atserver.go:93), andsessnap.Of()rebuilds from the live session, so a stored MAC has nowhere toride. Either the MAC is an envelope in the store adapter, in which case that backend has no MAC at
all, or the driver protocol carries it as an opaque field. One caller cannot reach another's work #368 already carries the adjacent
sentence about labels being dropped at the process boundary.
half a MAC cannot touch. If this issue gets split, those go first.
MAC would have closed it, and the call is to ship the snapshot MAC first and close the event log
separately in Event-log integrity: a forged approval record still grants a durable permission #385. What remains open: an existing benign tool call in the conversation plus a forged
EvApproval{AllowAlways}naming it is enough forapprovalreplayto runpolicy.Learn, becauseonly the snapshot half is authenticated. Do not describe this issue as closing the approval-replay
path.
Acceptance criteria
inside it,
workspace,profileandmodeincluded.backend is therefore not covered, and that is a decided exclusion rather than an oversight: the
driver server decodes and re-encodes, so a payload MAC cannot survive it. The exclusion rests on
One caller cannot reach another's work #368's deployment requirement that the driver endpoint is never tenant-reachable, which puts it out
of reach of the same adversary this MAC defends against.
detects tampering by an adversary who can write the store but cannot execute code in a mecatl pod.
It provides no integrity against a compromised pod or a prompt-injected model with Bash, because the
verifying key lives in the agent-loop process and is reachable from a child shell. It does not cover
the event log or the tool-call audit log. It is not confidentiality either; the snapshot stays
readable to anyone who can read the store.
Proof
The same properties, adversarially, with an actor and an ordering. A property-level criterion can go green while being false; these are what stop that.
"refuse everything" cannot pass.
workspaceto/in the store, then resume: refused, rather than a session whose filetools are rooted at the filesystem root.
profileoffno-fsin the store, then resume: refused, rather than a file-less sessionthat comes back holding Bash.
approval-replay path is closed.
fail this and the test says so, rather than the gap being discovered later.
Slices
Decomposition is the implementer's job; these are the natural seams, not a mandate.
Reasoning
The design this comes from, both on
main:Every hazard above is stated in full here rather than linked, so this issue stands on its own.