DEV Community

Cover image for πŸ”₯ Building Vigilo: A 15MB File Integrity Monitor That Outperforms OSSEC
Freemen HOUNGBEDJI
Freemen HOUNGBEDJI

Posted on

πŸ”₯ Building Vigilo: A 15MB File Integrity Monitor That Outperforms OSSEC

🚨 The Night Everything Broke
My former employer got hacked.

At 3:07 AM, an attacker modified /etc/sudoers.
No alerts.
No logs reviewed.
No alarms.

We noticed it 3 days later.
That night, I opened a blank Python file:
file_monitoring.py
That file became Vigilo.

❌ Why Existing Tools Failed Us
We didn’t ignore security tools.
We tried them.

OSSEC
❌ 200+ MB RAM on idle
❌ 50+ lines of XML config for a single file
❌ False positives drowning real alerts

Wazuh
❌ 30+ minutes installation
❌ YAML + agents + dashboards
❌ Massive overkill for < 50 servers

What we needed was simple:

β€œTell me immediately when a critical file changes.
Nothing more. Nothing less.”

πŸ› οΈ What I Built Instead

Vigilo is a lightweight File Integrity Monitor built for real-world ops teams.

πŸ’Ύ < 15 MB RAM
⚑ < 1 second alert latency
🧠 Zero configuration hell
🐍 100% Python, easy to hack & extend

🎯 Core Design Principles

Install in under 60 seconds
Minimal memory footprint
Readable, auditable code
Production-ready from day one

🧩 Technical Architecture
vigilo/
β”œβ”€β”€ file_monitoring.py # SHA-256 + metadata tracking
β”œβ”€β”€ FileWatcher.py # inotify wrapper with smart filtering
β”œβ”€β”€ logger.py # thread-safe persistent storage
β”œβ”€β”€ alert_manager.py # system / future email / webhook alerts
└── main.py # CLI entrypoint

⚑ Performance Optimizations That Matter
1️⃣ In-Memory Baseline Cache
Before (slow, disk-bound):
def handle_event(path):
baseline = read_from_disk(path)

After (fast, O(1)):
def handle_event(path):
baseline = self.cache[path]
πŸ“ˆ Result: 10Γ— faster event processing.

2️⃣ Atomic Writes (No Corrupted State)
temp = "file_info.json.tmp"
write_to(temp)
os.replace(temp, "file_info.json") # POSIX atomic

Even a crash won’t break your baseline.

3️⃣ Thread Safety (Because Events Are Brutal)
_db_lock = threading.Lock()
with _db_lock:
save_state()
No race conditions. No silent corruption.

πŸ“Š Benchmarks

Test: Monitoring /etc/nginx/nginx.conf
Load: 10 modifications / second

Tool CPU RAM False Positives
Vigilo 0.8% 11 MB 0
OSSEC 3.2% 187 MB 14
Wazuh 5.1% 243 MB 23

πŸš€ Usage

Install

pip install -r requirements.txt

Add file to monitoring

vigilo add /etc/nginx/nginx.conf --preset full --alert system

Start monitoring

vigilo start
Modify the file β†’ desktop alert in < 1 second.

πŸ” Security First (Yes, Even the Tool)

βœ… Path whitelisting (no /etc/shadow)
βœ… Command injection protection (shlex.quote)
βœ… Strict file permissions (0o600)
βœ… Input validation on all CLI arguments

πŸŒ™ Lessons Learned (The Hard Way)

Night 1 β€” The Watchdog Spam
One file triggered 1000+ events/min.
πŸ‘‰ Fixed by filtering events before processing.

Night 2 β€” The Performance Breakthrough
Added in-memory cache.
πŸ‘‰ Everything became 10Γ— faster.

Night 3 β€” The Security Obsession
Found a command injection flaw in alert execution.
πŸ‘‰ 6 hours replacing everything with shlex.quote().

Worth it.

❌ When NOT to Use Vigilo
You manage 1000+ servers
You need advanced event correlation
You require enterprise SLAs
You must meet strict compliance (β†’ use Tripwire / Wazuh)
βœ… When Vigilo Is Perfect:
< 100 servers
You want something that just works
You hate false positives
You like tools you can actually read and modify

🌍 Open Source
πŸ”— GitHub: https://github.com/FreemenTech/Vigilo
πŸ“„ License: MIT
Contributions are welcome πŸ™Œ
πŸ’¬ Questions or feedback? Drop them below πŸ‘‡

Top comments (0)