CtrlOps
|Docs
Product Modules

Security Audit: Scan and Harden Your Linux Servers

Run 25 predefined security audits on a connected Linux server over SSH. Get a hardening score, a PDF report, and fix commands that wait for your approval.

What you can do in the Audit tab

  • Run any of 25 predefined audits, grouped into Server, Database, Web Servers, and Docker. Filter the catalog by category or search it by name.
  • Check what an audit looks at, how long it takes, and whether it needs sudo, before you run it.
  • Pick exactly which checks run. Every check is a checkbox and all of them start ticked.
  • Watch the run live, with the log streaming and real-time progress.
  • Read a hardening score out of 100, a findings-by-severity breakdown, and a pass, warn, fail, and skip tally.
  • Sort and filter the findings table, and see the reason a check could not answer instead of having it silently dropped.
  • Download any run as a PDF, and reopen or download past runs from the Reports tab.
  • Hand selected findings to the AI Terminal as a ready-made prompt, then approve each fix command yourself.
  • Run the same audit across many servers at once from the workspace-level Audit Reports screen.

Watch it run

The whole flow in under three minutes - pick an audit, scope the checks, read the report, and fix a finding. Every step is written out below too, so you can skip straight to running your first audit.

The Audit tab checks how a server is configured, from the inside, over an authenticated SSH session. If you want a quick look at a server from the outside with nothing to install and no account, the free VPS Security Scanner probes open ports, TLS, and HTTP headers from the public internet. They answer different questions and are worth running together.

Why an audit tab instead of a manual checklist

Doing it by handDoing it in CtrlOps
ssh user@host, then remember which questions to askClick the server, click Audit, pick from the catalog
grep -E 'PermitRootLogin|PasswordAuthentication' /etc/ssh/sshd_configPart of the SSH & Access audit
ufw status verbose, then check iptables because the box uses that insteadFirewall & Network detects which one is in use
ss -tulpn | grep LISTEN and read the output yourselfOpen Ports and External Listeners, each with a verdict
find / -perm -4000 -type f 2>/dev/nullSUID/SGID Files
openssl x509 -enddate -noout -in /etc/letsencrypt/live/*/cert.pemSSL Certificate Expiry, plus whether renewal is automated
curl -sI https://example.com | grep -i strict-transport, six times for six headersThe Security Headers audit, all six at once
Decide for yourself whether each answer is badEvery check returns a status and a severity
Write the findings up by hand afterwardsA report with a score, a severity split, and a PDF
Repeat all of it on the next serverRun on N servers from Audit Reports

Open the Audit tab

Connect to your server

Open CtrlOps and click the server you want to audit. Wait for the header to show Connected.

Click Audit in the sidebar

Audit sits at the bottom of the left sidebar, under Logs. It only appears once a connection is established, because the audits run over that session.

Read the catalog

The catalog opens on all 25 audits. The pills across the top filter it to Server, Database, Web Servers, or Docker, and the search box filters by name. The toggle at the right switches between grid and list.

Each card tells you what you need before you commit to a run: the audit name, a one-line description of what it looks at, how many checks it contains, roughly how long it takes, and a sudo required badge when full coverage needs elevated access. The i button opens the detail for that audit.

Every audit and the checks inside it are listed in the audit catalog further down, if you would rather read the whole set before you run anything.

Run your first audit

Filter to the category you care about

If you are auditing a plain application server, Server is the place to start, and SSH & Access is the audit most likely to find something. A box running Nginx and MySQL is worth auditing in all three relevant categories rather than one.

Click Generate

The green Generate button on the card starts the flow. Nothing has run on the server yet.

Choose which checks to include

A picker opens listing every check in that audit, all of them ticked. Untick anything that does not apply to this host, and use the search box if the list is long. The footer counts what is selected, and Clear all empties the list if you would rather tick a handful.

This step is the answer to "I do not want it poking at my database". Nothing outside your selection runs.

Click Continue

CtrlOps runs the selected checks over your SSH session. The log streams live and progress updates as each check resolves, so a slow check is visible rather than a frozen screen. When the run finishes, the report opens.

Audits are read-only. Every check inspects configuration, file permissions, and process state. None of them change anything on the server, so running one on production is safe.

Read the report

The report header carries the audit name, a status pill, and a line identifying the run: server name, address, date, time, and audit version. That line is what makes a downloaded PDF meaningful three months later.

Findings by severity

A donut and a count for Critical, High, Medium, and Low. This is the triage view: it answers "how bad is it" before you read a single finding.

Hardening score

A score out of 100 with a plain-language label, plus a note about the run. On a first scan it says a baseline was saved for trend, so the next run on the same server can be compared against it.

Under the score sits the coverage note. If checks were skipped because they needed elevated access, the card says so in amber with the percentage that actually ran. See Coverage and sudo below.

Checks run

The tally: how many checks passed, how many raised warnings, how many failed, and how many were skipped. Skipped is not a failure and it is not a pass, which is why it gets its own number rather than being folded into either.

Findings and recommendations

A table with four columns:

ColumnWhat it holds
TypeThe check that produced the finding
FindingThe check number, its name, and the recommendation in a sentence
StatusPASSED, WARNING, FAILED, or SKIPPED
SeverityCRITICAL, HIGH, MEDIUM, or LOW

Status and Severity are both sortable and filterable, so you can pull every failed high-severity finding to the top and work down from there.

The recommendation is written to be actionable rather than diagnostic. A real one reads:

SSL Certificate Expiry - SKIPPED - HIGH No /etc/letsencrypt/live directory - if TLS terminates elsewhere, check that platform

That is the shape of every finding: what was looked at, what was found, and what to do about it.

Statuses and severities

Every check returns exactly one status and one severity.

StatusMeaning
PASSEDThe check ran and the configuration is what it should be.
WARNINGThe check ran and found something worth changing, but it is not immediately dangerous on its own.
FAILEDThe check ran and found a real problem.
SKIPPEDThe check could not answer, and the message says why. Usually the software is not installed, or reading the file needs root.
SeverityMeaning
CRITICALExploitable now, or exposes the whole host.
HIGHA serious weakness that materially widens your attack surface.
MEDIUMWorth fixing, and usually cheap to fix.
LOWHygiene and defence in depth.

Severity describes how much the check matters, not how bad this particular server is. A SKIPPED finding can still carry HIGH severity: the check is important and it could not be answered, which is exactly the pair you want to know about.

Coverage and sudo

Audits run as the SSH user you connected with, and a large share of the checks read files that only root can open, such as mongod.conf, redis.conf, database sockets, and certificate directories. Rather than guessing or silently dropping those checks, CtrlOps reports them as skipped with the real reason:

  • MySQL not accessible - server down, or root/sudo needed for socket auth
  • Root or sudo required to read mongod.conf
  • Root or sudo required to scan backup paths
  • Need root to read certificates

The score card then shows the coverage percentage for the run, so a report built from half the checks is never presented as a clean bill of health.

Connect as a user with sudo, or as root, before you run an audit you intend to act on or send to someone. A run at low coverage is still useful for a first look, but it is not the report you want in an email.

The sudo required badge on a card tells you in advance which audits are affected. Database and Docker audits are the ones that lean on it hardest.

Fix a finding with AI

This is the part that separates the Audit tab from a scanner. A scanner ends at a list of problems; here the list is the input to the fix.

Select the findings you want to fix

Tick the checkbox at the start of each row in the findings table. Start with a single finding so you can see the whole loop before you batch them.

Click Fix selected findings

The bar above the summary cards becomes the action. Clicking it builds a prompt from the findings you selected and copies it to your clipboard. Nothing has been sent anywhere and nothing has run on the server.

Paste it into the AI Terminal

Open the AI Terminal on the same server, paste the prompt into the assistant, and press Enter. It reads the findings and works out what needs to change.

Read the command, then run it

Each command arrives in an approval card marked Awaiting approval, with the command itself and a Why this command explanation of what it does and why the assistant chose it. Read it. Then click Run to execute it, or Cancel to skip it and move on.

Nothing is remediated automatically, ever. The assistant proposes and explains; you approve. A command you cancel leaves the server exactly as it was. This is the same approval boundary that governs every command in the AI Terminal.

When you have worked through the findings, run the same audit again. The new run is scored against the same checks, so the score moving is a real measurement rather than a claim, and the first run is kept as the baseline to compare against.

Download or revisit a report

Open the report

Either use the report that opened when the audit finished, or click Reports at the top of the Audit tab. The badge on that button counts how many saved runs that server has.

Click the download icon

The download button sits at the top right of the report. It writes the whole report to your machine as a PDF: the score, the severity split, and every finding with its status and message.

Check the header before you send it

The header line carries the server name, address, date, time, and audit version, so whoever opens the PDF knows exactly which host was scanned, when, and with which version of the checks.

Run an audit on many servers

The per-server Audit tab audits the server you are connected to. To audit several at once, use the workspace-level version instead.

Open Audit Reports from the Home screen

Go to the Home tab and click Audit Reports under Tools in the left sidebar. The catalog is identical.

Click Generate and pick your checks

Same flow as a single server: choose the audit, tick the checks to include, and continue.

Select the servers

The picker lists every saved server with a checkbox and a search box for name or address. Tick the hosts you want and click Run on N servers. Each server is audited separately and gets its own report under Reports.

Running one audit across a fleet is what makes the results comparable. The same checks with the same thresholds on every host means a difference in the score is a difference in the servers, not a difference in how carefully somebody looked.

The audit catalog

The full reference: all 25 audits and every named check inside them, so you can work out which ones apply to a given server without opening the app. Approximate times are for a single server on a normal connection.

Checks for software that is not installed report as skipped, so an audit aimed at the wrong server is harmless, just not useful. Pick by what the box actually runs.

Server

AuditApproxChecks it runs
SSH & Access~14sSSH Root Login, SSH Password Auth, SSH Port, SSH Idle Timeout, Authorized Keys, UID 0 Accounts, Sudo Group Members, Sudo NOPASSWD
Firewall & Network~14sFirewall State, Firewall Rules Audit, Docker Port Exposure, Open Ports, Exposed Database Ports, IPv6 Firewall Coverage, Outbound Policy
Services & Processes~11sUnneeded Services, Running Services, External Listeners, Cron Jobs, Systemd Timers
File System~10sWorld-Writable Files, SUID/SGID Files, /tmp Permissions, Log File Permissions
Application Security~10sSSL Certificate Expiry, Certificate Auto-Renewal, Application Versions, Database Access, Resource Isolation
Logging & Monitoring~9sFail2ban, Log Rotation, Failed SSH Logins
System Updates~8sPending Updates, Unattended Upgrades, Kernel Version, Reboot Required

Database

Covers MySQL and MariaDB, PostgreSQL, MongoDB, and Redis.

AuditApproxChecks it runs
Authentication~14sMySQL Root Password, MySQL Anonymous Users, MySQL Passwordless Accounts, MySQL Remote Root, PostgreSQL Auth Methods, PostgreSQL Password Hashing, MongoDB Authorization, Redis Authentication
Network Isolation~12sDatabase Engines, MySQL Network Binding, PostgreSQL Network Binding, MongoDB Network Binding, Redis Network Binding, Exposed Database Ports, Web DB Admin Tools
Least-Privilege Permissions~12sMySQL Wildcard Hosts, MySQL FILE Privilege, MySQL File Access, MySQL Admin Accounts, PostgreSQL Superusers, PostgreSQL Allowed Hosts
Configuration & Hardening~19sService User, Default Databases, Database Patches, Transaction Log Placement, Database Backups, Backup File Permissions
Transport Encryption~11sMySQL TLS Enforcement, MySQL Certificate, PostgreSQL TLS, PostgreSQL Certificate, MongoDB TLS
Credential Storage~10sConfig Files In Web Root, Config File Permissions, Git In Web Root, Client Credential Files

Web Servers

Covers Nginx and Apache.

AuditApproxChecks it runs
Content Exposure~14sDirectory Listing, Hidden File Exposure, Backup Files, HTTP Methods, Status Endpoints, Default Pages
TLS Configuration~12sHTTPS Enabled, TLS Protocols, TLS Ciphers, Certificate Expiry, HTTPS Redirect, OCSP Stapling
Logging & Monitoring~12sAccess Logging, Error Logging, Log File Permissions, Log Rotation, Web Application Firewall
Configuration Hardening~11sConfig File Permissions, Web Root Ownership, Request Size Limits, Connection Timeouts, Rate Limiting, Unnecessary Modules
Security Headers~10sHSTS, Content Type Options, Frame Protection, Content Security Policy, Referrer Policy, Permissions Policy
Identification & Patching~9sWeb Server Inventory, Version Disclosure, Worker User, Web Server Updates, Config Syntax

Docker

AuditApproxChecks it runs
Image Vulnerabilities~16sImage Vulnerability Scan, Base Image Security, Image Secrets Scan, Image Configuration Review, Image Signature Verification, End-of-Life Base Image, Image Best Practices, Software Bill of Materials (SBOM)
Volume Permissions~13sSensitive Host Path Mounts, Volume Read/Write Access, World-Writable Volumes, Volume Ownership, Volume Permissions, Anonymous/Dangling Volumes, Read-Only Volume Enforcement
Daemon & Socket~12sDocker Inventory, Docker TCP Socket, Socket In Containers, Docker Group Members, Daemon Log Level, Rootless Mode
Network & Supply Chain~12sPort Publishing, Inter-Container Connectivity, Secrets In Env, Engine Updates, Image Hygiene
Container Hardening~10sPrivileged Containers, No New Privileges, Container User, Capabilities, Read-Only Filesystem, Sensitive Bind Mounts
Runtime & Resources~10sSeccomp Profile, MAC Confinement, Memory Limits, CPU Limits, PID Limits, Restart Policy

The scripts behind these audits are plain POSIX sh and detect the distribution and package manager themselves, so the same audit runs on Ubuntu, Debian, RHEL, Rocky, AlmaLinux, Amazon Linux, Fedora, Oracle Linux, SUSE, and Alpine without you picking a variant.

What the audit does not do

Owning the boundary is more useful than implying a wider one. Four things this is not:

It is not a vulnerability scanner. There is no CVE feed, no exploit testing, and it never probes hosts you do not already have SSH access to. It reads how a machine is configured. The Docker audit named Image Vulnerabilities checks image hygiene, such as base image age, mutable tags, embedded secrets, signature verification, and whether an SBOM exists, rather than querying a vulnerability database. For CVE scanning, use Trivy, Grype, or a commercial scanner.

It is not continuous monitoring. There is no schedule, no daemon, and no agent installed on the server. Every audit is a run you start, and nothing watches the box between runs. If you need continuous detection and alerting, that is a host intrusion detection system such as Wazuh or Falco.

It is not a compliance certification. The checks are not mapped to CIS Benchmark or STIG control identifiers, and the reports are not attested evidence for SOC 2, ISO 27001, PCI, or HIPAA. They are a hardening record: useful internally, useful to hand a client, not something an auditor will accept as a control matrix. For that path, use a compliance platform such as Vanta or Drata, or OpenSCAP with a certified SCAP profile.

It does not fix anything by itself. Findings become a prompt, the AI writes a command, and you approve it. There is no background remediation and no auto-apply.

Everything runs inside the SSH session you already opened. Nothing is installed on the server, no credential leaves your machine, and the report is written to your own disk. See SSH and Security for how the connection is handled, Access Management for auditing who can log in, which is a separate question from how the box is configured, or the Security Audit feature page for a shorter overview of what the module is for.

Tips

Run SSH & Access first on any server you have just inherited. It is fast, it needs the least privilege of the server audits, and root login plus password authentication left on is the single most common real finding.

Use the check picker rather than skipping an audit entirely. If a Database audit is mostly irrelevant because the box only runs Postgres, untick the MySQL, MongoDB, and Redis checks and you get a short, fully relevant run instead of a wall of skips.

Fix one finding at a time on your first pass through the AI loop. Reading a single approval card teaches you what the assistant does with an audit prompt, and batching is much less nerve-racking once you have seen it work.

Troubleshooting

Frequently Asked Questions

How do I run a security audit on a Linux server?

Connect the server in CtrlOps and click Audit in the left sidebar. Pick an audit from the catalog, click Generate, tick the checks you want to include, and click Continue. CtrlOps runs the checks over the SSH session you already have open, streams the log live, and hands you a report with a hardening score and a downloadable PDF. Nothing is installed on the server.

What does a CtrlOps security audit check?

There are 25 audits across four categories. Server audits cover SSH and access, firewall and network, system updates, file system permissions, services and processes, application security, and logging. Database audits cover authentication, network isolation, least-privilege permissions, transport encryption, credential storage, and configuration hardening for MySQL, PostgreSQL, MongoDB, and Redis. Docker audits cover container hardening, the daemon and socket, image hygiene, volume permissions, runtime limits, and network exposure. Web server audits cover security headers, TLS configuration, content exposure, configuration hardening, logging, and version disclosure.

Do I need root or sudo to run a security audit?

No. Audits run as the SSH user you connected with. Many checks read files that only root can open, and those checks report SKIP with the reason rather than guessing. The score card shows a coverage percentage so a partial run is never mistaken for a clean one. Connect as a user with sudo, or as root, to get full coverage.

Can I get a PDF security report to send to a client?

Yes. Every audit run produces a report you can download as a PDF from the download button at the top right of the result panel. It contains the hardening score, the severity breakdown, and every finding with its status and message. Past runs are kept under the Reports tab, so you can download an older one at any time.

Is CtrlOps Audit a vulnerability scanner?

No. It is a configuration audit. There is no CVE feed, no exploit testing, and it never probes hosts you do not have SSH access to. The Docker audit named Image Vulnerabilities checks image hygiene such as base image age, mutable tags, embedded secrets, and signature verification, rather than querying a vulnerability database. For CVE scanning use a dedicated scanner such as Trivy, Grype, or Nessus.

Does CtrlOps run security audits on a schedule?

No. There is no schedule, no daemon, and no agent on the server. Every audit is a run you start yourself, and nothing watches the server between runs. If you need continuous detection, that is a host intrusion detection system such as Wazuh or Falco.

Can I use CtrlOps audit reports for SOC 2, ISO 27001, or CIS compliance?

Not as attested evidence. The checks are not mapped to CIS Benchmark or STIG control identifiers and the reports are not audit evidence for a certification. They are a hardening record you can act on and hand to a client. For a certification path use a compliance platform such as Vanta or Drata, or OpenSCAP with a certified SCAP profile.

Does the AI fix security audit findings automatically?

No. Selecting findings and clicking Fix selected findings copies a prompt to your clipboard. You paste it into the AI Terminal, the assistant writes the command and explains why, and then it waits. Nothing runs on the server until you read the command and click Run. Findings are fixed one at a time with you approving each step.

Can I run the same audit on more than one server at once?

Yes. Open Audit Reports from the Home screen instead of the per-server Audit tab, click Generate on the audit you want, and the server picker lists every saved server with a checkbox. Select the servers and click Run on N servers. Each host is audited separately and gets its own report.