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:

FieldDescriptionPurpose
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:

StatusMeaningAction 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:

SeverityRiskResponse TimeExamples
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
  ────────────────────────────────────────────────────

  AUTHUsers & 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

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

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

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

HTML use cases

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

OutputDescripción
scoreHardening Index (0-100)
gradeLetra (A-F)
totalTotal de checks
passedChecks que pasaron
failuresChecks que fallaron
report-pathRuta al reporte JSON

Los resultados SARIF se suben automáticamente a Security → Code scanning alerts en GitHub.

What happens in GitHub

Severity mapping

infrauditSARIF security-severityGitHub display
CRITICAL9.5Critical
HIGH7.5High
MEDIUM5.0Medium
LOW2.5Low
INFO0.0Note

Other uses

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:

SectionMeaningExample
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     PASSFAIL

  Improvements (3)
  ──────────────────────────────────────────────────────
   FS-001       HIGH     WARNPASS
   AUTH-001     CRITICAL FAILPASS
   AUTH-002     HIGH     FAILPASS

  New checks (1)
  ──────────────────────────────────────────────────────
  + LOG-001      MEDIUM   - → PASS

  ══════════════════════════════════════════════════════
  SUMMARY  ↑ 3 improved  ↓ 1 regressed  + 1 new  · 0 unchanged
  ══════════════════════════════════════════════════════

Exit codes for diff

CodeMeaningCI/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

  1. Detects remote architecture via ssh host uname -m
  2. Copies the matching infraudit binary to /tmp via SCP
  3. Executes infraudit audit --format json on the remote
  4. Collects JSON output and renders locally
  5. Removes the binary from the remote (unless --keep-binary)

Authentication

Two authentication methods are supported:

MethodUsageNotes
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

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

CodeMeaning
0All hosts passed (no failures or warnings)
1Warnings found on at least one host
2Failures found on at least one host
3Operational 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

LevelDescriptionControls
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

#SectionWhat it covers
1Initial SetupFilesystem, boot, MAC, banners, crypto policy, patches
2ServicesUnwanted services, NTP, MTA, NFS, Samba
3Network ConfigurationSysctl params, firewall, SNMP, DNS, IPv6
4Logging and Auditingauditd rules, journald, rsyslog, logrotate
5Access, Auth and AuthorizationSSH, PAM, sudo, cron, user accounts, passwords
6System MaintenanceFile 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"]
}
FieldDescription
min_scoreMinimum Hardening Index score (0-100). Fails if score is below this.
max_criticalMaximum allowed critical FAIL findings. Set to 0 for zero tolerance.
max_highMaximum allowed high FAIL findings.
required_passCheck IDs that must PASS. Fails if any of these are not PASS.
ignoreCheck 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:

CodeMeaningCI/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