# Understanding the Worktrunk Hook Security Model: Gate-by-Approval Protection

> Discover the Worktrunk hook security model. Learn how Gate-by-Approval protects against untrusted code execution from cloned repositories, ensuring robust project safety.

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

---

**Worktrunk treats every project-defined hook as potentially untrusted code, requiring explicit user approval through an immutable `HookPlan` before execution to prevent arbitrary code execution from cloned repositories.**

The max-sixty/worktrunk repository implements a rigorous security framework that addresses a critical vulnerability in developer workflows: the automatic execution of arbitrary code hidden in project hooks. Understanding the Worktrunk hook security model is essential for teams working with automated repository workflows, as it prevents malicious scripts from running silently when cloning, merging, or switching between codebases.

## The Five Pillars of the Worktrunk Hook Security Model

### 1. Approval Gate Mechanism

When Worktrunk discovers a hook, it immediately constructs an immutable `HookPlan` containing the exact set of commands to run. Before this plan is frozen, the user is prompted to **approve** each command through an interactive interface. This logic resides in [`src/commands/command_approval.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/command_approval.rs), where the `approve_or_skip` function handles the UI flow and ensures users see the literal command string before execution begins.

Users can bypass the interactive prompt only through explicit flags: `--yes` to auto-approve or `--no-hooks` to skip hook execution entirely.

### 2. Frozen Execution Plans

After approval, the plan is stored in a `HookPlan` object defined in [`src/commands/hook_plan.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hook_plan.rs) and **never re-read** from the project's configuration files. This immutability guarantee ensures that even if the repository's configuration changes after approval, Worktrunk executes only the previously approved commands. The frozen plan pattern eliminates the risk of configuration drift between approval time and execution time.

### 3. User-Controlled Whitelisting

Users can whitelist safe commands in their personal [`approvals.toml`](https://github.com/max-sixty/worktrunk/blob/main/approvals.toml) file or via the `approved-commands` section in [`config.toml`](https://github.com/max-sixty/worktrunk/blob/main/config.toml). The parser for this list is implemented in [`src/config/user/sections.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/config/user/sections.rs), while [`src/config/deprecation.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/config/deprecation.rs) handles migration of legacy `approved-commands` entries to the new file format. This allows automation of trusted commands—such as `cargo test` or `npm install`—without requiring interactive approval on every run.

### 4. Explicit CI/CD Consent

In CI/CD pipelines, the Worktrunk hook security model can be bypassed only through explicit configuration. The system requires either the `--yes` flag (for auto-approval in trusted environments) or pre-populated [`approvals.toml`](https://github.com/max-sixty/worktrunk/blob/main/approvals.toml) files. Attempting to run a hook without approval generates an error defined in [`src/git/error.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/git/error.rs) (line 1415), which explicitly suggests using `--yes` or configuring the approval UI. This prevents supply-chain attacks where CI jobs automatically clone and execute code from untrusted repositories.

### 5. Pre-Execution Safety Guarantees

Because the approval gate runs **before** any state-mutating operation—such as `wt merge`, `wt remove`, or `wt switch`—no hook can execute silently during repository transitions. The architectural enforcement occurs in [`src/output/handlers.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/output/handlers.rs), where the `execute_planned_hook` function (line 1167) consumes the frozen `HookPlan` only after the primary operation completes. This structural separation ensures hooks run after, not during, critical state changes, eliminating race conditions.

## Why the Worktrunk Hook Security Model Matters

**Arbitrary Code Execution Prevention**

Without this model, a malicious repository could embed a `pre-switch` hook containing commands like `curl ... | sh`. The Worktrunk hook security model forces users to inspect and approve each command before execution, rendering hidden payloads visible and preventable.

**Supply-Chain Attack Defense**

CI/CD pipelines that automatically clone and run Worktrunk on untrusted forks are protected by the requirement for explicit `--yes` flags or `--no-hooks` defaults. This prevents attackers from compromising build systems through malicious pull requests that contain harmful hooks.

**Configuration Tampering Protection**

The frozen `HookPlan` mechanism ensures that newly added hooks in updated repository configurations are ignored until the user explicitly re-approves them. Users cannot be surprised by new commands added after their initial approval.

**Operational Integrity**

Hooks execute only after the primary Git operation completes, preventing scenarios where a hook might modify repository state during a merge or switch operation. The immutable plan storage guarantees that the approved command sequence remains unchanged between validation and execution.

**Automation Without Compromise**

The approved-commands whitelist balances security with convenience, allowing teams to automate safe, repetitive commands while maintaining strict boundaries around unrecognized or potentially dangerous scripts.

## Configuring Hook Approvals in Practice

Run commands interactively to review hooks before execution:

```bash

# Default behavior: prompts for approval of each pre- and post-hook

wt merge

```

Enable automated execution in trusted CI environments:

```bash

# Auto-approve all hooks (use only in trusted pipelines)

wt merge --yes

```

Disable hooks for one-off operations:

```bash

# Run the command without executing any associated hooks

wt switch feature-branch --no-hooks

```

Configure persistent approvals in `~/.config/worktrunk/approvals.toml`:

```toml
approved_commands = [
    "cargo test",
    "npm install",
    "make lint",
]

```

## Summary

- **Immutable `HookPlan` objects** in [`src/commands/hook_plan.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hook_plan.rs) ensure approved commands cannot be altered between validation and execution.
- **Explicit user approval** via [`src/commands/command_approval.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/command_approval.rs) prevents automatic execution of untrusted code from cloned repositories.
- **Personal whitelisting** through [`src/config/user/sections.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/config/user/sections.rs) enables automation of safe commands without compromising security boundaries.
- **CI/CD protection** enforced through [`src/git/error.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/git/error.rs) requires explicit `--yes` flags, preventing supply-chain attacks in automated pipelines.
- **Post-operation execution** in [`src/output/handlers.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/output/handlers.rs) ensures hooks cannot interfere with state-mutating Git operations.

## Frequently Asked Questions

### How does Worktrunk prevent malicious hooks from executing when I clone a new repository?

Worktrunk treats every project-defined hook as untrusted by default. When you run commands like `wt merge` or `wt switch`, the system builds an immutable `HookPlan` in [`src/commands/hook_plan.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/hook_plan.rs) and presents each command for approval via the logic in [`src/commands/command_approval.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/commands/command_approval.rs) before execution. This gate-by-approval model ensures you inspect every command string before it runs, preventing hidden malicious scripts (such as `curl | sh` pipes) from executing automatically.

### What happens if a repository maintainer adds new hooks after I've approved the existing ones?

The frozen `HookPlan` mechanism ensures that newly added hooks are ignored until you explicitly re-approve them. Once you approve a set of hooks, Worktrunk stores the exact command list in an immutable structure and never re-reads the configuration file for that operation. Any hooks added to the repository after your approval require a new approval cycle, protecting you from silent policy changes.

### Can I use Worktrunk in CI/CD pipelines without interactive approval prompts?

Yes, but only through explicit configuration. You must either pass the `--yes` flag to auto-approve all hooks (suitable only for trusted, private repositories) or pre-populate the [`approvals.toml`](https://github.com/max-sixty/worktrunk/blob/main/approvals.toml) file with the specific commands your pipeline requires. The error handling in [`src/git/error.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/git/error.rs) enforces this by refusing to execute hooks without approval and suggesting these explicit override flags, ensuring CI environments do not accidentally execute untrusted code from public forks.

### Where does Worktrunk store my approved commands list?

Worktrunk stores approved commands in `~/.config/worktrunk/approvals.toml` (or the platform-appropriate configuration directory). The parser for this file is located in [`src/config/user/sections.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/config/user/sections.rs). If you previously used the legacy `approved-commands` section in [`config.toml`](https://github.com/max-sixty/worktrunk/blob/main/config.toml), Worktrunk migrates these entries automatically via [`src/config/deprecation.rs`](https://github.com/max-sixty/worktrunk/blob/main/src/config/deprecation.rs) to maintain consistency without losing your existing approvals.