Back to Blog
November 15, 2025
4 min

Argus: Building a High-Performance File Integrity Monitor in Rust

File integrity monitoring (FIM) is a fundamental security control. You deploy code to production — how do you know it hasn't been tampered with? A rootkit could modify binaries, a supply chain attack could swap libraries, or an insider could alter configuration files. FIM tools detect these changes by computing cryptographic hashes of files and alerting when they differ from a known-good baseline.

The problem: most FIM tools are slow. Scanning large directories takes minutes, making continuous monitoring impractical. I built Argus to solve this — a multi-threaded file integrity monitor in Rust that processes 10,000+ files per second.

Architecture

Argus is built around three core components:

1. Recursive File Scanner

The scanner walks directory trees and collects file metadata. Using async I/O, it avoids blocking on slow storage:

async fn scan_directory(path: &Path) -> Vec<FileEntry> {
    let mut entries = Vec::new();
    let mut stack = vec![path.to_path_buf()];

    while let Some(dir) = stack.pop() {
        let mut read_dir = tokio::fs::read_dir(&dir).await.unwrap();
        while let Some(entry) = read_dir.next_entry().await.unwrap() {
            let file_type = entry.file_type().await.unwrap();
            if file_type.is_dir() {
                stack.push(entry.path());
            } else {
                entries.push(FileEntry::new(entry.path()));
            }
        }
    }
    entries
}

2. Parallel SHA256 Hashing

The bottleneck in any FIM is hashing. Computing SHA256 over thousands of files is CPU-bound work. Argus parallelizes this using Rust's ownership model to ensure safe concurrency without data races:

use rayon::prelude::*;
use sha2::{Sha256, Digest};

fn hash_files(entries: &mut [FileEntry]) {
    entries.par_iter_mut().for_each(|entry| {
        let mut hasher = Sha256::new();
        let data = std::fs::read(&entry.path).unwrap();
        hasher.update(&data);
        entry.hash = Some(format!("{:x}", hasher.finalize()));
    });
}

Rayon's par_iter_mut distributes work across threads automatically. Rust's ownership system guarantees at compile time that no two threads access the same FileEntry simultaneously — no mutexes, no locks, no data races.

3. Change Detection

Argus compares the current scan against a stored baseline. Any file with a different hash, a new file, or a missing file triggers an alert:

fn detect_changes(baseline: &HashMap<PathBuf, String>, current: &HashMap<PathBuf, String>) -> Vec<Change> {
    let mut changes = Vec::new();

    for (path, hash) in current {
        match baseline.get(path) {
            Some(old_hash) if old_hash != hash => {
                changes.push(Change::Modified(path.clone()));
            }
            None => {
                changes.push(Change::Added(path.clone()));
            }
            _ => {}
        }
    }

    for path in baseline.keys() {
        if !current.contains_key(path) {
            changes.push(Change::Removed(path.clone()));
        }
    }

    changes
}

Performance

The combination of async I/O for directory traversal and parallel hashing lets Argus process over 10,000 files per second on commodity hardware. The key performance decisions:

  • Async directory walking: Doesn't block while waiting on filesystem metadata
  • Rayon for CPU-bound hashing: Automatically scales to available cores
  • Streaming reads: Files are read in chunks rather than loaded entirely into memory
  • Batch comparison: Hash map lookups for O(1) change detection

Why Rust?

FIM tools are security-critical infrastructure. A bug in a FIM could mean:

  • Missing a tampered file (false negative)
  • Crashing under load and leaving a monitoring gap
  • Memory corruption leading to incorrect hashes

Rust eliminates entire classes of these bugs at compile time. The ownership model makes the parallel hashing inherently safe. No garbage collector means predictable performance. And the type system catches logic errors that would be runtime bugs in C or Python.

Use Cases

Argus is designed for the kind of file integrity monitoring you'd find in enterprise host-based intrusion detection systems (HIDS):

  • Server baseline monitoring: Detect unauthorized changes to system binaries
  • Compliance auditing: Prove that production files match approved versions
  • Incident response: Quickly identify which files an attacker modified
  • CI/CD verification: Ensure build artifacts haven't been tampered with

The core SHA256 hashing and change detection functionality is the same approach used in production HIDS deployments — Argus just makes it fast and memory-safe.