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

> Learn how Destructive Command Guard normalizes commands by stripping absolute paths from git and rm binaries, preventing evasion and enhancing security.

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

---

**Command normalization in the Destructive Command Guard (dcg) removes leading directory components from absolute paths pointing to `git` or `rm` executables, converting commands like `/usr/bin/git reset --hard` into `git reset --hard` to prevent evasion of destructive pattern detection.**

The Destructive Command Guard (dcg) is a security tool that intercepts potentially dangerous shell commands before they execute. Its **command normalization** engine processes every incoming command string to strip absolute paths from sensitive binaries, ensuring that pattern matching operates on a canonical form regardless of how the binary was invoked. This prevents attackers from bypassing safety checks by using fully qualified paths like `/usr/local/bin/git` instead of `git`.

## How dcg Normalizes Commands with Absolute Paths

The normalization pipeline lives 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). The module transforms raw command strings into a standardized format through a multi-stage process that specifically targets path-based evasion techniques.

### Parsing the Command String

First, dcg splits the raw input into the executable token and its arguments using whitespace-aware tokenization. The parser respects quoted strings and escaped spaces, ensuring that arguments containing paths (like target directories) remain intact while only the executable component is considered for path stripping.

### Identifying git and rm Executables

The first token of the parsed command is inspected to determine if it represents a file system path. If the token contains a path separator (`/` on Unix or `\` on Windows), dcg treats it as an absolute or relative path rather than a bare command name. The system then checks if the final component of that path matches `git` or `rm` using case-sensitive comparison.

### Stripping Directory Components with Path::file_name

When the detected executable is `git` or `rm`, dcg extracts only the file name using Rust's `Path::file_name` method. This operation removes any leading directories, leaving only the base binary name. For example:

- `/usr/bin/git` becomes `git`
- `/opt/local/bin/rm` becomes `rm`
- `/home/user/.local/bin/git` becomes `git`

This transformation occurs regardless of how deeply nested the binary resides in the file system hierarchy.

### Re-assembling the Canonical Form

After stripping the path components, dcg reconstructs the command by combining the cleaned executable name with the original argument list. The resulting normalized string is then passed to [[`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), where safe-pattern and destructive-pattern matching occurs against the canonical representation.

## Code Examples of Path Stripping in normalize.rs

The following Rust examples demonstrate the practical effect of the normalization logic on real-world command strings:

```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 command with an absolute path
let raw = "/bin/rm -rf /tmp/cache";
let normalized = normalize_command(raw);
// normalized becomes: "rm -rf /tmp/cache"

```

```rust
// Example: Preserving arguments that contain paths
let raw = "/usr/local/bin/git clean -fd /path/to/repo";
let normalized = normalize_command(raw);
// normalized becomes: "git clean -fd /path/to/repo"
// Note: /path/to/repo is preserved as an argument, not stripped

```

## Why Path Normalization Matters for Security

Without **command normalization**, an attacker could evade dcg's destructive pattern detection simply by invoking binaries through their absolute file system locations. For instance, while `git reset --hard` might trigger a safety warning, `/usr/bin/git reset --hard` could bypass the check entirely if the matcher only looks for the bare command name. By converting all invocations to a consistent baseline before evaluation, dcg ensures that security policies apply uniformly regardless of how the shell resolved the binary location.

## Summary

- **Command normalization** in dcg removes absolute path prefixes from `git` and `rm` binaries to prevent evasion attacks.
- The logic is implemented 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 uses `Path::file_name` to extract base names.
- Only the executable token is modified; arguments containing paths remain untouched to preserve command semantics.
- Normalized commands flow into [[`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) for destructive pattern matching.
- This approach ensures that `/usr/bin/git reset --hard` and `git reset --hard` are evaluated identically by the security engine.

## Frequently Asked Questions

### What is command normalization in dcg?

Command normalization is the preprocessing stage in the Destructive Command Guard that transforms incoming shell commands into a canonical format before security evaluation. It strips absolute paths from specific binaries, normalizes whitespace, and ensures that pattern matching operates on consistent command representations regardless of how the user originally typed the command.

### Which binaries does dcg strip paths from?

According to the source code 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), dcg specifically targets the `git` and `rm` executables for path stripping. When the parser detects these binary names preceded by directory components, it removes the path prefix to create a standardized command string for pattern matching.

### How does normalize.rs handle quoted arguments or escaped spaces?

The tokenizer 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) uses whitespace-aware parsing that respects quoted strings and escaped spaces. This ensures that path stripping only affects the executable token (the first element of the command) and preserves the integrity of arguments that may contain spaces or special characters.

### Where does the normalized command go after processing?

After normalization 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), the canonical command string is passed to [[`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). The evaluator then applies safe-pattern and destructive-pattern matching rules to determine whether the command should be allowed to execute or blocked as potentially dangerous.