Output & Reports
infraudit generates detailed security audit reports in four formats. Each report groups findings by category, sorts them by severity, and provides actionable remediation for every finding.
Report Structure
Every report — regardless of format — contains the same information:
| Field | Description | Purpose |
|---|---|---|
id |
Unique check identifier (e.g. AUTH-001) |
Reference for skipping, filtering, and cross-referencing with compliance frameworks |
name |
Human-readable check name | Quick understanding of what was tested |
category |
One of 17 audit categories (auth, pam, network, etc.) | Grouping and filtering — assign findings to the right team |
severity |
CRITICAL, HIGH, MEDIUM, LOW, or INFO | Prioritization — tells you which findings to fix first |
status |
PASS, WARN, FAIL, ERROR, or SKIPPED | Outcome — did the check pass or is action required? |
message |
Detailed finding description | Explains exactly what was found and the current state |
remediation |
How to fix the finding (only for WARN/FAIL/ERROR) | Actionable steps to resolve the issue — often a single command |
Status Levels
Each check returns one of four status levels:
| Status | Meaning | Action Required |
|---|---|---|
| PASS | The check passed — the system meets the security requirement | None. This is the desired state. |
| WARN | A potential issue was found but it may be acceptable in context | Review the finding. It may be a conscious risk acceptance, or it may need fixing. Warnings include items like informational ports open, non-default configurations, or best practices not fully implemented. |
| FAIL | The check failed — a security requirement is not met | Fix this. A failed check means the system has a specific, known vulnerability or misconfiguration. The remediation field provides the exact steps to resolve it. |
| ERROR | The check could not be executed (missing permissions, file not found) | Investigate why the check couldn't run. Common causes: not running as root, missing packages, or non-standard system configuration. Run with sudo for full results. |
| SKIPPED | The check was skipped — platform requirements not met (OS family, init system, or package manager) | None. This is expected on systems where the check doesn't apply. Skipped checks do not affect the hardening score. Example: RHEL-specific crypto-policy checks are skipped on Debian. |
Severity Levels
Severity indicates the risk level of the finding, guiding prioritization:
| Severity | Risk | Response Time | Examples |
|---|---|---|---|
| CRITICAL | Directly exploitable vulnerability. An attacker can gain unauthorized access or full system control. | Immediate — fix within hours | Root login via SSH, empty passwords, open relay, privileged containers, world-readable shadow file |
| HIGH | Significant risk that requires prompt attention. May enable privilege escalation or data exposure. | Urgent — fix within days | Pending security updates, missing firewall, SSH password auth, no intrusion prevention, SUID abuse |
| MEDIUM | Security best practice not applied. Increases overall risk but not immediately exploitable. | Planned — fix within weeks | Missing mount options, IP forwarding enabled, no audit rules, no cron access control |
| LOW | Recommended improvement with low direct risk. Defense-in-depth measure. | Backlog — fix when convenient | Missing login banner, NTS not enabled, wireless on server, Bluetooth active |
| INFO | Informational finding. No action required, provided for context. | None | Container runtime detected, system configuration details |
Console Output (default)
The console format is designed for interactive use. It groups checks by category, sorts failures first, uses ANSI colors for instant visual scanning, and includes a progress bar summary.
$ sudo infraudit audit --category auth
infraudit v2.2.1 — Security Audit Report
────────────────────────────────────────────────────
AUTH — Users & Authentication 5 passed 2 warn 1 fail
──────────────────────────────────────────────────────────────────
✗ FAIL AUTH-001 CRITICAL PermitRootLogin is set to 'yes'
↳ Set 'PermitRootLogin no' in /etc/ssh/sshd_config
! WARN AUTH-006 HIGH Found 2 NOPASSWD entries in sudoers
↳ Review NOPASSWD entries and remove unnecessary ones
! WARN AUTH-008 MEDIUM su is not restricted via pam_wheel.so
↳ Uncomment 'auth required pam_wheel.so' in /etc/pam.d/su
✓ PASS AUTH-003 CRITICAL Only root has UID 0
✓ PASS AUTH-007 HIGH Permissions correct
✓ PASS AUTH-005 HIGH All system accounts have nologin
✓ PASS AUTH-002 HIGH PasswordAuthentication is 'no'
✓ PASS AUTH-004 CRITICAL No users have empty passwords
══════════════════════════════════════════════════════════════════
SUMMARY
████████████████████████████████████████ 5/8 checks
✓ 5 Passed ! 2 Warnings ✗ 1 Failures 0 Errors
══════════════════════════════════════════════════════════════════
Reading the console report
- Category headers show pass/warn/fail counts per category at a glance
- Findings are sorted: FAIL first, then WARN, then PASS — so critical issues are always at the top
- Remediation lines (↳) appear only for non-passing checks and give you the exact command or config change
- Progress bar gives a visual ratio of passed vs. total checks
JSON Output
Machine-readable format for CI/CD pipelines, monitoring systems, and custom dashboards. Use --format json to enable.
$ sudo infraudit audit --format json --output report.json
{
"checks": [
{
"id": "AUTH-001",
"name": "SSH root login disabled",
"category": "auth",
"severity": "CRITICAL",
"status": "FAIL",
"message": "PermitRootLogin is set to 'yes'",
"remediation": "Set 'PermitRootLogin no' in /etc/ssh/sshd_config"
},
{
"id": "AUTH-003",
"name": "Only root has UID 0",
"category": "auth",
"severity": "CRITICAL",
"status": "PASS",
"message": "Only root has UID 0"
}
],
"summary": {
"total": 287,
"passed": 98,
"warnings": 25,
"failures": 7,
"errors": 2,
"skipped": 3,
"score": 72,
"grade": "C",
"duration_seconds": 2.3,
"os": {
"id": "ubuntu",
"name": "Ubuntu",
"version": "24.04",
"family": "debian",
"pkg_manager": "apt",
"init_system": "systemd",
"arch": "amd64"
}
}
}
JSON use cases
- CI/CD gates: Parse the summary to block deployments with critical failures
- Monitoring: Feed results into Grafana, Datadog, or ELK for historical trending
- Automation: Use
jqto extract specific findings:jq '.checks[] | select(.status=="FAIL")' - Compliance: Archive JSON reports as evidence of periodic security assessments
- Comparison: Diff two JSON reports to track remediation progress over time
YAML Output
Human-friendly structured format for integration with configuration management tools. Use --format yaml.
$ sudo infraudit audit --format yaml --output report.yaml
summary:
total: 287
passed: 98
warnings: 25
failures: 7
errors: 2
skipped: 3
score: 72
grade: C
duration_seconds: 2.3
os:
id: ubuntu
name: Ubuntu
version: "24.04"
family: debian
pkg_manager: apt
init_system: systemd
arch: amd64
checks:
- id: AUTH-001
name: SSH root login disabled
category: auth
severity: CRITICAL
status: FAIL
message: "PermitRootLogin is set to 'yes'"
remediation: "Set 'PermitRootLogin no' in /etc/ssh/sshd_config"
- id: AUTH-003
name: Only root has UID 0
category: auth
severity: CRITICAL
status: PASS
message: Only root has UID 0
YAML use cases
- Ansible/Puppet: Parse YAML reports to generate remediation playbooks automatically
- Documentation: YAML is easy to include in wikis, tickets, and runbooks
- GitOps: Commit reports to a repository for change tracking and audit trails
HTML Output
Visual, self-contained report that opens in any browser. Use --format html. The report is a single .html file with embedded CSS — no external dependencies. Dark theme, responsive design, print-friendly.
$ sudo infraudit audit --format html --output report.html
What the HTML report includes
- Header: Version, hostname, timestamp, and audit duration
- Summary dashboard: Four metric cards (Passed, Warnings, Failures, Errors) with a color-coded progress bar
- Category sections: Checks grouped by category with status badges, severity indicators, and per-category statistics
- Remediation: Fix instructions shown inline for every non-passing check
- Print to PDF: Use Ctrl+P in the browser for a clean PDF export
HTML use cases
- Client deliverables: Send a professional audit report to clients or management
- Compliance evidence: Attach to compliance tickets as proof of security assessment
- Team review: Share via Slack, email, or wiki — opens in any browser, no tools needed
- PDF generation: Print from browser for a formatted PDF document
File Output
Use --output <file> with any format to write the report to a file instead of stdout:
# JSON report to file
sudo infraudit audit --format json --output /var/log/infraudit/audit-$(date +%F).json
# YAML report to file
sudo infraudit audit --format yaml --output /tmp/report.yaml
# HTML visual report
sudo infraudit audit --format html --output /var/log/infraudit/audit-$(date +%F).html
# Console report is still written to stdout when --output is used with console format
sudo infraudit audit --output /tmp/audit.txt
SARIF Output (GitHub / GitLab Integration)
SARIF (Static Analysis Results Interchange Format) is the standard format for security tools used by GitHub Code Scanning, GitLab SAST, and VS Code. Use --format sarif to generate it.
$ sudo infraudit audit --format sarif --output results.sarif
GitHub Action
Use the official civanmoreno/infraudit/action to integrate infraudit into your workflows. It supports two modes: local (audit the GHA runner) and SSH (audit a remote server).
Modo local (en el runner)
# .github/workflows/security-audit.yml
name: Security Audit
on: [push]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run infraudit
uses: civanmoreno/infraudit/action@v2
id: audit
with:
min-score: 70
format: sarif
Modo SSH (servidor remoto)
- name: Audit production
uses: civanmoreno/infraudit/action@v2
with:
mode: ssh
host: deploy@prod.example.com
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
profile: web-server
min-score: 80
format: sarif
Auditoría de flota (múltiples servidores)
jobs:
audit:
strategy:
matrix:
server:
- { name: web-1, host: "deploy@web1.example.com", profile: web-server }
- { name: db-1, host: "deploy@db1.example.com", profile: db-server }
steps:
- name: Audit ${{ matrix.server.name }}
uses: civanmoreno/infraudit/action@v2
with:
mode: ssh
host: ${{ matrix.server.host }}
ssh-key: ${{ secrets.FLEET_SSH_KEY }}
profile: ${{ matrix.server.profile }}
min-score: 70
Outputs disponibles
| Output | Descripción |
|---|---|
score | Hardening Index (0-100) |
grade | Letra (A-F) |
total | Total de checks |
passed | Checks que pasaron |
failures | Checks que fallaron |
report-path | Ruta al reporte JSON |
Los resultados SARIF se suben automáticamente a Security → Code scanning alerts en GitHub.
What happens in GitHub
- Findings appear in Security → Code scanning alerts
- Each finding can be assigned, triaged, or dismissed with a reason
- Findings auto-close when the next scan no longer detects them
- GitHub sends notifications when new findings appear
- PRs can be blocked if there are open security alerts
Severity mapping
| infraudit | SARIF security-severity | GitHub display |
|---|---|---|
| CRITICAL | 9.5 | Critical |
| HIGH | 7.5 | High |
| MEDIUM | 5.0 | Medium |
| LOW | 2.5 | Low |
| INFO | 0.0 | Note |
Other uses
- GitLab: Upload as a SAST artifact in your
.gitlab-ci.yml - VS Code: Open
.sariffiles directly with the SARIF Viewer extension - Azure DevOps: Supports SARIF natively in its security dashboard
Comparing Reports (diff)
Use infraudit diff to compare two JSON audit reports and see what changed. This is essential for tracking remediation progress and detecting regressions.
# Run audit before remediation
sudo infraudit audit --format json --output before.json
# ... apply security fixes ...
# Run audit after remediation
sudo infraudit audit --format json --output after.json
# Compare the two reports
infraudit diff before.json after.json
What the diff shows
The diff output is organized into sections, ordered by priority:
| Section | Meaning | Example |
|---|---|---|
| Regressions | Checks that got worse (e.g. PASS → FAIL, PASS → WARN) | A firewall was disabled, a service was exposed |
| Improvements | Checks that got better (e.g. FAIL → PASS, WARN → PASS) | SSH root login was disabled, permissions were fixed |
| New checks | Checks present in the after report but not in before | A new version of infraudit added checks |
| Removed checks | Checks present in before but not in after | Checks were skipped or a category was excluded |
The report also shows the Hardening Index delta — the score change between the two reports (e.g. 42 (F) → 78 (C) +36).
Example output
$ infraudit diff before.json after.json
infraudit diff — Audit Comparison
────────────────────────────────────────────────────
Hardening Index: 42 (F) → 78 (C) +36
Regressions (1)
──────────────────────────────────────────────────────
↓ NET-001 HIGH PASS → FAIL
Improvements (3)
──────────────────────────────────────────────────────
↑ FS-001 HIGH WARN → PASS
↑ AUTH-001 CRITICAL FAIL → PASS
↑ AUTH-002 HIGH FAIL → PASS
New checks (1)
──────────────────────────────────────────────────────
+ LOG-001 MEDIUM - → PASS
══════════════════════════════════════════════════════
SUMMARY ↑ 3 improved ↓ 1 regressed + 1 new · 0 unchanged
══════════════════════════════════════════════════════
Exit codes for diff
| Code | Meaning | CI/CD Action |
|---|---|---|
0 |
No regressions — all changes are improvements or unchanged | Proceed — security posture is stable or improved |
1 |
Regressions detected — one or more checks got worse | Block — investigate why checks regressed before deploying |
CI/CD workflow with diff
# Store baseline report in your repo or artifact storage
infraudit audit --format json --output baseline.json
# In CI/CD pipeline: compare current state against baseline
infraudit audit --format json --output current.json
infraudit diff baseline.json current.json
if [ $? -ne 0 ]; then
echo "Security regression detected — blocking deployment"
exit 1
fi
# If passed, update baseline for next run
cp current.json baseline.json
Remote Scanning (SSH)
Use infraudit scan to audit remote servers without installing anything on them. The binary is copied via SCP, executed via SSH, and cleaned up automatically.
Single host
# Audit a remote server
infraudit scan --host root@192.168.1.10
# With custom SSH port and sudo
infraudit scan --host deploy@server.com:2222 --sudo
# With specific SSH key
infraudit scan --host ubuntu@server.com --identity ~/.ssh/prod_key
# With password authentication (requires sshpass)
infraudit scan --host root@server.com --password mypassword
# Filter checks on the remote
infraudit scan --host root@server.com --category auth,network --profile web-server
Multiple hosts
Create a hosts file (one per line, # for comments):
# servers.txt
root@web1.example.com
root@web2.example.com:2222
deploy@db1.example.com
# Scan all hosts, 5 concurrent
infraudit scan --hosts servers.txt --concurrency 5
# JSON output for all hosts
infraudit scan --hosts servers.txt --format json --output fleet-report.json
How it works
- Detects remote architecture via
ssh host uname -m - Copies the matching infraudit binary to
/tmpvia SCP - Executes
infraudit audit --format jsonon the remote - Collects JSON output and renders locally
- Removes the binary from the remote (unless
--keep-binary)
Authentication
Two authentication methods are supported:
| Method | Usage | Notes |
|---|---|---|
| SSH Key (recommended) | infraudit scan --host root@server |
Uses your SSH agent and ~/.ssh/config automatically. BatchMode=yes prevents password prompts. |
| Password | infraudit scan --host root@server --password pass |
Requires sshpass installed locally. Install: apt install sshpass |
Requirements
- ssh and scp on PATH — uses your system SSH, inheriting agent, config, and ProxyJump settings
- sshpass on PATH (only if using
--password) — install with your package manager - Remote: Linux with /tmp writable — the binary is placed in /tmp temporarily
Fleet summary
Multi-host scans show a fleet summary table after individual reports:
FLEET SUMMARY
────────────────────────────────────────────────────────────
Host Score Grade Failures Warnings
────────────────────────────────────────────────────────────
root@web1.example.com 72 C 8 12
root@web2.example.com 85 B 3 7
deploy@db1.example.com ERR - connection refused
════════════════════════════════════════════════════════════
Exit codes for scan
| Code | Meaning |
|---|---|
0 | All hosts passed (no failures or warnings) |
1 | Warnings found on at least one host |
2 | Failures found on at least one host |
3 | Operational error (SSH connection failed, timeout) |
CIS Compliance Report
Generate a formal CIS Benchmark compliance report from your audit results. Shows compliance percentage per CIS section and lists all gaps that need remediation.
Usage
# Run audit and save JSON report
sudo infraudit audit --format json --output report.json
# Generate CIS Level 1 compliance report (default)
infraudit compliance report.json
# Generate CIS Level 2 compliance report
infraudit compliance report.json --level 2
# JSON output for automation
infraudit compliance report.json --format json
Example output
CIS Benchmark Level 1 — Compliance Report
───────────────────────────────────────────────────────
Overall: 78% compliant (117/150 controls passed)
Section Pass Total %
───────────────────────────────────────────────────────
1. Initial Setup 28 35 80%
2. Services 22 26 84%
3. Network Configuration 24 30 80%
4. Logging and Auditing 4 6 66%
5. Access, Authentication and Auth. 25 32 78%
6. System Maintenance 14 21 66%
Gaps (33)
───────────────────────────────────────────────────────
FAIL AUTH-001 5.2.1 — Ensure SSH root login is disabled
FAIL NET-001 3.5.1 — Ensure a firewall is active
WARN PAM-001 5.4.1 — Ensure password creation requirements
...
CIS Levels
| Level | Description | Controls |
|---|---|---|
| Level 1 | Essential security settings that can be applied on most systems with minimal impact on functionality. Recommended as the minimum baseline. | ~150 controls |
| Level 2 | Advanced security settings for high-security environments. May reduce functionality or require additional planning. Includes all Level 1 controls. | ~170 controls |
CIS Sections
| # | Section | What it covers |
|---|---|---|
| 1 | Initial Setup | Filesystem, boot, MAC, banners, crypto policy, patches |
| 2 | Services | Unwanted services, NTP, MTA, NFS, Samba |
| 3 | Network Configuration | Sysctl params, firewall, SNMP, DNS, IPv6 |
| 4 | Logging and Auditing | auditd rules, journald, rsyslog, logrotate |
| 5 | Access, Auth and Authorization | SSH, PAM, sudo, cron, user accounts, passwords |
| 6 | System Maintenance | File permissions, user/group integrity, duplicates |
CI/CD integration
# Generate audit + check compliance in CI
sudo infraudit audit --format json --output report.json
infraudit compliance report.json --format json > compliance.json
# Fail pipeline if compliance is below threshold
COMPLIANCE=$(cat compliance.json | jq '.overall_percentage')
if [ "$COMPLIANCE" -lt 80 ]; then
echo "CIS compliance $COMPLIANCE% is below 80% threshold"
exit 1
fi
Policy-as-Code
Define compliance requirements in a JSON policy file and enforce them automatically. Use --enforce-policy to validate audit results against your policy.
Policy file format
# .infraudit-policy.json
{
"min_score": 80,
"max_critical": 0,
"max_high": 3,
"required_pass": ["AUTH-001", "AUTH-002", "NET-001", "BOOT-005"],
"ignore": ["HARD-009", "MAL-003"]
}
| Field | Description |
|---|---|
min_score | Minimum Hardening Index score (0-100). Fails if score is below this. |
max_critical | Maximum allowed critical FAIL findings. Set to 0 for zero tolerance. |
max_high | Maximum allowed high FAIL findings. |
required_pass | Check IDs that must PASS. Fails if any of these are not PASS. |
ignore | Check IDs to exclude from policy evaluation (accepted risks). |
Usage
# Enforce with explicit policy file
sudo infraudit audit --enforce-policy .infraudit-policy.json
# Auto-detect policy file (searches ./, ~/, /etc/infraudit/)
sudo infraudit audit --enforce-policy ""
# Combine with other flags
sudo infraudit audit --profile web-server --enforce-policy policy.json --format json
Policy violation output
POLICY VIOLATION (.infraudit-policy.json)
──────────────────────────────────────────────────
min_score Score 65 is below minimum 80
max_critical 2 critical findings (maximum: 0)
required_pass AUTH-001: FAIL (required: PASS)
required_pass NET-001: WARN (required: PASS)
──────────────────────────────────────────────────
CI/CD integration
# In your CI/CD pipeline
sudo infraudit audit --enforce-policy .infraudit-policy.json --format json --output report.json
if [ $? -ne 0 ]; then
echo "Policy violation — deployment blocked"
exit 1
fi
Filtering & Profiles
Control which checks run to focus on what matters:
# Run only one category
sudo infraudit audit --category auth
# Skip specific checks you've accepted the risk for
sudo infraudit audit --skip HARD-007,SVC-012
# Use a server profile (skips irrelevant categories)
sudo infraudit audit --profile web-server
# Combine: web-server profile, JSON output, skip known exceptions
sudo infraudit audit --profile web-server --format json --skip NET-003 --output report.json
Exit Codes
infraudit returns meaningful exit codes for scripting and CI/CD integration:
| Code | Meaning | CI/CD Action |
|---|---|---|
0 |
All checks passed | Proceed — system meets security requirements |
1 |
Warnings found (no failures or errors) | Review recommended — may proceed with caution |
2 |
Failures or errors found | Block deployment — security issues must be resolved |
CI/CD Example
# GitHub Actions / GitLab CI example
sudo infraudit audit --format json --output report.json --profile web-server
EXIT_CODE=$?
# Upload report as artifact
# Then gate on exit code
if [ $EXIT_CODE -eq 2 ]; then
echo "BLOCKED: Security failures found"
cat report.json | jq '.checks[] | select(.status=="FAIL") | .id + ": " + .message'
exit 1
elif [ $EXIT_CODE -eq 1 ]; then
echo "WARNING: Review findings before production"
fi