Bypassing AIDE File Integrity Monitoring

󰃭 2025-08-21

This is a writeup on two vulnerabilities I reported in AIDE (Advanced Intrusion Detection Environment) - CVE-2025-54389 and CVE-2025-54409.

AIDE is a classic host-based file integrity monitoring (FIM) tool: it snapshots a baseline of the filesystem (hashes, permissions, ownership, xattrs, symlink targets, etc.), and on every subsequent run compares the live system against that database, printing a report of everything that’s been added, removed, or changed. It’s exactly the kind of tool an incident responder reaches for after a breach to answer “what did the attacker touch?” - and it’s exactly the kind of tool a lot of compliance frameworks (PCI-DSS, CIS benchmarks, various government hardening guides) mandate specifically because of that property.

Both advisories carry a “Moderate” severity (CVSS 6.2) - locally exploitable, no special privileges needed, no direct confidentiality impact. Read in isolation, that undersells them. For a general-purpose application, a bug that lets you corrupt your own log output isn’t very interesting. For a file-integrity monitor, corrupting the output is the impact - the entire product is the report. If an attacker can control what that report says (or whether it gets produced at all), they’ve defeated the control, not just found a bug in it.


CVE-2025-54409 Crashing AIDE with a malformed extended attribute

AIDE can be configured to track extended attributes (xattrs) on files - metadata like user.comment or SELinux labels stored outside the regular inode fields. When it builds its database, it base64-encodes xattr values for storage; when it later reads that database back to compare against the live filesystem, it decodes them.

The decoding path didn’t handle two edge cases correctly:

  • an xattr with an empty value, or
  • an xattr key name containing a comma

Either one causes AIDE to dereference a null pointer while decoding the stored attribute and segfault.

Any user with write access to a filesystem that supports xattrs (no special privileges required) can trigger it:

# Empty xattr value - crashes on database listing
touch xattrs-file
setfattr -n user.empty_value xattrs-file
aide --config <(printf -- "database_out=stdout\n$(pwd)/xattrs-file xattrs\n") --init \
  | aide --config <(printf -- "database_in=stdin\n$(pwd)/xattrs-file xattrs\n") --list

# Xattr key containing a comma - crashes on the next --check
touch xattrs-file
setfattr -n user.ke,y -v value xattrs-file
aide --config <(printf -- "database_out=stdout\n$(pwd)/xattrs-file xattrs\n") --init \
  | aide --config <(printf -- "database_in=stdin\n$(pwd)/xattrs-file xattrs\n") --check

Note the two-step nature of the trigger: the crash doesn’t happen on the run that writes the malformed attribute into the database - it happens on the next run that reads it back, specifically when the value would be shown in a report (because it changed) or the database is listed directly.

This is the more direct of the two bugs: if AIDE segfaults before it finishes comparing the filesystem to the database, it never produces a report at all. A scheduled integrity check that silently crashes looks, to most monitoring setups, indistinguishable from “nothing to report” - unless someone is specifically alerting on the AIDE process’s own exit code, which is a much less common thing to monitor than “did the report show changes.”

0.19.2 adds proper error handling around the base64 decode and correctly handles empty values and comma-containing keys. The advisory’s suggested interim mitigation, if you can’t upgrade right away, is to drop the xattrs group from your AIDE rules for filesystems where untrusted local users can write extended attributes - you lose xattr monitoring on those paths, but you stop the crash vector.


CVE-2025-54389 Hiding a file from the report with terminal escape sequences

AIDE prints its report - added files, removed files, changed files - straight to stdout/stderr (and often into a log file), including the filenames it discovered. Filenames on Linux can contain almost any byte except / and the null terminator. That includes ANSI/VT100 terminal escape sequences - the same control codes a terminal uses to move the cursor, clear a line, or change color.

AIDE wasn’t neutralizing those bytes before printing them. So a filename that embeds a “move cursor up one line” escape sequence doesn’t just get printed oddly - it actively rewrites what appears on the line above it.

mkdir test
touch test/$(echo -e 'malicious-file\033[1A')
touch test/regular-testfile
aide --config <(printf -- "database_in=file:/dev/null\nroot_prefix = ./test\n/ R") --check

The report comes back showing regular-testfile as added - and says nothing about the file with the escape sequence in its name, even though the summary count at the top still correctly says 3 added entries. The malicious filename’s own escape code moved the terminal cursor back up a line right before the next entry was printed, and that next line simply overwrote it.

This isn’t cosmetic. Think through what a defender does after AIDE flags a run as “differences found”: they read the added/removed/changed list to figure out what to investigate. If the one file that matters never appears in that list, the defender has no reason to go looking for it. The only tell is a mismatch between the summary count (“3 added”) and the number of lines actually printed (“2 shown”) - and that’s a detail that’s trivial to miss by hand, especially on a busy system where “added entries” routinely number in the dozens or hundreds after a legitimate deployment. Pad the attack with a realistic number of decoy legitimate-looking files, and the discrepancy disappears into the noise.

It’s also worth noting the bug wasn’t limited to filenames - the advisory notes that extended attribute key names and symbolic link targets get the same unsanitized treatment, which is a second, independent way to smuggle control characters into the same report.

AIDE 0.19.2 neutralizes control characters before they hit the report/log output. If you can’t upgrade immediately, the advisory’s interim mitigation is worth calling out because it’s non-obvious but effective: write the report to a regular file (report_url=file:/var/log/aide.log) rather than letting it go to a terminal, and make sure you open that file with something that doesn’t itself interpret escape sequences. A cat in a terminal is still vulnerable to the same trick at read-time; a plain text editor or grep is not.

Disclosure timeline

  • Reported to the AIDE maintainers privately.
  • Both advisories published by the maintainers on August 14, 2025.
  • Fixed together in AIDE v0.19.2.
  • CVE-2025-54389 and CVE-2025-54409 assigned.
  • Credited as finder on both advisories.

References