# How Command Normalization in dcg Removes Absolute Paths from git and rm Binaries

> Discover how command normalization in dcg removes absolute paths from git and rm binaries. Learn its technique for secure command execution and parsing in Rust.

- Repository: [Jeff Emanuel/destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard)
- Tags: internals
- Published: 2026-07-21

---

**Command normalization in dcg strips absolute paths from git and rm binaries by parsing the shell command into tokens, detecting path separators in the executable, and extracting only the file name using Rust's `Path::file_name` before pattern matching occurs.**

The Destructive Command Guard (dcg) from `Dicklesworthstone/destructive_command_guard` processes every incoming shell command through a strict normalization pipeline designed to prevent evasion attacks. This stage removes unnecessary path information that could otherwise bypass the guard's safety checks, ensuring that commands like `/usr/bin/git reset --hard` are evaluated identically to `git reset --hard`.

## How Command Normalization Works in dcg

The normalization engine resides in [[`src/normalize.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/normalize.rs)](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/normalize.rs) and operates through a four-stage pipeline that canonicalizes command strings before they reach the pattern matcher.

### Parsing and Tokenization

When dcg receives a raw command string, it splits the input into the executable token and its arguments using **whitespace-aware tokenization**. This parser respects quoted strings and escaped spaces, ensuring that complex commands are broken down accurately without mangling argument boundaries.

### Path Detection and Stripping

The first token is inspected for path separators (`/` or `\`). If the executable contains these characters, dcg treats it as a file path and checks whether the base name matches `git` or `rm` using **case-sensitive comparison**. When matched, the code extracts only the file name using `Path::file_name`, effectively removing any leading directory components:

- `/usr/bin/git` becomes `git`
- `/opt/local/bin/rm` becomes `rm`
- `/bin/rm` becomes `rm`

This step prevents attackers from circumventing the blacklist by invoking binaries via absolute paths.

### Command Reassembly

After stripping the directory components, dcg combines the cleaned executable name with the original argument list. The resulting **canonical form** is then passed to the safety evaluation engine, ensuring consistent pattern matching regardless of how the binary was originally invoked.

## Implementation Details in src/normalize.rs

The core logic uses Rust's standard library path manipulation to extract base names safely. Here are practical examples demonstrating the transformation:

```rust
// Example: Normalizing a git command with an absolute path
let raw = "/usr/bin/git reset --hard HEAD";
let normalized = normalize_command(raw);
// `normalized` now holds "git reset --hard HEAD"

```

```rust
// Example: Normalizing an rm invocation with an absolute path
let raw = "/bin/rm -rf /tmp/cache";
let normalized = normalize_command(raw);
// `normalized` becomes "rm -rf /tmp/cache"

```

These transformations occur before any destructive pattern checks, ensuring that `/usr/local/bin/git reset --hard` is correctly identified as a dangerous command rather than being missed due to the unusual path prefix.

## Integration with the Evaluation Pipeline

The normalization stage operates independently of configuration settings but feeds directly into the safety-critical components of dcg:

- **[[`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs)](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs)** receives the normalized command and applies safe- and destructive-pattern matching against the canonical form.
- **[[`src/main.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/main.rs)](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/main.rs)** serves as the entry point, feeding raw hook JSON into the normalizer before evaluation begins.
- **[[`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs)](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs)** holds pack configuration settings, though normalization executes regardless of specific pack enablement states.

## Summary

- **Command normalization** in dcg prevents evasion by stripping absolute paths from `git` and `rm` binaries before pattern matching.
- The logic in [`src/normalize.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/normalize.rs) uses `Path::file_name` to extract base names when path separators are detected in the executable token.
- **Whitespace-aware tokenization** handles quoted strings and escaped spaces correctly during the parsing phase.
- Normalized commands are reassembled and passed to [`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs) for destructive pattern detection.
- This process ensures that `/usr/bin/git reset --hard` and `git reset --hard` are evaluated identically.

## Frequently Asked Questions

### Why does dcg only normalize git and rm commands?

The normalization logic specifically targets `git` and `rm` binaries because these represent the most common vectors for destructive operations in shell environments. The case-sensitive check ensures that only these exact executable names trigger path stripping, preventing false positives while catching evasion attempts using absolute paths like `/usr/local/bin/git` or `/opt/homebrew/bin/rm`.

### How does dcg handle quoted paths or escaped spaces during normalization?

The tokenizer in [`src/normalize.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/normalize.rs) implements **whitespace-aware parsing** that respects shell quoting rules. It correctly handles double-quoted paths, single-quoted strings, and escaped spaces within the command string, ensuring that the executable token is identified accurately even when arguments contain complex whitespace patterns.

### Can command normalization be disabled in dcg?

According to the source code in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs), normalization operates as a core preprocessing step independent of pack configuration settings. The path-stripping logic executes before pattern evaluation regardless of which safety packs are enabled, making it a mandatory security control rather than an optional feature.

### What happens after a command is normalized?

Once normalized, the canonical command string flows into [`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs) where it undergoes **destructive pattern matching**. The evaluator compares the cleaned command against known dangerous patterns (such as `git reset --hard` or `rm -rf /`). If a match occurs, dcg blocks the command; otherwise, it permits execution to proceed.