What this protects, and what it doesn't
Protects
- Gives you a quick, honest picture of settings that are easy to forget: disk encryption, the firewall, automatic updates, screen lock, remote access and telemetry.
- Reads only. Every line is a status query, so you can run it on a machine you own without changing its configuration.
- Is short enough to read in full before running, so you are never asked to trust a black box.
Does not protect
- Reading a setting is not the same as being secure. The script tells you what is configured; acting on the warnings is still up to you.
- It is not a full audit. It checks common, high-value settings, not every control in a hardening benchmark such as the CIS Benchmarks.
- It changes nothing and fixes nothing by design. It will not turn on encryption or a firewall for you.
- The Windows script is provided as-is for you to read and run on your own machine; treat any script from the internet that way, and run it yourself rather than trusting a result pasted by someone else.
Prerequisites
- A computer you own and administer. Do not run posture checks on machines you do not control.
- On Linux: a terminal. On Windows: the built-in Windows PowerShell (or PowerShell 7+).
- Optional: run it in an elevated / sudo session to let a few checks read more detail. It works without.
Step by step
-
What these scripts do, and do not do
Each script walks through a short list of privacy and security settings and prints, for every one, whether it looks fine (
[ OK ]), is worth reviewing ([WARN]), or could not be read on this machine ([ -- ]). Nothing is uploaded, and no setting is written: the scripts use only read commands (lsblk,ss,Get-BitLockerVolume, registry reads and the like).Read the whole script before you run it — it is deliberately short and commented so you can. The idea is borrowed from configuration-hardening baselines such as the CIS Benchmarks, Microsoft's security baselines and Ubuntu's Security Guide, reduced to the handful of checks that matter most for an individual. For a full audit, use those benchmarks themselves (linked under Sources).
-
Linux: privacy-check.sh
Save the following as
privacy-check.shand run it withbash privacy-check.sh. It checks disk encryption (LUKS), the host firewall, listening network services, Secure Boot, automatic security updates, the GNOME screen lock, the SSH daemon, shell history and crash-report telemetry.#!/usr/bin/env bash # # ============================================================================= # privacy-check.sh - a READ-ONLY privacy & security posture check for Linux # ============================================================================= # # WHAT IT DOES # Looks at a handful of important privacy/security settings on this machine # and prints, for each one, whether it looks OK or deserves attention. # # WHAT IT DOES NOT DO # It changes NOTHING. It writes no settings, deletes no files, installs # nothing, and sends nothing over the network. Every command below only # READS state. You can read the whole script top to bottom before running # it - there are no surprises. # # HOW TO RUN # bash privacy-check.sh # A few checks can see more detail if you run it with sudo, but it works # fine without. When a value cannot be read, the check says so ([ -- ]). # # HOW TO READ THE OUTPUT # [ OK ] = this looks fine # [WARN] = worth reviewing; the line explains why # [ -- ] = could not determine (tool missing, or needs sudo) # ============================================================================= set -u # treat use of an unset variable as an error LANG=C # stable, English output regardless of system locale # --- tiny helpers so the checks below stay readable ------------------------- ok() { printf ' [ OK ] %s\n' "$1"; } # print an "OK" line warn() { printf ' [WARN] %s\n' "$1"; } # print a "needs attention" line na() { printf ' [ -- ] %s\n' "$1"; } # print a "could not determine" line have() { command -v "$1" >/dev/null 2>&1; } # is a command available? echo "== Linux privacy posture (read-only) ==" echo " $(date -u '+%Y-%m-%d %H:%M UTC') host: $(hostname 2>/dev/null || echo '?')" echo # ----------------------------------------------------------------------------- # 1. Disk encryption # If the disk is not encrypted, anyone who takes the machine or the drive # can read your files. We look for a LUKS-encrypted volume. # ----------------------------------------------------------------------------- echo "Disk encryption" if have lsblk && lsblk -o FSTYPE 2>/dev/null | grep -qi crypto_LUKS; then ok "A LUKS-encrypted volume is present." else warn "No LUKS volume detected. If this disk is unencrypted, its data is readable if the machine is lost or seized." fi # ----------------------------------------------------------------------------- # 2. Host firewall # A firewall limits which network services strangers can reach. We check the # four common Linux firewall front-ends, in order. # ----------------------------------------------------------------------------- echo echo "Firewall" if have ufw && ufw status 2>/dev/null | grep -qi "Status: active"; then ok "ufw is active." elif have firewall-cmd && firewall-cmd --state 2>/dev/null | grep -qi running; then ok "firewalld is running." elif have nft && [ -n "$(nft list ruleset 2>/dev/null)" ]; then ok "nftables has a ruleset loaded." elif have iptables && iptables -S 2>/dev/null | grep -qvE '^-P (INPUT|FORWARD|OUTPUT) ACCEPT$'; then ok "iptables has non-default rules." else warn "No active host firewall detected (ufw / firewalld / nftables / iptables)." fi # ----------------------------------------------------------------------------- # 3. Listening network services # Every program listening on a port is something the outside (or your LAN) # could try to reach. We just list them so you can spot anything unexpected. # ----------------------------------------------------------------------------- echo echo "Listening network services" if have ss; then # -t TCP, -u UDP, -l listening only, -n numeric, -H no header row count=$(ss -tulnH 2>/dev/null | wc -l) ss -tulnH 2>/dev/null | awk '{print $1, $5}' | sort -u | sed 's/^/ /' if [ "$count" -gt 0 ]; then na "$count listening socket(s) above. Each is reachable by something; close what you do not need." fi else na "ss not available; cannot list listening ports." fi # ----------------------------------------------------------------------------- # 4. Secure Boot # Secure Boot helps stop tampered boot code from running. mokutil reports # whether it is enabled (only meaningful on UEFI systems). # ----------------------------------------------------------------------------- echo echo "Secure Boot" if have mokutil; then if mokutil --sb-state 2>/dev/null | grep -qi "enabled"; then ok "Secure Boot is enabled." else warn "Secure Boot is not enabled." fi else na "mokutil not installed; cannot read Secure Boot state." fi # ----------------------------------------------------------------------------- # 5. Automatic security updates # Unpatched software is the most common way machines get compromised. We # check whether an automatic-update service is switched on. # ----------------------------------------------------------------------------- echo echo "Automatic security updates" if have systemctl && systemctl is-enabled --quiet unattended-upgrades 2>/dev/null; then ok "unattended-upgrades is enabled (Debian/Ubuntu)." elif have systemctl && systemctl is-enabled --quiet dnf-automatic.timer 2>/dev/null; then ok "dnf-automatic.timer is enabled (Fedora/RHEL)." else warn "No automatic-update service detected. Apply security updates promptly." fi # ----------------------------------------------------------------------------- # 6. Screen lock (GNOME desktop, current user) # An unlocked screen is physical access to everything. We read the GNOME # setting for "lock on wake" and the idle timeout. (Only works on GNOME.) # ----------------------------------------------------------------------------- echo echo "Screen lock (GNOME, current user)" if have gsettings; then lock=$(gsettings get org.gnome.desktop.screensaver lock-enabled 2>/dev/null) delay=$(gsettings get org.gnome.desktop.session idle-delay 2>/dev/null | awk '{print $NF}') if [ "$lock" = "true" ]; then ok "Screen lock on wake is enabled (idle-delay: ${delay:-?} s)." elif [ -n "$lock" ]; then warn "Screen lock on wake is disabled." else na "Could not read GNOME screensaver settings." fi else na "gsettings not available (not GNOME, or headless)." fi # ----------------------------------------------------------------------------- # 7. SSH daemon # If an SSH server is running, password login is a common break-in route. # We check whether anything listens on port 22 and, if so, whether password # authentication is turned off (keys only is the safer setting). # ----------------------------------------------------------------------------- echo echo "SSH daemon" if have ss && ss -tlnH 2>/dev/null | grep -qE ':22\b'; then pw="?" if [ -r /etc/ssh/sshd_config ]; then # take the last PasswordAuthentication line, lower-cased pw=$(awk 'tolower($1)=="passwordauthentication"{print tolower($2)}' /etc/ssh/sshd_config | tail -1) fi case "$pw" in no) ok "sshd is listening; password auth is disabled (keys only).";; yes) warn "sshd is listening with password authentication enabled. Prefer keys only.";; *) na "sshd is listening; could not read PasswordAuthentication (try with sudo).";; esac else ok "No SSH server listening on :22." fi # ----------------------------------------------------------------------------- # 8. Shell history # Your shell records the commands you type. This is normal and useful; we # only report its state and remind you how to clear it yourself if you want. # ----------------------------------------------------------------------------- echo echo "Shell history" if [ "${HISTFILE:-}" = "/dev/null" ] || [ "${HISTSIZE:-x}" = "0" ]; then ok "Shell history is disabled for this session." else na "Shell history is on (normal). To clear it yourself: history -c (and edit ~/.bash_history)." fi # ----------------------------------------------------------------------------- # 9. Telemetry / crash reporting # Some distributions send crash reports upstream. We check for Ubuntu's # "whoopsie" crash-reporting service as the common example. # ----------------------------------------------------------------------------- echo echo "Telemetry / crash reporting" if have systemctl && systemctl is-enabled --quiet whoopsie 2>/dev/null; then warn "whoopsie (Ubuntu crash reporting) is enabled." else ok "No whoopsie crash-reporting service enabled." fi echo echo "== End of report. Nothing was changed. ==" -
Windows: privacy-check.ps1
Save the following as
privacy-check.ps1and run it withpowershell -ExecutionPolicy Bypass -File .\privacy-check.ps1. It checks BitLocker disk encryption, the Windows Firewall, Microsoft Defender, the diagnostic-data (telemetry) level, activity-history upload, Remote Desktop, SmartScreen, local administrator accounts and the screen-saver lock.<# ============================================================================= privacy-check.ps1 - a READ-ONLY privacy & security posture check for Windows ============================================================================= WHAT IT DOES Looks at a handful of important privacy/security settings on this PC and prints, for each one, whether it looks OK or deserves attention. WHAT IT DOES NOT DO It changes NOTHING. Every command below is a "Get-" or a registry READ. It writes no settings, deletes no files, installs nothing, and sends nothing over the network. You can read the whole script before running it. HOW TO RUN Open PowerShell and run: powershell -ExecutionPolicy Bypass -File .\privacy-check.ps1 (or, on PowerShell 7+: pwsh -File .\privacy-check.ps1) Some checks show more detail in an elevated (Administrator) window, but it runs fine without. When a value cannot be read, the check says so. HOW TO READ THE OUTPUT [ OK ] = this looks fine [WARN] = worth reviewing; the line explains why [ -- ] = could not determine (needs elevation, or not available here) ============================================================================= #> # Do not stop on the first error; a missing cmdlet should just mean "could not # determine", not a crash. Each check handles its own absence. $ErrorActionPreference = 'SilentlyContinue' # --- tiny helpers so the checks below stay readable -------------------------- function Write-Ok ($m) { Write-Host " [ OK ] $m" } # this looks fine function Write-Warn ($m) { Write-Host " [WARN] $m" } # worth reviewing function Write-Na ($m) { Write-Host " [ -- ] $m" } # could not determine Write-Host "== Windows privacy posture (read-only) ==" Write-Host (" {0} host: {1}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm'), $env:COMPUTERNAME) Write-Host "" # ----------------------------------------------------------------------------- # 1. Disk encryption (BitLocker) # If the system drive is not encrypted, anyone who takes the PC or the disk # can read your files. We ask BitLocker about the operating-system drive. # ----------------------------------------------------------------------------- Write-Host "Disk encryption (BitLocker)" $bitlocker = Get-BitLockerVolume -ErrorAction SilentlyContinue if ($bitlocker) { $systemDrive = $bitlocker | Where-Object { $_.VolumeType -eq 'OperatingSystem' } | Select-Object -First 1 if ($systemDrive -and $systemDrive.ProtectionStatus -eq 'On') { Write-Ok ("System drive {0} is encrypted ({1})." -f $systemDrive.MountPoint, $systemDrive.EncryptionMethod) } else { Write-Warn "The system drive is not BitLocker-protected. Its data is readable if the PC is lost or seized." } } else { Write-Na "Could not read BitLocker status (needs an elevated window, or this Windows edition has no BitLocker)." } Write-Host "" # ----------------------------------------------------------------------------- # 2. Firewall # The firewall limits which network services strangers can reach. Windows # has three profiles (Domain, Private, Public); all three should be on. # ----------------------------------------------------------------------------- Write-Host "Firewall" $firewallProfiles = Get-NetFirewallProfile -ErrorAction SilentlyContinue if ($firewallProfiles) { $disabled = $firewallProfiles | Where-Object { -not $_.Enabled } if ($disabled) { Write-Warn ("Firewall is OFF for profile(s): {0}." -f (($disabled.Name) -join ', ')) } else { Write-Ok "Windows Firewall is enabled for all profiles (Domain, Private, Public)." } } else { Write-Na "Could not read firewall profiles." } Write-Host "" # ----------------------------------------------------------------------------- # 3. Antivirus (Microsoft Defender) # Real-time protection catches most commodity malware. If you run a third- # party antivirus instead, Defender may report itself off - that is expected. # ----------------------------------------------------------------------------- Write-Host "Antivirus (Microsoft Defender)" $defender = Get-MpComputerStatus -ErrorAction SilentlyContinue if ($defender) { if ($defender.RealTimeProtectionEnabled) { Write-Ok ("Real-time protection is on; signatures from {0}." -f $defender.AntivirusSignatureLastUpdated) } else { Write-Warn "Defender real-time protection is OFF (another antivirus may be installed instead)." } } else { Write-Na "Could not read Defender status (third-party antivirus, or needs elevation)." } Write-Host "" # ----------------------------------------------------------------------------- # 4. Diagnostic data (telemetry) level # Windows sends diagnostic data to Microsoft. A policy value of 0 or 1 is # the most private; higher values send more. (Reads a policy registry key.) # ----------------------------------------------------------------------------- Write-Host "Diagnostic data (telemetry) level" $telemetryKey = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\DataCollection' $telemetryLevel = (Get-ItemProperty -Path $telemetryKey -Name 'AllowTelemetry' -ErrorAction SilentlyContinue).AllowTelemetry if ($null -ne $telemetryLevel) { $levelName = @{ 0 = 'Security (lowest)'; 1 = 'Required/Basic'; 2 = 'Enhanced'; 3 = 'Full' }[[int]$telemetryLevel] if ([int]$telemetryLevel -le 1) { Write-Ok ("Telemetry policy set to {0}." -f $levelName) } else { Write-Warn ("Telemetry policy set to {0}. Consider lowering it." -f $levelName) } } else { Write-Na "No telemetry policy set (Windows default applies; Home edition cannot set the lowest level)." } Write-Host "" # ----------------------------------------------------------------------------- # 5. Activity history uploaded to Microsoft # Windows can send your "activity history" (apps and files you used) to your # Microsoft account. We check the policy that controls uploading it. # ----------------------------------------------------------------------------- Write-Host "Activity history sent to Microsoft" $activityKey = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\System' $published = (Get-ItemProperty -Path $activityKey -Name 'PublishUserActivities' -ErrorAction SilentlyContinue).PublishUserActivities $uploaded = (Get-ItemProperty -Path $activityKey -Name 'UploadUserActivities' -ErrorAction SilentlyContinue).UploadUserActivities if ($uploaded -eq 0) { Write-Ok "Uploading activity history to Microsoft is disabled by policy." } elseif ($null -ne $published) { Write-Warn "Activity history collection is enabled. Review Settings > Privacy & security > Activity history." } else { Write-Na "No activity-history policy set; check Settings > Privacy & security > Activity history." } Write-Host "" # ----------------------------------------------------------------------------- # 6. Remote Desktop (RDP) # RDP lets someone log in over the network. Leave it off unless you need it, # and never expose it directly to the internet. (Reads one registry value.) # ----------------------------------------------------------------------------- Write-Host "Remote Desktop (RDP)" $rdpDenied = (Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -Name 'fDenyTSConnections' -ErrorAction SilentlyContinue).fDenyTSConnections if ($rdpDenied -eq 1) { Write-Ok "Remote Desktop is disabled." } elseif ($rdpDenied -eq 0) { Write-Warn "Remote Desktop is ENABLED. Disable it unless you need it, and never expose it to the internet." } else { Write-Na "Could not read the Remote Desktop setting." } Write-Host "" # ----------------------------------------------------------------------------- # 7. SmartScreen # SmartScreen warns before running unrecognised downloads. "Off" means that # safety net is gone. (Reads one registry value.) # ----------------------------------------------------------------------------- Write-Host "SmartScreen" $smartScreen = (Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer' -Name 'SmartScreenEnabled' -ErrorAction SilentlyContinue).SmartScreenEnabled if ($smartScreen -and $smartScreen -ne 'Off') { Write-Ok ("SmartScreen is on ({0})." -f $smartScreen) } elseif ($smartScreen -eq 'Off') { Write-Warn "SmartScreen is Off." } else { Write-Na "Could not read SmartScreen state." } Write-Host "" # ----------------------------------------------------------------------------- # 8. Local administrator accounts # Day-to-day work is safer in a standard (non-admin) account, so malware you # run cannot immediately take over the machine. We list the admins to review. # ----------------------------------------------------------------------------- Write-Host "Local administrator accounts" $admins = Get-LocalGroupMember -Group 'Administrators' -ErrorAction SilentlyContinue if ($admins) { Write-Na ("Members of Administrators: {0}. Use a standard account for daily work." -f (($admins.Name) -join ', ')) } else { Write-Na "Could not enumerate local administrators (domain account, or needs elevation)." } Write-Host "" # ----------------------------------------------------------------------------- # 9. Screen saver lock # A password-protected screen saver re-locks the PC when you step away. # (Win+L locks immediately at any time.) Reads two per-user registry values. # ----------------------------------------------------------------------------- Write-Host "Screen saver lock" $desktopKey = 'HKCU:\Control Panel\Desktop' $saverActive = (Get-ItemProperty -Path $desktopKey -Name 'ScreenSaveActive' -ErrorAction SilentlyContinue).ScreenSaveActive $saverIsSecure = (Get-ItemProperty -Path $desktopKey -Name 'ScreenSaverIsSecure' -ErrorAction SilentlyContinue).ScreenSaverIsSecure if ($saverActive -eq '1' -and $saverIsSecure -eq '1') { Write-Ok "A password-protected screen saver is enabled." } else { Write-Warn "No password-protected screen saver set. Set a short lock timeout (Win+L locks now)." } Write-Host "" Write-Host "== End of report. Nothing was changed. ==" -
What to do with the warnings
A
[WARN]is a prompt to look, not proof of a problem — some settings are off for good reason on your machine. Work through them in rough order of impact:- Disk encryption off is usually the most important to fix. See Full-disk encryption.
- No firewall, or Remote Desktop / SSH exposed: close what you do not use, and never expose remote access directly to the internet. See Securing your home network.
- No automatic updates: turn them on; unpatched software is the most common way machines are compromised.
- Weak or absent screen lock: on a laptop this is what stands between a lost device and your data.
Re-run the script after you make changes to confirm the result moved from
[WARN]to[ OK ].
Your ticks are saved in this browser only (see or delete local data).
Common mistakes
- Running a posture or hardening script on a computer you do not own or administer.
- Treating an all-OK result as "I am secure". These are a handful of checks, not a full audit.
- Pasting someone else's script output and assuming it reflects your machine — run the read-only check yourself.
- Seeing a warning and disabling the feature (for example turning off Location entirely) in a way that breaks something useful like finding a lost device.
- Running an unfamiliar script without reading it first. These are short on purpose so you can.
Going further
These checks are a starting point, not a benchmark. For a thorough, standardised audit of a system, use the CIS Benchmarks for your operating system, Microsoft's security baselines on Windows, or Ubuntu's Security Guide (USG) on Ubuntu, all linked below. On a Medium or High threat model, pair the fixes with the encryption, accounts and browsing guides here, and remember that a configuration check only reports the state of the machine — it cannot tell you whether the machine is already compromised.