How to Use Lynis for Linux Security Auditing
Lynis is an open-source security auditing tool for Linux, macOS, and BSD systems. It checks hundreds of security controls — SSH config, kernel parameters, file permissions, installed software, authentication settings — and gives you a hardening index score. It runs locally as the user you specify (usually root), which means it can find misconfigurations that a remote scanner would miss.
Installation
# Debian/Ubuntu
sudo apt install lynis
# RHEL/CentOS/Amazon Linux
sudo yum install lynis
# Or install from source for the latest version
git clone https://github.com/CISOfy/lynis
cd lynis
sudo ./lynis audit system
Always use the latest version — the check database is updated frequently.
lynis update info
lynis update release # download latest if available
Running a Full Audit
# Full system audit (requires root for some checks)
sudo lynis audit system
# Audit without root (skips privileged checks)
lynis audit system
# Write report to a custom path
sudo lynis audit system --report-file /var/log/lynis-report.dat
# Non-interactive mode — useful in scripts/CI
sudo lynis audit system --no-colors --quiet
The audit takes 2–5 minutes. Output is color-coded: green (OK), yellow (suggestion), red (warning).
Understanding the Output
At the end of a run you see the Hardening Index — a score from 0 to 100.
-[ Lynis 3.1.2 Results ]-
Warnings (2):
----------------------------
! Found some information disclosure in SMTP banner [MAIL-8818]
! CUPS daemon is not needed here [PRNT-2307]
Suggestions (34):
----------------------------
* Consider hardening SSH configuration [SSH-7408]
- Details : AllowTcpForwarding (YES --> NO)
* Disable IPv6 if not needed [NETW-3015]
* Enable process accounting [ACCT-9622]
Follow-up:
----------------------------
- Show details of a test : lynis show details TEST-ID
- Check the log file : /var/log/lynis.log
- Read security controls : https://cisofy.com/lynis/controls/
Lynis security scan details:
Hardening index : 67 [############# ]
Tests performed : 248
Plugins enabled : 0
A score of 67 is typical for a default Ubuntu/Debian install. Aim for 80+ on production systems.
Fixing Common Warnings
SSH Hardening (SSH-7408)
# Show what Lynis found for SSH
sudo lynis show details SSH-7408
# Edit /etc/ssh/sshd_config
sudo nano /etc/ssh/sshd_config
Add or update these lines:
# Disable unused features
AllowTcpForwarding no
X11Forwarding no
AllowAgentForwarding no
PermitRootLogin no
# Strong ciphers and MACs
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com
# Timeouts
ClientAliveInterval 300
ClientAliveCountMax 2
LoginGraceTime 30
MaxAuthTries 3
# Logging
LogLevel VERBOSE
# Test config before restarting
sudo sshd -t && sudo systemctl restart sshd
Kernel Parameters (KRNL-6000)
# View kernel hardening suggestions
sudo lynis show details KRNL-6000
# Create a hardening sysctl file
sudo tee /etc/sysctl.d/99-hardening.conf << 'EOF'
# Disable IP forwarding unless this is a router
net.ipv4.ip_forward = 0
# Protect against SYN flood
net.ipv4.tcp_syncookies = 1
# Disable ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# Disable source routing
net.ipv4.conf.all.accept_source_route = 0
# Log martian packets
net.ipv4.conf.all.log_martians = 1
# Prevent core dumps from leaking
fs.suid_dumpable = 0
# Restrict dmesg to root
kernel.dmesg_restrict = 1
# Restrict perf events
kernel.perf_event_paranoid = 3
# Disable magic SysRq
kernel.sysrq = 0
# Prevent ptrace across process boundaries
kernel.yama.ptrace_scope = 1
# Randomize memory layout (ASLR)
kernel.randomize_va_space = 2
EOF
sudo sysctl -p /etc/sysctl.d/99-hardening.conf
Password Policy (AUTH-9282, AUTH-9286)
# Install password quality checking
sudo apt install libpam-pwquality # Debian/Ubuntu
sudo yum install libpwquality # RHEL
# Edit /etc/security/pwquality.conf
sudo tee /etc/security/pwquality.conf << 'EOF'
minlen = 14
dcredit = -1
ucredit = -1
lcredit = -1
ocredit = -1
maxrepeat = 3
usercheck = 1
EOF
# Set password aging
sudo sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 90/' /etc/login.defs
sudo sed -i 's/^PASS_MIN_DAYS.*/PASS_MIN_DAYS 1/' /etc/login.defs
sudo sed -i 's/^PASS_WARN_AGE.*/PASS_WARN_AGE 14/' /etc/login.defs
File Permissions (FILE-7524)
# Find world-writable files and directories
sudo find / -path /proc -prune -o -path /sys -prune -o -perm -002 -type f -print
# Fix common issues
sudo chmod 700 /root
sudo chmod 600 /etc/crontab
sudo chmod 700 /etc/cron.d /etc/cron.daily /etc/cron.weekly /etc/cron.monthly
sudo chmod 600 /etc/ssh/sshd_config
Comparing Scans Over Time
Lynis writes a machine-readable report to /var/log/lynis-report.dat.
# Parse the report for scores and warnings
grep -E "^(hardening_index|warning\[\]|suggestion\[\])" /var/log/lynis-report.dat | head -40
# Simple diff between two reports
diff /var/log/lynis-report-2026-03-01.dat /var/log/lynis-report.dat | grep "^[<>]"
Automating with Cron
# /usr/local/bin/lynis-scheduled.sh
#!/bin/bash
set -euo pipefail
REPORT_DIR="/var/log/lynis"
DATE=$(date +%Y-%m-%d)
REPORT="${REPORT_DIR}/report-${DATE}.dat"
LOG="${REPORT_DIR}/log-${DATE}.txt"
mkdir -p "$REPORT_DIR"
/usr/bin/lynis audit system \
--no-colors \
--quiet \
--report-file "$REPORT" \
>> "$LOG" 2>&1
SCORE=$(grep "^hardening_index=" "$REPORT" | cut -d= -f2)
WARNINGS=$(grep "^warning\[\]=" "$REPORT" | wc -l)
echo "Lynis scan ${DATE}: score=${SCORE}, warnings=${WARNINGS}" | \
mail -s "Lynis Audit ${DATE} - Score: ${SCORE}" admin@example.com || true
# Keep only last 30 reports
find "$REPORT_DIR" -name "report-*.dat" -mtime +30 -delete
find "$REPORT_DIR" -name "log-*.txt" -mtime +30 -delete
chmod +x /usr/local/bin/lynis-scheduled.sh
# Add weekly cron job
echo "0 3 * * 0 root /usr/local/bin/lynis-scheduled.sh" | \
sudo tee /etc/cron.d/lynis-audit
Running Lynis in a CI Pipeline
Use Lynis to gate deployments on golden images.
# .github/workflows/image-audit.yml
name: Security Audit
on:
push:
paths:
- 'packer/**'
- 'ansible/**'
jobs:
lynis-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Lynis
run: |
git clone --depth 1 https://github.com/CISOfy/lynis /opt/lynis
- name: Run audit
run: |
sudo /opt/lynis/lynis audit system \
--no-colors \
--quiet \
--report-file /tmp/lynis-report.dat
- name: Check hardening index
run: |
SCORE=$(grep "^hardening_index=" /tmp/lynis-report.dat | cut -d= -f2)
echo "Hardening index: $SCORE"
if [ "$SCORE" -lt 75 ]; then
echo "::error::Hardening index $SCORE is below threshold of 75"
exit 1
fi
- name: Upload report
uses: actions/upload-artifact@v4
with:
name: lynis-report
path: /tmp/lynis-report.dat
Creating Custom Profiles for Compliance Frameworks
Lynis ships with a default profile but supports custom profiles that enable or disable specific tests. This is useful for mapping your audit to a compliance framework (CIS Benchmarks, PCI DSS, ISO 27001) or for skipping tests that are intentionally out of scope for your environment.
# Copy the default profile to create a custom one
sudo cp /etc/lynis/default.prf /etc/lynis/custom.prf
# Edit to adjust settings
sudo nano /etc/lynis/custom.prf
Useful profile settings:
# /etc/lynis/custom.prf
# Skip specific test IDs (one per line)
# Example: skip CUPS check if this server has no printing
skip-test=PRNT-2307
# Skip the SMTP banner disclosure check if you intentionally show hostname
skip-test=MAIL-8818
# Set minimum score threshold (used for CI enforcement)
minimum-score=75
# Set report file location
report-file=/var/log/lynis/lynis-report.dat
# Enable verbose output
verbose=yes
# Disable colored output (cleaner for log files)
colors=no
# Log file location
logfile=/var/log/lynis/lynis.log
Run with the custom profile:
sudo lynis audit system --profile /etc/lynis/custom.prf
For CIS Benchmark compliance, Lynis maps many of its test IDs to CIS controls. Check which tests align with your target framework:
# View all available tests and their categories
sudo lynis show tests | grep -E "(AUTH|SSH|KRNL|FILE)" | head -30
# Check details of a specific test
sudo lynis show details AUTH-9282
sudo lynis show details KRNL-6000
# List all test categories
sudo lynis show categories
Interpreting the Lynis Report for Remediation Priority
The Lynis report file is tab-separated and machine-parseable. A score of 80+ is achievable on most servers within a few hours of remediation — but not all suggestions have equal impact on your actual security posture.
Prioritize in this order:
| Priority | Test Type | Examples | Impact |
|---|---|---|---|
| 1 | Warnings (red) | Open world-readable sensitive files, root SSH enabled | High — active risk |
| 2 | Authentication tests | Weak password policy, no account lockout | High — attack vector |
| 3 | SSH hardening | Weak ciphers, forwarding enabled | Medium — reduces attack surface |
| 4 | Kernel hardening | Missing sysctl settings | Medium — defense in depth |
| 5 | Suggestions (yellow) | Missing auditing, unused services | Low — incremental improvement |
Track your improvement over time by saving the score after each remediation pass:
# Quick score check without running a full audit
grep "^hardening_index=" /var/log/lynis-report.dat
# Score trend from multiple reports
for report in /var/log/lynis/report-*.dat; do
date=$(basename "$report" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}')
score=$(grep "^hardening_index=" "$report" | cut -d= -f2)
echo "$date: $score"
done | sort
A realistic improvement path for a default Ubuntu server: 60 → 72 (SSH hardening + kernel params, 30 min) → 80 (password policy + file permissions, 1 hour) → 85+ (auditd + AppArmor profiles, 2-3 hours).
Related Articles
- How to Audit npm Packages for Security
- VPN Provider Annual Audit Results: Independent Security
- Linux File Permissions Privacy
- Arch Linux Hardened Kernel Installation Guide For Advanced
- How to Audit Your Password Manager Vault: A Practical Guide
- How to Audit What Source Code AI Coding Tools Transmit Built by theluckystrike — More at zovo.one