← Privacy Guides

Devices & OS

Check your privacy settings with a read-only script

Two short scripts, one for Linux and one for Windows, that report how a handful of important privacy and security settings are configured on your own computer. They only read and report: they change nothing, install nothing and send nothing anywhere.

  • Low threat
  • Time 15 minutes
  • Difficulty Easy
  • Last verified

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

  1. 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).

  2. Linux: privacy-check.sh

    Save the following as privacy-check.sh and run it with bash 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. =="
    
  3. Windows: privacy-check.ps1

    Save the following as privacy-check.ps1 and run it with powershell -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. =="
    
  4. 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 ].

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.