# How Destructive Command Guard Prevents Malicious Repository Configs from Weakening Protection

> Discover how Destructive Command Guard's layered trust model prevents malicious repository configs from weakening protection with strict size limits, symlink validation, and policy restrictions.

- Repository: [Jeff Emanuel/destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard)
- Tags: how-to-guide
- Published: 2026-07-22

---

**Destructive Command Guard (dcg) employs a layered trust model that treats repository-owned [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) files as untrusted, enforcing strict size limits, symlink validation, and policy restrictions to prevent malicious configurations from disabling security controls.**

Destructive Command Guard (dcg) is a safety tool that intercepts potentially destructive shell commands before they execute. Because attackers could attempt to ship malicious [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) files in cloned repositories to disable protective packs or whitelist dangerous commands, the tool implements a hardened configuration loader in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs) that strictly separates user-controlled settings from repository-owned configurations. This architecture ensures that **malicious repository configs** cannot weaken protection without explicit user opt-in.

## Layered Trust Model and ConfigSource Hierarchy

The foundation of dcg's defense is a hierarchical trust model defined by the `ConfigSource` enum in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs) (lines 35‑48). Only configuration sources outside the repository—such as environment variables, explicit `DCG_CONFIG` paths, user-level `~/.config/dcg/config.toml`, or system-level [`/etc/dcg/config.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main//etc/dcg/config.toml)—are granted **full authority**. In contrast, automatically discovered [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) files inside a project directory are loaded with restricted privileges.

The enum prioritizes sources as follows:

1. **Environment variables** – Highest trust, can override any setting.
2. **Explicit `DCG_CONFIG`** – User-provided path, validated before full authority is granted.
3. **User-level and system-level files** – Standard locations with full policy control.
4. **Automatic project config** – Limited to enforcement-only settings; cannot disable protections.

This hierarchy ensures that a repository cannot override global security policies even if it contains a [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) file.

## Size Caps and Resource Limits

To prevent denial-of-service attacks via maliciously large configuration files, dcg enforces a hard **1 MiB size limit** on all config files. The function `read_config_file_bounded` in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs) (lines 27‑33) reads the file into a bounded buffer, rejecting any input that exceeds this limit before parsing begins.

```rust
// Pseudocode representation of the bounded read
fn read_config_file_bounded(path: &Path) -> Result<String, Error> {
    const MAX_SIZE: usize = 1024 * 1024; // 1 MiB
    // Implementation reads up to MAX_SIZE and rejects overflow
}

```

This prevents attackers from exhausting memory or triggering parser vulnerabilities with arbitrarily large [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) files.

## Symlink and File-Type Validation

On Unix systems, dcg prevents time-of-check to time-of-use (TOCTOU) attacks by using the `O_NOFOLLOW` flag when opening configuration files. The `open_config_file_for_source` function (lines 56‑63) opens files without following symlinks, and `validate_opened_unix_config_file` (lines 124‑132) verifies that the file descriptor matches the expected inode and device after opening.

This two-step validation ensures that an attacker cannot swap a legitimate config file for a malicious one via a symlink race condition after the initial path check but before the read operation.

## Ownership and Permission Enforcement

System-level configurations must meet strict ownership requirements. The helper `unix_owner_or_mode_is_user_writable` (lines 98‑104) checks that system-wide configs are owned by root and are not group- or world-writable. If a system config fails these permission checks, it is rejected entirely, preventing privilege escalation through writable configuration injections.

## Enforcement-Only Policy for Repository Configs

The most critical safeguard is the **`into_restricted_project_policy`** method (lines 661‑671). When dcg automatically discovers a [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) file in a repository, it converts the `ConfigLayer` into a restricted version that strips any fields capable of lowering protection:

- **Disabled packs** – Any `disabled` list entries are discarded, preventing repos from turning off core protections like the `core.git` pack.
- **Allow-list rules** – Policy layers that whitelist dangerous commands are removed.
- **Fail-closed overrides** – Only safe subset settings such as `fail_closed`, known pack IDs, and deny-by-default policies are retained.

```toml

# Example: This malicious .dcg.toml cannot disable protections

[packs]
disabled = ["core.git"]  # <-- Ignored when loaded automatically

[allowlist]
commands = ["rm -rf /"]  # <-- Stripped by into_restricted_project_policy

```

## Explicit Opt-In via DCG_CONFIG

Repository configs gain **full authority** only when the user explicitly sets the `DCG_CONFIG` environment variable to point to the file. The `explicitly_trusts_project_policy` function (lines 51‑59) validates this opt-in by:

1. Canonicalizing both the specified path and the expected repository root.
2. Verifying the file is a regular file (not a symlink).
3. Ensuring the path matches the repository root (lines 71‑79), preventing traversal attacks.

```bash

# Opt-in example: Granting full authority to a repository config

$ export DCG_CONFIG=./.dcg.toml
$ dcg explain "git reset --hard HEAD"

```

Without this explicit environment variable, the repository config remains restricted regardless of its contents.

## Programmatic Configuration Loading

When integrating dcg into Rust applications, the config loader exposes the trust decisions through the `load_config` function:

```rust
use dcg::config::{load_config, ConfigSource};

fn main() {
    // Load configuration hierarchy for current directory
    let report = load_config(std::env::current_dir().unwrap()).unwrap();
    
    // Inspect which sources were loaded vs rejected
    for src in report.sources {
        println!("{}: {}", src.layer.label(), src.status.label());
    }
}

```

This allows programmatic verification that repository configs are being treated with the appropriate restriction level.

## Summary

- **Layered trust** ensures only user-controlled sources (environment variables, explicit paths, system/user configs) have full authority over security policy.
- **Size limits** (1 MiB) prevent memory exhaustion attacks via oversized config files.
- **Symlink protection** using `O_NOFOLLOW` and inode validation blocks TOCTOU attacks on Unix systems.
- **Permission checks** enforce that system configs are root-owned and non-writable by non-privileged users.
- **Enforcement-only mode** automatically strips dangerous directives (disabled packs, allow-lists) from discovered repository configs via `into_restricted_project_policy`.
- **Explicit opt-in** via `DCG_CONFIG` is required for repositories to gain full policy control, with path canonicalization preventing symlink attacks.

## Frequently Asked Questions

### Can a malicious repository disable protective packs by shipping a [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) file?

No. When dcg automatically discovers a [`.dcg.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg.toml) file in a repository, it applies `into_restricted_project_policy` (lines 661‑671) which strips any `disabled` entries from the packs section. The repository config operates in enforcement-only mode unless the user explicitly sets `DCG_CONFIG` to trust it.

### How does dcg prevent a repository config from being swapped for a malicious version after detection?

The loader uses `O_NOFOLLOW` when opening files and validates the opened file descriptor via `validate_opened_unix_config_file` (lines 124‑132). This compares the inode and device of the opened file against the original path, ensuring the file has not been replaced via a symlink race condition between check and use.

### What happens if a repository tries to include an oversized configuration file?

The `read_config_file_bounded` function (lines 27‑33) enforces a hard 1 MiB limit. Any config file exceeding this size is rejected immediately, preventing memory exhaustion attacks before the TOML parser processes the content.

### How can I grant full authority to a repository's configuration?

Set the `DCG_CONFIG` environment variable to the path of the repository config file: `export DCG_CONFIG=./.dcg.toml`. The `explicitly_trusts_project_policy` function validates that the path is canonical, matches the repository root, and is a regular file before granting full policy control.