problem area

Cybersecurity Triage

Defensive commands for checking exposure, logs, permissions, and suspicious activity.

69 checked fixes

One-liners in this area

Cybersecurity Triage safe

Simulate Security Package Upgrades

Security patch triage starts by seeing what apt would change, without changing it.

apt-get -s upgrade | awk '/^Inst/ && /security/ {print}'
Cybersecurity Triage safe

Prove a Package Candidate Is From Security

The package name is not enough; the candidate repository tells the patch story.

apt-cache policy openssl | sed -n '/Installed:/p;/Candidate:/p;/security/p'
Cybersecurity Triage safe

Dry-Run Unattended Security Upgrades

Unattended upgrades can explain what they would patch before they patch it.

unattended-upgrade --dry-run --debug 2>&1 | sed -n '/Packages that will be upgraded:/,/^$/p'
Cybersecurity Triage safe

Build a Recent Apt Patch Timeline

Apt history turns patch claims into timestamps and package names.

awk '/^(Start-Date|Commandline|Upgrade|End-Date)/ {print}' /var/log/apt/history.log
Cybersecurity Triage safe

Find Warnings in Apt Terminal Logs

The package installed, but the terminal log may still contain the warning that matters.

grep -Ei 'warning|error|failed|dpkg' /var/log/apt/term.log
Cybersecurity Triage safe

Preview Security Impact of dist-upgrade

Kernel and dependency security fixes may only appear in the broader upgrade plan.

apt-get -s dist-upgrade | awk '/^Inst/ {print}'
Cybersecurity Triage safe

Check Whether Patches Require Reboot

Some security fixes are not complete until the host boots the new kernel or libraries.

test -f /var/run/reboot-required && printf 'reboot-required\n' && cat /var/run/reboot-required.pkgs
Cybersecurity Triage safe

Extract Environment Names Only

Audit environment labels without printing secret values.

grep -RhoE 'ENVIRONMENT|NODE_ENV|APP_ENV|RAILS_ENV' config deploy | sort -u
Cybersecurity Triage caution

Inspect Container Environment Names

Check what environment variables exist without printing their secret values.

docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' api | sed 's/=.*$/=/'
Cybersecurity Triage safe

Review Recent Docker Events

Docker keeps a recent event trail for starts, stops, pulls, and health changes.

docker events --since 30m --until 0s
Cybersecurity Triage safe

Read UFW Policy Verbosely

The firewall was active, but the defaults mattered more than the rule list.

ufw status verbose
Cybersecurity Triage safe

List Numbered UFW Rules

Numbered rules make firewall review less ambiguous.

ufw status numbered
Cybersecurity Triage safe

Show iptables INPUT Rules

Legacy firewall state can still explain live exposure.

iptables -S INPUT
Cybersecurity Triage safe

Show Publicly Bound Listeners

Localhost services are different from public listeners.

ss -ltnp | awk 'NR==1 || $4 ~ /^(0[.]0[.]0[.]0|[[]::[]]|[*]):/'
Cybersecurity Triage safe

Find Allowed Ports with No Listener

An open firewall rule can outlive the service it was created for.

comm -23 <(ufw status numbered | awk '/ALLOW/ {print}' | grep -Eo '[0-9]+/(tcp|udp)' | cut -d/ -f1 | sort -u) <(ss -ltnp | awk '/LISTEN/ {n=split($4,a,":"); print a[n]}' | sort -u)
Cybersecurity Triage safe

Find Public Listeners Not Allowed by UFW

The process was public, but the firewall did not mention it.

comm -13 <(ufw status numbered | awk '/ALLOW/ {print}' | grep -Eo '[0-9]+/(tcp|udp)' | cut -d/ -f1 | sort -u) <(ss -ltnp | awk '$4 ~ /^(0[.]0[.]0[.]0|[[]::[]]|[*]):/ {n=split($4,a,":"); print a[n]}' | sort -u)
Cybersecurity Triage safe

Check Whether SSH Is Publicly Bound

SSH can be locked down by source and still bind publicly.

ss -ltnp | awk '$4 ~ /:22$/ && $4 !~ /^127[.]/ {print}'
Cybersecurity Triage safe

Show Local-Only Database Listeners

The database was listening, but only on localhost.

ss -ltnp | awk '$4 ~ /^127[.]0[.]0[.]1:(5432|3306|6379)$/ {print}'
Cybersecurity Triage safe

Redact Secret-Looking Log Lines

Incident notes should not copy secrets forward.

grep -RInE '(password=|token=|secret=|Authorization: Bearer)' fixtures/incidents | awk '{gsub(/password=[^ ]+/, "password=REDACTED"); gsub(/token=[^ ]+/, "token=REDACTED"); gsub(/secret=[^ ]+/, "secret=REDACTED"); gsub(/Authorization: Bearer [A-Za-z0-9._-]+/, "Authorization: Bearer REDACTED"); print}'
Cybersecurity Triage safe

Find Writable Directories Missing the Sticky Bit

A writable log directory is not the same thing as a safe shared directory.

find fixtures/perm-audit -type d -perm -0002 ! -perm -1000 -printf '%m %u:%g %p\n' | sort
Cybersecurity Triage safe

Find World-Readable Secret-Looking Files

The fastest secret audit starts with readable files that look like secrets.

find fixtures/perm-audit -type f -perm -0004 \( -iname '*secret*' -o -iname '*.env' -o -iname '*token*' -o -iname '*key*' \) -printf '%M %u:%g %p\n' | sort
Cybersecurity Triage safe

Find Config Files with Execute Bits

Config files do not usually need to be executable.

find fixtures/perm-audit -type f -perm /111 \( -path '*/config/*' -o -name '*.env' -o -name '*.conf' \) -printf '%M %u:%g %p\n' | sort
Cybersecurity Triage safe

Find Upload Files Writable Outside the Owner

Uploads are supposed to be writable at the edge, not writable forever by everyone.

find fixtures/perm-audit/releases/2026-06-25/uploads -type f -perm /0022 -printf '%M %u:%g %p\n' | sort
Cybersecurity Triage safe

Find Listening Ports with ss

Before blaming the firewall, check whether anything is actually listening.

ss -ltnp
Cybersecurity Triage safe

Summarize SSH Auth Outcomes

SSH logs get easier to read once accepted and failed methods are counted.

awk '/sshd/ && /Accepted/ {print "accepted", $7} /sshd/ && /Failed password/ {print "failed", "password"} /sshd/ && /Failed publickey/ {print "failed", "publickey"}' logs/auth.log | sort | uniq -c | sort -nr
Cybersecurity Triage safe

Find SSH Password Auth Exceptions

A global password-auth setting can be changed later by a Match block.

awk '/^Match /{ctx=$0} /^PasswordAuthentication|^AuthenticationMethods|^[[:space:]]+PasswordAuthentication|^[[:space:]]+AuthenticationMethods/ {print (ctx ? ctx : "global") ": " $0}' etc/ssh/sshd_config
Cybersecurity Triage safe

List SSH Allow and Deny Rules

SSH access can be shaped by users, groups, and Match blocks.

grep -RhnE '^(AllowUsers|AllowGroups|DenyUsers|DenyGroups|Match )' etc/ssh
Cybersecurity Triage safe

Inventory SSH authorized_keys

authorized_keys files are the practical list of who can use key-based SSH.

find home -path '*/.ssh/authorized_keys' -exec awk '{print FILENAME, $1, $NF}' {} +
Cybersecurity Triage safe

List Accepted SSH Login Sources

Successful SSH logins are the access events worth anchoring first.

awk '/Accepted publickey/ {print $1, $2, $3, $9, $11}' logs/auth.log
Cybersecurity Triage safe

Show Failed SSH Public-Key Users

A failed public-key attempt often points to stale keys or the wrong account.

awk '/Failed publickey/ {print $9, $11}' logs/auth.log | sort | uniq -c | sort -nr
Cybersecurity Triage safe

Summarize SSH Authorized Key Types

Key inventory gets more useful when old key types stand out.

find home -path '*/.ssh/authorized_keys' -exec awk '{print $1}' {} + | sort | uniq -c | sort -nr
Cybersecurity Triage safe

Find Loose authorized_keys Modes

SSH key access files should not be looser than intended.

find home -path '*/.ssh/authorized_keys' -printf '%m %p\n' | awk '$1 > 600'
Cybersecurity Triage safe

Show SSH Auth Policy Order

The order of Include, Match, and authentication directives changes how SSH policy reads.

grep -nE '^(Include|Match |PubkeyAuthentication|PasswordAuthentication|AuthenticationMethods|[[:space:]]+(PasswordAuthentication|AuthenticationMethods))' etc/ssh/sshd_config
Cybersecurity Triage safe

Extract SSH AllowUsers Accounts

AllowUsers turns SSH access into an explicit account list.

awk '/^AllowUsers/ {for (i = 2; i <= NF; i++) print $i}' etc/ssh/sshd_config
Cybersecurity Triage safe

List Accounts with Login Shells

Login shells are the first account inventory to review.

awk -F: '$7 ~ /(bash|sh|zsh)$/ {printf "%s %s\n", $1, $7}' fixtures/user-access-audit/etc/passwd
Cybersecurity Triage safe

Find Password-Enabled Accounts

A shell account with an unlocked password hash deserves extra attention.

awk -F: '$2 !~ /^(!|\*)/ {print $1}' fixtures/user-access-audit/etc/shadow
Cybersecurity Triage safe

Review sudo Grants

Privilege paths should be visible before you remove or approve access.

awk -F: '$1=="sudo" {print "sudo group: " $4}' fixtures/user-access-audit/etc/group; grep -RhnE '^[^#].*ALL=' fixtures/user-access-audit/etc/sudoers fixtures/user-access-audit/etc/sudoers.d
Cybersecurity Triage safe

Count authorized_keys by User

authorized_keys is the practical SSH access list.

find fixtures/user-access-audit/home -path '*/.ssh/authorized_keys' -exec sh -c 'for f do user=$(basename "$(dirname "$(dirname "$f")")"); keys=$(grep -vc "^[[:space:]]*#" "$f"); printf "%s %s %s\n" "$user" "$keys" "$f"; done' sh {} + | sort
Cybersecurity Triage safe

Find SSH Keys for nologin Users

A nologin shell does not automatically mean SSH keys are irrelevant.

comm -12 <(awk -F: '$7 !~ /(bash|sh|zsh)$/ {print $1}' fixtures/user-access-audit/etc/passwd | sort) <(find fixtures/user-access-audit/home -path '*/.ssh/authorized_keys' -printf '%h\n' | awk -F/ '{print $(NF-1)}' | sort)
Cybersecurity Triage safe

Show Successful Logins and sudo Use

Access reviews need both who logged in and who elevated privileges.

grep -E 'Accepted publickey|sudo:' fixtures/user-access-audit/logs/auth.log
Cybersecurity Triage safe

List Privileged Group Members

Group membership can grant more access than the username suggests.

awk -F: '$1 ~ /^(sudo|adm|docker)$/ && $4 != "" {print $1 ": " $4}' fixtures/user-access-audit/etc/group
Cybersecurity Triage safe

Summarize sudo Commands by User

Privilege history is easier to review when users and commands are separated.

sed -n 's/.*sudo: *\([^: ]*\).*COMMAND=\(.*\)$/\1 -> \2/p' fixtures/user-access-audit/logs/auth.log | sort
Cybersecurity Triage safe

Review a Breakglass Account

Emergency accounts should be easy to find and hard to ignore.

grep -Rhn 'breakglass' fixtures/user-access-audit/etc fixtures/user-access-audit/home fixtures/user-access-audit/logs
Cybersecurity Triage safe

Find SSH Key Users with sudo

The highest-priority access review starts where SSH keys and sudo overlap.

comm -12 <(find fixtures/user-access-audit/home -path '*/.ssh/authorized_keys' -printf '%h\n' | awk -F/ '{print $(NF-1)}' | sort) <(awk -F: '$1=="sudo" {gsub(",","\n",$4); print $4}' fixtures/user-access-audit/etc/group | sort)
Cybersecurity Triage safe

Count Failed SSH Login Users

Failed SSH attempts are noisy; grouping users makes the pattern readable.

sed -n 's/.*Failed password for \(invalid user \)\?\([^ ]*\) from .*/\2/p' logs/auth.log | sort | uniq -c | sort -nr
Cybersecurity Triage safe

Count Failed SSH Login IPs

The loudest SSH source is usually visible with one count.

sed -n 's/.*Failed password .* from \([0-9.]*\) port.*/\1/p' logs/auth.log | sort | uniq -c | sort -nr
Cybersecurity Triage safe

Show Accepted SSH Logins

During first response, successful logins matter more than background noise.

grep 'Accepted publickey' logs/auth.log
Cybersecurity Triage safe

Show Recent sudo Commands

Privilege use is one of the fastest first-response signals.

grep 'sudo:' logs/auth.log | tail -n 10
Cybersecurity Triage safe

List Users with Login Shells

Not every local account should be able to log in.

awk -F: '$7 ~ /sh$/ {print $1, $7}' etc/passwd
Cybersecurity Triage safe

Check Key SSH Authentication Settings

SSH policy should be visible before you change it.

grep -nE '^(PasswordAuthentication|PermitRootLogin|PubkeyAuthentication|AllowUsers)' etc/ssh/sshd_config
Cybersecurity Triage safe

Find Loose Private Key Permissions

SSH private keys should not be readable like ordinary files.

find home -type f -name 'id_*' -printf '%m %p\n' | awk '$1 > 600'
Cybersecurity Triage safe

List authorized_keys Files

Authorized keys are the server's practical access list.

find home -path '*/.ssh/authorized_keys' -printf '%m %p\n'
Cybersecurity Triage safe

Find the IPs Creating the Most 4xx Noise

One address can turn a normal access log into a wall of failed requests.

awk '$9 ~ /^4/ {count[$1]++} END {for (ip in count) print count[ip], ip}' ./fixtures/nginx/access.log | sort -nr | head
Cybersecurity Triage safe

Spot Unusual HTTP Methods in Access Logs

Most site traffic is boring. The weird methods are worth a look.

awk '$6 !~ /^"(GET|POST|HEAD|OPTIONS)$/ {print $1, $6, $7, $9}' ./fixtures/nginx/access.log | sort | uniq -c | sort -nr
Cybersecurity Triage safe

Count the Most Common User Agents

A strange traffic spike often has a strange user agent.

awk -F'"' '{print $6}' ./fixtures/nginx/access.log | sort | uniq -c | sort -nr | head
Cybersecurity Triage safe

Find Common Admin Probe Paths

A site does not need WordPress to receive WordPress-looking probes.

awk '$7 ~ /(admin|login|wp-|phpmyadmin)/ {print $1, $7, $9}' ./fixtures/nginx/access.log | sort | uniq -c | sort -nr | head
Cybersecurity Triage safe

Find Paths Repeatedly Returning 404

One missing URL is normal. A repeated missing URL is a signal.

awk '$9==404 {count[$7]++} END {for (path in count) if (count[path] >= 3) print count[path], path}' ./fixtures/nginx/access.log | sort -nr | head
Cybersecurity Triage safe

Spot Request Bursts by Minute

Traffic spikes are easier to read when you bucket them by time.

awk '{minute=substr($4,2,17); count[minute]++} END {for (m in count) print count[m], m}' ./fixtures/nginx/access.log | sort -nr | head
Cybersecurity Triage safe

Find Clients Repeating the Same Path

The suspicious pattern is sometimes one client hammering one URL.

awk '{key=$1 " " $7; count[key]++} END {for (k in count) if (count[k] >= 5) print count[k], k}' ./fixtures/nginx/access.log | sort -nr | head