From db21f658f0e6a72e693c2e1d47c7f72ce4b8dcb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Tue, 2 Jun 2026 15:26:27 +0200 Subject: [PATCH] agent: prevent use-after-free in synthesizeSave --- src/agent/Agent.zig | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/agent/Agent.zig b/src/agent/Agent.zig index d50529a1..bbdcc6b5 100644 --- a/src/agent/Agent.zig +++ b/src/agent/Agent.zig @@ -893,9 +893,13 @@ fn synthesizeSave(self: *Agent, arena: std.mem.Allocator, filename: ?[]const u8, return self.failSave("the model returned no script"); }; - // Dupe out of `result.arena` (freed below) and `message_arena` (rebuilt by - // rollback) into the command arena before either is reclaimed. - const script = browser_tools.reverseSubstituteEnvVars(arena, stripCodeFence(raw)) catch { + // `result.text` lives in `message_arena`, which the rollback below frees; + // copy into the command arena first (scrubbing may return its input as-is). + const owned = arena.dupe(u8, stripCodeFence(raw)) catch { + self.rollbackMessages(baseline); + return self.failSave("out of memory"); + }; + const script = browser_tools.reverseSubstituteEnvVars(arena, owned) catch { self.rollbackMessages(baseline); return self.failSave("out of memory"); };