How the Trust Boundary Works for Repo Config Commands in no-mistakes

The no-mistakes daemon prevents remote code execution by exclusively loading executable commands from the repository's default branch while ignoring command overrides from any pushed branch unless explicitly authorized.

The kunchenguid/no-mistakes project implements a cryptographic trust boundary around the .no-mistakes.yaml configuration file to eliminate remote code execution (RCE) vulnerabilities. When contributors open pull requests, the daemon cannot trust the configuration present on their branch because malicious actors could inject harmful shell commands. Instead, the system reads sensitive execution parameters exclusively from the repository's default branch, creating a security boundary that forces all command execution to be explicitly approved by maintainers.

Fetching the Trusted Default Branch

The trust boundary begins by establishing an immutable reference to the default branch's configuration. Before processing any run, the daemon fetches the default branch into a temporary worktree and resolves the exact commit SHA.

In internal/daemon/manager.go, the startRun function orchestrates this fetch:

trustedSHA := ""
if repo.DefaultBranch != "" {
    if err := git.FetchRemoteBranch(ctx, wtDir, "origin", repo.DefaultBranch); err != nil {
        slog.Warn("failed to fetch default branch …")
    } else if sha, err := git.ResolveRef(ctx, wtDir,
        "refs/remotes/origin/"+repo.DefaultBranch); err != nil {
        slog.Warn("failed to resolve fetched default‑branch ref …")
    } else {
        trustedSHA = sha
    }
}

This resolves a concrete trustedSHA that represents the repository's canonical state. If the fetch fails or the reference cannot be resolved, the pipeline proceeds with an empty trustedSHA, triggering the fail-closed behavior.

Loading the Immutable Configuration

With the trusted SHA identified, the daemon loads the configuration using loadTrustedRepoConfig, which reads .no-mistakes.yaml from that specific commit using git.ShowFile.

Located in internal/daemon/manager.go, this function returns nil if the file is missing, the SHA is invalid, or any error occurs:

trustedRepoCfg := loadTrustedRepoConfig(ctx, wtDir, trustedSHA, run.ID)

When trustedRepoCfg is nil, the system cannot verify which commands are safe to run. This immediately triggers the security default where executable fields are forced to empty values.

Merging Configurations with EffectiveRepoConfig

The core enforcement logic resides in EffectiveRepoConfig within internal/config/config.go. This function implements the trust boundary by selectively overriding dangerous fields while preserving safe configuration options from the pushed branch.

func EffectiveRepoConfig(pushed, trusted *RepoConfig, allowRepoCommands bool) *RepoConfig {
    if pushed == nil {
        pushed = &RepoConfig{}
    }
    effective := *pushed

    if allowRepoCommands {
        return &effective
    }

    if trusted != nil {
        effective.Commands = trusted.Commands
        effective.Agent    = trusted.Agent
    } else {
        effective.Commands = Commands{}
        effective.Agent    = ""
    }
    return &effective
}

Key security behaviors:

  • Default denial: Unless allowRepoCommands is true, the daemon replaces Commands and Agent with values from the trusted configuration.
  • Opt-in requirement: The allow_repo_commands flag must be set in the trusted default branch configuration. A contributor cannot enable this from their PR branch because the flag is read only from trustedRepoCfg.
  • Safe settings preserved: Non-executing fields like ignore patterns, auto-fix settings, and test configurations remain sourced from the pushed branch.

Fail-Closed Design

The architecture implements a fail-closed security model. If loadTrustedRepoConfig returns nil due to network failures, missing files, or resolution errors, EffectiveRepoConfig forces Commands and Agent to empty values.

This ensures that a malicious actor cannot exploit a temporary fetch failure to execute commands from their branch. The pipeline continues with built-in defaults or empty values, preventing execution entirely rather than falling back to untrusted input.

Security Verification

The implementation includes comprehensive test coverage validating the trust boundary. The internal/config/config_repo_trust_test.go file contains unit tests verifying that EffectiveRepoConfig correctly isolates executable fields, while internal/e2e/repo_config_security_test.go provides end-to-end validation.

A representative security test confirms that malicious commands on PR branches are ignored:

func TestRepoConfigSecurity(t *testing.T) {
    // Setup: default branch has no lint command, PR branch adds `lint: "rm -rf /"`
    runID := triggerRunWithPush(t, repo, "feature/bad")
    got := db.GetRun(t, runID)
    if got.Commands.Lint != "" {
        t.Fatalf("SECURITY REGRESSION: pushed‑branch lint command executed")
    }
}

This test verifies that even when a contributor injects lint: "rm -rf /" into their branch, the daemon executes with an empty Commands.Lint value.

Summary

  • Trust boundary: The daemon reads executable commands (Commands.*, Agent) exclusively from the default branch's .no-mistakes.yaml, never from pushed branches.
  • Fail-closed: If the trusted configuration cannot be fetched or parsed, the system defaults to empty commands, preventing execution.
  • Opt-in flag: The allow_repo_commands setting must be enabled in the trusted configuration; contributors cannot activate it via PR.
  • Safe separation: Non-executing configuration (ignore patterns, intent) loads from the pushed branch, maintaining flexibility without security risk.
  • Implementation: loadTrustedRepoConfig in internal/daemon/manager.go and EffectiveRepoConfig in internal/config/config.go enforce this boundary.

Frequently Asked Questions

Can a malicious PR execute arbitrary commands by modifying .no-mistakes.yaml?

No. The daemon ignores the .no-mistakes.yaml file present on the pushed branch when determining which commands to execute. It fetches the default branch separately and reads the configuration from that specific commit SHA. Even if an attacker modifies commands.lint to rm -rf /, the system uses the trusted default branch's values or empty defaults instead.

What happens if the default branch fetch fails during a run?

The system implements a fail-closed design. If git.FetchRemoteBranch or git.ResolveRef fails in internal/daemon/manager.go, the trustedSHA remains empty, causing loadTrustedRepoConfig to return nil. Consequently, EffectiveRepoConfig forces Commands and Agent to empty values, preventing any shell command execution rather than falling back to potentially malicious configuration.

How does allow_repo_commands work securely?

The allow_repo_commands flag enables contributors to define custom commands in their PRs, but only when explicitly authorized by maintainers. The daemon checks this flag exclusively from the trusted configuration loaded from the default branch. Since contributors cannot modify the default branch without merge privileges, they cannot enable this flag themselves. When allow_repo_commands is false (the default), executable fields are always replaced with the trusted copy's values.

Why are some settings read from the pushed branch while commands are not?

Settings like ignore patterns, auto-fix preferences, and test configurations affect behavior but cannot cause remote code execution. These non-executing fields are read from the pushed branch to allow contributors flexibility in configuring linting scope and automation. Only fields capable of executing shell commands (Commands struct) or launching external agents (Agent string) are restricted to the trusted default branch configuration.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →