# How Worktrunk Prevents TOCTOU Vulnerabilities in Hook Execution

> Learn how Worktrunk prevents TOCTOU vulnerabilities by freezing approved hooks at the approval boundary, ensuring security during operation.

- Repository: [Maximilian Roos/worktrunk](https://github.com/max-sixty/worktrunk)
- Tags: security
- Published: 2026-09-14

---

**Worktrunk eliminates Time-of-Check-to-Time-of-Use (TOCTOU) race conditions by freezing the exact set of hooks permitted to execute at the moment the user crosses the approval boundary, then using that immutable snapshot for the entire operation.**

Worktrunk, a Rust-based git workflow automation tool in the max-sixty/worktrunk repository, implements a **frozen hook plan** architecture to secure command execution against TOCTOU vulnerabilities. When users run commands like `wt merge` or `wt step`, the tool must ensure that the hooks approved for execution cannot be modified between the approval check and the actual execution. By capturing an immutable `HookPlan` at the consent boundary, Worktrunk guarantees that what the user approves is exactly what runs, regardless of subsequent repository changes or file system races.

## Understanding the TOCTOU Risk in Hook-Based Workflows

Time-of-Check-to-Time-of-Use vulnerabilities occur when a program checks a condition, then acts on it after a delay during which the condition could change. In hook execution, this represents the window between discovering which hooks exist and actually spawning the subprocess. A malicious actor or race condition could modify hook scripts after the user approves the operation but before execution begins, leading to arbitrary code execution with the user's privileges. Worktrunk addresses this by removing the time window entirely through **plan-backed execution**.

## The Frozen Hook Plan Architecture

### Constructing the Immutable HookPlan

When a command that may invoke hooks reaches the approval prompt, Worktrunk builds a `HookPlan` containing the exact list of hook commands permitted for that operation. This plan is captured before any state-changing actions occur.

According to the source code in [`src/commands/hook_plan.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hook_plan.rs), this design explicitly "closes the approval-boundary TOCTOU" by creating an immutable structure that cannot be altered after user consent:

```rust
// At the approval boundary
let approved_plan = HookPlan::approve(&project_config, &command_args)?;

```

The top-level comments in lines 1-7 of [`src/commands/hook_plan.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hook_plan.rs) document this safety mechanism, ensuring that once the user sees the approval prompt, the set of hooks is frozen and cannot mutate even if the underlying configuration changes.

### The Approval Boundary Pattern

The approval UI is shown exactly once, and the snapshot of the hook plan is used for the entire operation. Because the plan cannot be mutated after the user's consent, any later changes to the repository—such as a newly added hook script or modified configuration—cannot affect the already-approved execution path.

As implemented in [`src/commands/hook_plan.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hook_plan.rs) (lines 440-447), this design ensures the approval prompt remains "byte-identical" and "TOCTOU-covered," guaranteeing that no hook can be inserted or altered after the user reviews the operation but before execution completes.

## Plan-Backed Hook Execution

The actual hook runner in [`src/commands/hooks.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hooks.rs) receives the pre-approved `HookPlan` and iterates over the cached list rather than re-reading the project configuration each time a hook launches. This eliminates the window between checking which hooks exist and actually launching them.

The module header in [`src/commands/hooks.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hooks.rs) (lines 18-22) explicitly notes this "Plan-backed (the TOCTOU-covered set)" approach:

```rust
// Later, after any mutating work has happened
for hook in approved_plan.iter() {
    // No re-reading of config; the list is immutable
    HookExecutor::run(hook)?;
}

```

By using the frozen plan rather than querying the filesystem or configuration for each hook execution, Worktrunk ensures that the exact commands approved by the user are the commands that execute, even if minutes pass between approval and completion.

## TOCTOU Protection for Reference Updates

Beyond hook execution, Worktrunk extends TOCTOU protection to git ref updates. For operations that modify refs—such as push, merge, or promote—the tool snapshots the target SHA **before** performing any mutating actions. This snapshot is then used for the ref update, guaranteeing that the ref being updated has not changed between the check and the write.

In [`src/commands/worktree/push.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/worktree/push.rs) (lines 104-110), the code shows this early snapshot pattern:

```rust
// Capture SHA before any race window
let target_sha = repo.resolve_ref("refs/heads/main")?;
let push = Push::new(&repo, target_sha);
// ... perform push safely
push.execute()?;

```

This same pattern appears in [`src/commands/merge.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/merge.rs), which utilizes the frozen hook plan for merge-related hooks while ensuring the merge target remains stable throughout the operation.

## Summary

- **Frozen Hook Plans**: Worktrunk constructs an immutable `HookPlan` at the approval boundary in [`src/commands/hook_plan.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hook_plan.rs), freezing the exact set of hooks before any state changes occur.
- **No Configuration Re-reading**: The hook executor in [`src/commands/hooks.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hooks.rs) uses the cached plan rather than querying the filesystem, eliminating the TOCTOU window between check and use.
- **Atomic Ref Snapshots**: Operations like pushes in [`src/commands/worktree/push.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/worktree/push.rs) capture target SHAs before mutating work, preventing race conditions in ref updates.
- **Single Approval Boundary**: By showing the approval prompt once and using a byte-identical plan for the entire operation, Worktrunk ensures that approved operations cannot be altered by subsequent filesystem changes.

## Frequently Asked Questions

### What is a TOCTOU vulnerability in the context of hook execution?

A TOCTOU (Time-of-Check-to-Time-of-Use) vulnerability in hook execution occurs when a program verifies which hooks are present and safe to run, but then executes them after a delay during which the hook scripts could be modified. This creates a window where malicious code could replace approved hooks, leading to privilege escalation or arbitrary code execution with the user's credentials.

### How does the HookPlan prevent race conditions?

The `HookPlan` prevents race conditions by capturing the exact list of permitted hooks and their configurations at the moment the user approves the operation. As implemented in [`src/commands/hook_plan.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hook_plan.rs), this plan is immutable and "closes the approval-boundary TOCTOU." Once frozen, the plan travels with the operation through completion, ensuring that even if the underlying repository configuration changes, the execution uses only the originally approved hooks.

### Does this protection apply to all Worktrunk commands?

The TOCTOU protection applies to all commands that invoke hooks, including `wt merge`, `wt remove`, and `wt step`, as well as reference-modifying operations like pushes. Any command that crosses the approval boundary receives a frozen plan or snapshot before performing mutating actions, ensuring consistent protection across the codebase.

### Where is the frozen plan created in the source code?

The frozen plan is created in [`src/commands/hook_plan.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hook_plan.rs), where the `HookPlan` struct is defined with comments explaining the TOCTOU-covered approval boundary. The execution logic that respects this frozen state resides in [`src/commands/hooks.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hooks.rs), which receives the pre-approved plan and runs hooks from the cached list without re-reading configuration files.