HOWTOIntermediate

AIDE File Integrity Monitoring: Detect Unauthorized Changes on Linux

Deploy AIDE (Advanced Intrusion Detection Environment) to build a cryptographic baseline of your Linux filesystem and automatically alert on unauthorized...

Dylan H.

Tutorials

August 3, 2026
9 min read
AIDE File Integrity Monitoring: Detect Unauthorized Changes on Linux

Introduction

One of the quietest signs of a breach is a modified system file. An attacker who has gained a foothold will often alter binaries, add cron jobs, plant SSH keys, or tamper with /etc/passwd — all without triggering firewall rules or noisy network events. File Integrity Monitoring (FIM) catches exactly this class of activity.

AIDE (Advanced Intrusion Detection Environment) is a mature, open-source FIM tool that builds a cryptographic database of your filesystem at a known-good point in time. On every subsequent check, it compares the live filesystem against that baseline and reports every change — added files, deleted files, and altered attributes like permissions, ownership, size, and hash values.

This guide walks through installing and configuring AIDE on a Linux server, automating daily integrity checks, sending email alerts on findings, and integrating the output with a central log pipeline. It is directly applicable to CIS Controls v8 (Control 3.14 — Log Sensitive Data Access) and PCI DSS requirement 11.5.


Prerequisites

Before starting, ensure you have:

  • A freshly patched Linux server (Ubuntu 22.04/24.04, Debian 12, or RHEL/Rocky 9)
  • Root or sudo access
  • postfix or sendmail installed if you want email alerts (optional but recommended)
  • Enough disk space for the AIDE database — typically 50–200 MB depending on filesystem size

Tip: Run the initial AIDE database build immediately after a clean OS installation and before installing any applications. This gives you the cleanest possible baseline.


Step 1 — Install AIDE

Ubuntu / Debian

sudo apt update
sudo apt install -y aide aide-common

RHEL / Rocky / AlmaLinux

sudo dnf install -y aide

Verify the installation:

aide --version

The output should show something like Aide 0.18.x or newer.


Step 2 — Review and Customize the Configuration

AIDE's configuration lives at /etc/aide/aide.conf (Debian/Ubuntu) or /etc/aide.conf (RHEL). It defines which directories to monitor and what attributes to check.

Open the config file:

sudo nano /etc/aide/aide.conf

Understanding Rule Groups

AIDE uses named rule groups that combine attribute checks. The default installation ships sensible defaults, but review the key directives:

# Default rule groups (common built-ins)
FIPSR = p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha512
CONTENT = sha256+ftype
CONTENT_EX = sha256+ftype+p+u+g+n+acl+selinux+xattrs
DATAONLY = p+n+u+g+s+acl+selinux+xattrs+sha256
  • p = permissions, i = inode, n = number of links
  • u = user, g = group, s = size, m = mtime, c = ctime
  • sha256 / sha512 = cryptographic hash of file content

Key Directories to Monitor

A minimal high-value configuration watches:

# Critical binaries and libraries
/bin    CONTENT_EX
/sbin   CONTENT_EX
/lib    CONTENT_EX
/lib64  CONTENT_EX
/usr/bin  CONTENT_EX
/usr/sbin CONTENT_EX
/usr/lib  CONTENT_EX

# Configuration files
/etc    CONTENT_EX

# Boot files
/boot   CONTENT_EX

# Root home directory
/root   CONTENT_EX

# Exclude frequently-changing directories
!/etc/mtab
!/var/log
!/var/cache
!/tmp
!/proc
!/sys
!/run

Rather than editing the main config, create a drop-in file that overrides specific paths:

sudo nano /etc/aide/aide.conf.d/99-local.conf
# Watch cron directories closely
/var/spool/cron   CONTENT_EX
/etc/cron.d       CONTENT_EX
/etc/cron.daily   CONTENT_EX
/etc/cron.hourly  CONTENT_EX
/etc/cron.weekly  CONTENT_EX
/etc/cron.monthly CONTENT_EX

# Monitor SSH authorized keys for all users
/home   CONTENT_EX
!/home/.*/\.cache
!/home/.*/.local/share/Trash

# Exclude AIDE's own database file from checks
!/var/lib/aide

Save and close the file.


Step 3 — Build the Initial Baseline Database

This is the most important step. Run it on a known-good, clean system:

sudo aideinit

On Debian/Ubuntu, aideinit is a wrapper that calls aide --init and then copies the generated database to the active location:

AIDE, version 0.18.x

### AIDE database at /var/lib/aide/aide.db.new initialized.

The new database is written to /var/lib/aide/aide.db.new. Promote it to the active database:

sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db

Security note: Store an offline copy of this database. If an attacker can modify aide.db itself, they can cover their tracks. Consider copying it to read-only storage or a remote server:

scp /var/lib/aide/aide.db backups@192.168.1.50:/backups/aide/$(hostname)-$(date +%F).db

Step 4 — Run Your First Integrity Check

With the baseline in place, run a manual check:

sudo aide --check

On a freshly initialized system, the output should show no changes:

AIDE, version 0.18.x

### All files match AIDE database. Looks okay!

If you have recently updated packages or changed config files since the aideinit, you may see legitimate changes. Review them and — once confirmed safe — update the baseline (covered in Step 7).


Step 5 — Automate Daily Checks with Cron

Create a daily cron job that runs AIDE and emails the output:

sudo nano /etc/cron.d/aide-check
# Run AIDE integrity check daily at 03:15 and mail results to root
15 3 * * * root /usr/bin/aide --check 2>&1 | /usr/bin/mail -s "AIDE Integrity Check: $(hostname) $(date +%F)" root

If you prefer a dedicated script that filters output and only sends mail when changes are detected:

sudo nano /usr/local/sbin/aide-check.sh
#!/usr/bin/env bash
# AIDE integrity check — only alert on actual findings
set -euo pipefail
 
AIDE_BIN="/usr/bin/aide"
ALERT_EMAIL="security@example.com"
HOSTNAME="$(hostname -f)"
DATE="$(date +%F)"
LOGFILE="/var/log/aide/aide-$(date +%Y%m%d).log"
 
mkdir -p /var/log/aide
 
OUTPUT="$($AIDE_BIN --check 2>&1)"
EXIT_CODE=$?
 
echo "$OUTPUT" >> "$LOGFILE"
 
# AIDE exits 0 if no changes, non-zero if there are changes or errors
if [[ $EXIT_CODE -ne 0 ]]; then
    echo "$OUTPUT" | mail \
        -s "[ALERT] AIDE found changes on $HOSTNAME ($DATE)" \
        -a "From: aide-monitor@$HOSTNAME" \
        "$ALERT_EMAIL"
    echo "[$(date)] Changes detected — alert sent to $ALERT_EMAIL" >> "$LOGFILE"
else
    echo "[$(date)] No changes detected." >> "$LOGFILE"
fi

Make it executable and add the cron entry:

sudo chmod +x /usr/local/sbin/aide-check.sh
sudo nano /etc/cron.d/aide-check
15 3 * * * root /usr/local/sbin/aide-check.sh

Step 6 — Forward AIDE Logs to Syslog / SIEM

To feed AIDE output into a centralized log platform (Graylog, Splunk, Wazuh, Loki), pipe the output through the system logger:

sudo nano /usr/local/sbin/aide-check.sh

Update the script to also log to syslog:

OUTPUT="$($AIDE_BIN --check 2>&1)"
EXIT_CODE=$?
 
# Log a structured summary line to syslog
if [[ $EXIT_CODE -ne 0 ]]; then
    logger -t aide -p security.warning "INTEGRITY_VIOLATION host=$HOSTNAME date=$DATE exit_code=$EXIT_CODE"
else
    logger -t aide -p security.info "INTEGRITY_OK host=$HOSTNAME date=$DATE"
fi

If you are running Wazuh, it has native AIDE integration. Add this to your agent's ossec.conf:

<localfile>
  <log_format>syslog</log_format>
  <location>/var/log/aide/aide-*.log</location>
</localfile>

Wazuh ships built-in rules for AIDE log events (rule IDs 550–552).


Step 7 — Update the Baseline After Legitimate Changes

After system updates or intentional config changes, update the AIDE database to avoid false positives on the next check:

# After an apt upgrade or intentional file changes:
sudo apt upgrade -y
 
# Rebuild the database
sudo aide --update
 
# Promote the new database
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db

Workflow tip: Always run aide --update after patch maintenance windows, not before. This records the post-patch state as your new clean baseline.


Step 8 — Protect the AIDE Binary and Database

An attacker who can replace aide itself or tamper with aide.db can make changes invisible. Harden the tooling:

Immutable Flags (Linux ext4/xfs)

# Make the AIDE database immutable — must be removed before updates
sudo chattr +i /var/lib/aide/aide.db
 
# Remove before baseline update, then re-apply
sudo chattr -i /var/lib/aide/aide.db
sudo aide --update
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db
sudo chattr +i /var/lib/aide/aide.db

Verify the AIDE Binary Hash Manually

sha256sum /usr/bin/aide
# Store this output offline for manual verification

Consider AIDE Over SSH (Remote Execution)

For high-security environments, run AIDE from a trusted jump host over SSH so local root cannot tamper with results:

# From a remote admin host
ssh -i ~/.ssh/admin-key admin@target-server "sudo aide --check" 2>&1 | tee aide-$(date +%F)-remote.log

Verification and Testing

Test That AIDE Detects Changes

Create a test scenario to confirm AIDE is working:

# 1. Create a test file in a monitored path
sudo touch /etc/aide-test-file.txt
 
# 2. Run AIDE check — it should report the new file
sudo aide --check
 
# Expected output includes something like:
# f++++++++++++++++: /etc/aide-test-file.txt
 
# 3. Clean up
sudo rm /etc/aide-test-file.txt
sudo aide --update
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db

Interpret AIDE Output

The change codes in AIDE output follow this format:

f+++++++++++++++++: /path/to/file   <- new file added
f-----------------: /path/to/file   <- file removed
f...5.....S.......: /path/to/file   <- sha256 changed + size changed

Key change indicators:

SymbolMeaning
fregular file
ddirectory
+attribute added (new)
-attribute removed (deleted)
.no change
ppermissions changed
u / guser / group changed
ssize changed
5SHA-256 hash changed
SSHA-512 hash changed

Troubleshooting

AIDE Takes Too Long to Run

Large filesystems can make AIDE checks slow. Reduce scope by excluding high-churn directories more aggressively:

!/var
!/tmp
!/home/.*/.mozilla
!/home/.*/.config/google-chrome
!/home/.*/.cache

You can also run AIDE in parallel across filesystem mounts, or switch to using aide --compare with separate databases per mount point.

"No such file or directory" for aide.db

The active database has not been initialized or promoted:

sudo aideinit
sudo cp /var/lib/aide/aide.db.new /var/lib/aide/aide.db

Too Many False Positives After Package Updates

Always run aide --update after a package manager upgrade. If false positives persist, identify the noisy paths:

sudo aide --check 2>&1 | grep '^f' | awk '{print $2}' | sort | uniq -c | sort -rn | head -20

Add the top offenders to your exclusion list in /etc/aide/aide.conf.d/99-local.conf.

AIDE Reports Changes in /proc or /sys

These virtual filesystems change constantly. Ensure they are excluded:

!/proc
!/sys
!/run
!/dev

Mail Alerts Not Sending

Confirm mailutils is installed and your MTA is configured:

sudo apt install -y mailutils
echo "Test" | mail -s "AIDE test" your@email.com

Check /var/log/mail.log for delivery errors.


Summary

You now have a working AIDE file integrity monitoring setup that:

  • Builds a cryptographic baseline of your Linux filesystem's known-good state
  • Detects unauthorized file additions, removals, and modifications — including hash changes, permission changes, and ownership changes
  • Runs daily checks automatically via cron and only alerts when genuine changes are found
  • Forwards findings to syslog for SIEM ingestion (Wazuh, Graylog, Loki)
  • Protects the AIDE database from tampering using immutable file attributes

AIDE directly satisfies several compliance requirements: CIS Controls v8 Control 3.14 (log sensitive data access), PCI DSS 11.5 (deploy a change detection mechanism), and NIST 800-53 SI-7 (software, firmware, and information integrity).

The next recommended layer to add is centralizing these logs in a SIEM — check out the Wazuh SIEM/XDR Deployment guide and Linux Auditd Security Monitoring guide for complementary coverage.