Skip to content

fix(exec): Windows child can spawn a grandchild before Job Object assignment #9

Description

@CMGS

Surfaced in the 2026-07-16 whole-repo audit. Windows-only; not verifiable on the macOS dev host, so filed rather than fixed blind.

Problem

agent/exec.go calls cmd.Start() then procCtl.AfterStart(cmd)AssignProcessToJobObject (agent/sysproc_windows.go). exec.Cmd.Start() creates the child running immediately — no CREATE_SUSPENDED — so between Start() returning and the Job Object assignment completing, the child can spawn a grandchild that never becomes a job member. That grandchild then survives JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE when the session ends via windowsProcessController.close().

This is the Windows analogue of the guarantee Linux gets from Setpgid + process-group kill (covered by TestServerExecBackgroundChildDoesNotPinSession), which has no Windows equivalent test.

Fix direction

Create the process with CREATE_SUSPENDED via a raw windows.CreateProcess (os/exec doesn't expose the primary thread handle needed to resume), assign to the Job Object, then ResumeThread. Alternatively, document the narrow race as accepted.

Acceptance

  • A Windows exec whose child immediately spawns a grandchild: ending the session kills both (Job Object membership established at creation, pre-resume).
  • A Windows-target test mirroring TestServerExecBackgroundChildDoesNotPinSession.
  • Verified on a Windows runner, not a mac-only green.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions