Linux Privacy Hardening Guide: Essential Terminal Commands & Settings
Linux Privacy Hardening Guide: Essential Terminal Commands & Settings
The Myth of "Default Privacy" in Enterprise Linux
In my decade of conducting incident response and security audits, I've lost count of the times a client has told me, "We use Linux, so our data is private by default." This is a dangerous fallacy. While Linux doesn't inherently harvest user data for advertising like some commercial operating systems, default configurations are optimized for usability and debugging, not privacy.
From a threat modeling perspective, privacy and security are deeply intertwined. If an adversary achieves local access, the default Linux configuration leaves a massive forensic footprint. In the MITRE ATT&CK framework, techniques like T1005 (Data from Local System) and T1552 (Unsecured Credentials) rely heavily on the default permissive logging, shell history, and process visibility inherent in standard Linux deployments.
This guide provides the exact terminal commands and configuration settings I use to harden Linux environments against local forensic analysis, network snooping, and data leakage, aligning with NIST SP 800-53 (AU-9 Protection of Audit Information) and ISO 27001 (A.8.24 Use of Cryptography) controls.
Phase 1: Eradicating Shell History and Command Footprints
The Bash history file (~/.bash_history) is a goldmine for attackers. I've seen penetration testers pivot to root simply by reading a user's command history to find plaintext passwords passed as CLI arguments.
Configuring HISTCONTROL and HISTSIZE
By default, Bash records every command. We need to configure it to ignore duplicates, ignore commands preceded by a space, and limit the overall size.
# Append to ~/.bashrc for the specific user
export HISTCONTROL=ignoreboth:erasedups
export HISTSIZE=500
export HISTFILESIZE=500
# Note: "ignoreboth" already combines "ignorespace" (skip commands prefixed
# with a space) and "ignoredups" (skip immediate duplicate entries).
# Any command you type with a leading space will now be excluded from
# history automatically -- no extra shopt flag is needed for this purpose.
Disabling History for Specific Sensitive Sessions
If I am running a script that handles cryptographic keys or database credentials, I don't rely on the space-prefix trick. I disable history entirely for that specific terminal session.
# Unset the history file for the current session
unset HISTFILE
# Alternatively, set it to /dev/null
export HISTFILE=/dev/null
Actionable Takeaway: Train your engineering teams to never pass secrets as CLI arguments. Use environment variables or standard input instead, as environment variables of child processes are harder to harvest post-mortem than shell history.
Correction note: The original draft referenced shopt -s histverify as a way to hide sensitive input. That is incorrect — histverify only affects how Bash's history-expansion syntax (e.g. !!, !123) is displayed before execution and has no bearing on privacy or hiding commands. It has been removed above.
Phase 2: Securing Data at Rest and Forensic Wiping
When a user deletes a file in Linux, the filesystem merely unlinks the inode. The actual data remains on the disk until overwritten. If a laptop is seized, forensic tools like photorec or sleuthkit will easily recover "deleted" sensitive documents.
Secure Deletion with shred and wipe
For mechanical hard drives (HDDs), overwriting the file data is highly effective. I use shred for individual files and wipe for entire directory trees.
# Overwrite a specific file 3 times with random data, then zero it, and finally delete it
shred -vfz -n 3 /path/to/sensitive_document.pdf
# For recursive directory wiping (requires the 'wipe' package)
wipe -r -f /path/to/sensitive_directory/
SSD Realities: blkdiscard and TRIM
In my experience, shred is largely ineffective on modern Solid State Drives (SSDs) due to wear-leveling algorithms; the SSD controller moves data around, meaning the original physical blocks are never actually overwritten. For SSDs, privacy relies on hardware-level commands.
# WARNING: blkdiscard erases the ENTIRE target partition/device, not a
# single file. Double-check the device path before running this.
sudo blkdiscard /dev/nvme0n1p2
# Ensure continuous TRIM is enabled for ongoing privacy of deleted blocks
sudo systemctl enable fstrim.timer
sudo systemctl start fstrim.timer
Phase 3: Network Privacy and DNS Hardening
Network privacy is about preventing local network adversaries and ISPs from observing your DNS queries and masking your hardware identity. Default Linux configurations often use plaintext DNS, which is trivial to intercept (MITRE ATT&CK T1040 Network Sniffing).
Enforcing DNS over TLS (DoT) via systemd-resolved
Instead of installing third-party DNS proxies, I leverage the native systemd-resolved daemon to enforce encrypted DNS. This aligns with NIST SP 800-53 (SC-8 Transmission Confidentiality).
# Edit the resolved configuration
sudo nano /etc/systemd/resolved.conf
Add or modify the following lines:
[Resolve]
DNS=1.1.1.1 9.9.9.9
DNSOverTLS=yes
DNSSEC=allow-downgrade
Correction note: DNSSEC=allow-downgrade is the pragmatic default for broad compatibility, but it permits a downgrade attack if an adversary can strip DNSSEC signaling. For environments where every upstream resolver is confirmed DNSSEC-capable, set DNSSEC=yes for strict enforcement instead.
# Restart the service to apply
sudo systemctl restart systemd-resolved
MAC Address Randomization in NetworkManager
When connecting to public Wi-Fi, your device's MAC address can be used to track your physical movements. I enforce MAC randomization at the NetworkManager level.
# Create a NetworkManager configuration drop-in
sudo nano /etc/NetworkManager/conf.d/10-mac-randomization.conf
Add the following content:
[device]
wifi.scan-rand-mac-address=yes
[connection]
wifi.cloned-mac-address=random
ethernet.cloned-mac-address=random
# Restart NetworkManager
sudo systemctl restart NetworkManager
Phase 4: Kernel-Level Process and Memory Privacy
By default, any user on a Linux system can view the command-line arguments and environment variables of processes running under other users' accounts. This is a massive privacy and security leak.
Restricting Process Visibility (hidepid)
I mount the /proc filesystem with the hidepid=2 option. This ensures users can only see their own processes, effectively blinding them from the rest of the system.
# Create a group for users who need to see all processes (e.g., monitoring tools)
sudo groupadd procusers
# Remount /proc with hidepid
sudo mount -o remount,rw,hidepid=2,gid=procusers /proc
# Note: on some kernels/distros, a live remount of hidepid does not take
# effect until the next full unmount/mount cycle or reboot. Verify with:
# grep hidepid /proc/mounts
# If it isn't reflected, reboot or perform a full umount + mount instead
# of "remount".
Make it persistent across reboots by editing /etc/fstab. Add or modify the proc line:
proc /proc proc defaults,hidepid=2,gid=procusers 0 0
Restricting Kernel Ring Buffer and dmesg
The kernel ring buffer (dmesg) contains hardware details, driver loads, and sometimes sensitive memory addresses. I restrict access to this to the root user only.
# Apply via sysctl immediately
sudo sysctl -w kernel.dmesg_restrict=1
# Make persistent
echo "kernel.dmesg_restrict = 1" | sudo tee -a /etc/sysctl.d/99-privacy.conf
sudo sysctl --system
Comparative Analysis: Privacy Hardening Tools
When architecting a privacy-hardened Linux deployment, choosing the right tools is critical. Here is how I evaluate native utilities versus third-party alternatives based on enterprise deployment realities.
| Privacy Domain | Native Linux Tool | Third-Party Alternative | Engineer's Verdict & Use Case |
|---|---|---|---|
| Secure File Deletion | shred (coreutils) |
scrub, srm |
Native is best for HDDs. shred is pre-installed and reliable. For SSDs, rely on blkdiscard and full-disk encryption (LUKS) rather than file-level wiping. |
| Encrypted DNS | systemd-resolved (DoT) |
dnscrypt-proxy, Unbound |
Use systemd-resolved for 90% of enterprise endpoints. It requires zero extra dependencies. Use dnscrypt-proxy only if you need advanced anonymization routing (e.g., Tor/DNSCrypt). |
| Shell History | Bash HISTCONTROL |
atuin, ble.sh |
Stick to native Bash tweaks for high-security environments. Third-party history sync tools (like atuin) introduce cloud dependencies that violate strict privacy models — unless deployed with a self-hosted sync server, which mitigates this concern. |
| Process Hiding | mount -o hidepid=2 |
grsecurity (PaX) |
Native hidepid is sufficient for standard privacy. grsecurity offers superior memory protection but requires custom kernel compilation, which is often impractical for modern cloud deployments. |
Interactive FAQ: Real-World Implementation Scenarios
Will setting hidepid=2 break my system monitoring tools like Prometheus or Datadog?
Yes, it will. Monitoring agents run under specific service accounts (e.g., prometheus or datadog) and need to read /proc to gather metrics. When you implement hidepid=2,gid=procusers, you must add the monitoring service accounts to the procusers group. I always test this in a staging environment first, as some legacy applications also assume they can read other users' PIDs.
Does systemd-resolved's DNSDoes OverTLS=yes actually prevent ISP tracking?
It prevents your ISP from seeing the specific domain names you are querying, as the DNS payload is encrypted inside the TLS tunnel. However, the ISP can still see the IP address of the DNS server you are connecting to (e.g., Cloudflare's 1.1.1.1) and the SNI (Server Name Indication) of the actual websites you visit via HTTPS. It stops casual DNS snooping, but it is not a silver bullet for total network anonymity.
How do I securely wipe a drive that is encrypted with LUKS?
If the drive is fully encrypted with LUKS, secure deletion of individual files is largely moot because the underlying data is already ciphertext. To "wipe" the drive and make the data unrecoverable, you simply need to destroy the LUKS key material. Running cryptsetup luksErase /dev/sdX (note: the subcommand is luksErase, not erase) wipes all key slots and headers, or you can manually overwrite the LUKS header region with random data (dd if=/dev/urandom of=/dev/sdX bs=4M count=10). Either approach renders the entire drive's contents permanently cryptographically inaccessible in seconds.
Can I prevent the kernel from logging USB device serial numbers?
Yes. By default, plugging in a USB drive logs its serial number to dmesg and /var/log/syslog, which can be a privacy leak if the logs are shipped to a central SIEM. You can suppress this by adjusting the kernel's printk levels or using rsyslog filters to drop messages containing "USB" and "SerialNumber". However, the cleanest approach is to disable USB mass storage entirely if it's not required for the user's role.

Join the conversation