How to Tell If Your Alpine Linux (or any Linux) WordPress Site Was Hacked

Defensive Security

How to Tell If Your Alpine Linux (or any Linux) WordPress Site Was Hacked

A step-by-step forensic checklist for self-hosted WordPress sites running on Alpine Linux — covering logs, file integrity, database users, network connections, and how to distinguish a system upgrade crash from a real intrusion. My site on Alpine Linux stopped working this morning due to an auto upgrade which I wasn’t expecting. I decided to write this up so that it might help someone.  

Steve Gopal
 
April 13, 2026
 
15 min read
 
CISSP Verified
 
Alpine Linux

“Your site just went down. Before you panic, ask the right question: was it a system change — or was it someone else?”

Self-hosted WordPress sites on Alpine Linux are lean, fast, and highly customizable. But when something breaks — a sudden outage, unexpected behavior, or unfamiliar content — many site owners immediately assume the worst: a hack. In reality, most unexpected outages are caused by system package upgrades, not malicious actors. Knowing how to tell the difference quickly and methodically is a core operational skill.

This guide walks through the exact forensic commands to run on an Alpine Linux system hosting WordPress via Podman containers. Every command is tested and real — no theoretical checklists. By the end you will know definitively whether your site was compromised or simply broken by an update. You can adapt the steps here to your version on Linux.

9forensic checks to run
<10mto complete full audit
$0cost — all built-in tools
100%command-line, no GUI needed

Hack vs. Upgrade Crash — Key Differences

The first question to answer is not “what happened” but “what kind of event is this?” The symptoms of a system upgrade crash and a compromise can look identical from the outside — both result in a site that is down. The difference is in the evidence left behind.

Signal Upgrade Crash Compromise
Site down after reboot ✓ Very common ✓ Possible
Container runtime errors in logs ✓ Typical (cgroups, networking) ✗ Rare
New unknown WordPress admin user ✗ Never ✓ Strong indicator
Modified PHP files in last 24–48 hrs ✗ Unlikely ✓ Strong indicator
eval(base64_decode) in PHP files ✗ Never ✓ Definitive indicator
Unexpected outbound connections ✗ Unlikely ✓ Strong indicator
Site content defaced or spammy ✗ Never ✓ Definitive indicator
Package upgrade in system logs ✓ Present ✗ Absent
ℹ️
Real World Example

A Podman v4 to v5 upgrade on Alpine Linux silently changed the default rootless networking from slirp4netns to pasta and the default cgroup handling — causing containers to fail to start after reboot. This is indistinguishable from an outage caused by a hack until you examine the container and system logs.

Check WordPress Files for Malware

The most reliable server-side hack indicator is malicious code injected into PHP files. Attackers typically use obfuscated PHP — base64-encoded payloads wrapped in eval() calls — to establish persistence and execute remote commands. These two grep commands will catch the most common injection patterns.

Scan for Obfuscated Malware

bashmalware-scan.sh
# Scan for base64-encoded eval payloads (most common malware pattern)
sudo grep -r “eval(base64_decode” /home/testuser/wordpress-podman/wordpress/wp_data

# Scan for gzip-compressed eval payloads (second most common)
sudo grep -r “eval(gzinflate” /home/testuser/wordpress-podman/wordpress/wp_data

# Scan for additional obfuscation patterns
sudo grep -r “eval(str_rot13” /home/testuser/wordpress-podman/wordpress/wp_data
sudo grep -r “preg_replace.*\/e” /home/testuser/wordpress-podman/wordpress/wp_data

# Clean output means no matches — your files are not injected

Find Recently Modified PHP Files

bashrecent-files.sh
# Files modified in the last 7 days
find /home/testuser/wordpress-podman/wordpress/wp_data -name “*.php” -mtime -7

# Files modified in last 24 hours (urgent — investigate immediately)
find /home/testuser/wordpress-podman/wordpress/wp_data -name “*.php” -mtime -1

# Files modified in last 7 days — any file type
find /home/testuser/wordpress-podman/wordpress/wp_data -mtime -7 -type f

⚠️
Expected Results vs. Suspicious Results

Normal results include cache files under wp-content/cache/ and plugin update files such as firewall rule settings. Suspicious results include any .php files in wp-content/uploads/ (uploads should never contain executable PHP), files with random hex names, or any core WordPress files like wp-login.php or wp-config.php showing recent modification timestamps you did not cause.

Audit WordPress Database Users

One of the first things an attacker does after gaining WordPress access is create a hidden admin account for persistent access. This account may have an innocuous name and a personal-looking email address. Auditing your WordPress user table takes seconds and is one of the highest-value checks you can run.

List All WordPress Users and Their Roles

bashdb-audit.sh
# List all users with registration date
podman exec -it mariadb mysql -u testdbuser -pwordpresspass testdbpass -e \
“SELECT user_login, user_email, user_registered FROM wp_users;”

# List users AND their WordPress roles (administrator, editor, etc.)
podman exec -it mariadb mysql -u testdbuser -pwordpresspass testdbpass -e \
“SELECT user_login, user_email, user_registered, meta_value \
FROM wp_users JOIN wp_usermeta ON wp_users.ID = wp_usermeta.user_id \
WHERE meta_key = ‘wp_capabilities’;”

# Check for recently created users (last 30 days)
podman exec -it mariadb mysql -u testdbuser -pwordpresspass testdbpass -e \
“SELECT user_login, user_email, user_registered FROM wp_users \
WHERE user_registered > DATE_SUB(NOW(), INTERVAL 30 DAY);”

Remove a Suspicious Admin User

bashremove-user.sh
# Remove user and all associated metadata
podman exec -it mariadb mysql -u testdbuser -pwordpresspass testdbpass -e \
“DELETE FROM wp_users WHERE user_login=’suspicious_user’;”

podman exec -it mariadb mysql -u testdbuser -pwordpresspass testdbpass -e \
“DELETE FROM wp_usermeta WHERE user_id NOT IN (SELECT ID FROM wp_users);”

🔴
Red Flag: Unknown Administrator Account

Any administrator-role user you did not create is a definitive sign of compromise. Do not simply delete the account and move on — if an attacker created an admin account they likely also installed a backdoor plugin or modified a theme file. Run the full malware scan above before considering the incident resolved.

Check SSH Login Attempts

Alpine Linux logs authentication events to /var/log/messages. Reviewing this file tells you who has been trying to log in — and whether any attempt succeeded. Failed logins from internal IPs are usually your own devices with a typo. Failed logins from external IPs are brute force attempts and warrant further investigation.

Review Authentication Logs

bashssh-audit.sh
# View last 20 failed password attempts
sudo grep “Failed password” /var/log/messages | tail -20

# View successful logins
sudo grep “Accepted password\|Accepted publickey” /var/log/messages | tail -20

# Count failed attempts by source IP (spot brute force)
sudo grep “Failed password” /var/log/messages | \
awk ‘{print $(NF-3)}’ | sort | uniq -c | sort -rn | head -10

# View login history
sudo last | head -20

Distinguish Internal vs. External Attempts

baship-check.sh
# Identify which device an internal IP belongs to
arp -a | grep 192.168.0.99

# Check if a suspicious external IP has known reputation
# Visit https://www.abuseipdb.com and enter the IP address

ℹ️
192.168.x.x Failures Are Usually Benign

Failed logins from RFC1918 private IP ranges (192.168.x.x, 10.x.x.x, 172.16-31.x.x) are almost always your own devices — a Mac, phone, or another Linux box on your home network with a mistyped username or old SSH key. Verify the IP with arp -a before treating it as a threat.

Inspect Open Network Connections

A compromised server often maintains persistent outbound connections to attacker-controlled infrastructure — command-and-control servers, data exfiltration endpoints, or reverse shells. Inspecting active network connections takes seconds and immediately reveals anything unexpected.

Check All Listening and Active Connections

bashnetwork-audit.sh
# Show all listening services and which process owns them
sudo netstat -tulnp

# Show all active connections including established outbound
sudo netstat -tanp

# Alternative using ss (more modern)
sudo ss -tulnp

# Show only established outbound connections
sudo ss -tnp state established

Expected Open Ports on a Clean System

Port Process Expected?
22 (TCP) sshd ✓ Yes — SSH access
8787 (TCP) rootlessport (Podman) ✓ Yes — WordPress
127.0.0.1:20241 (TCP) cloudflared ✓ Yes — Tunnel
UDP high ports cloudflared ✓ Yes — QUIC/tunnel
4444, 1337, 8888 unknown ✗ Investigate immediately
Any port, unknown process ??? ✗ Investigate immediately
🔴
High Risk Port Patterns

Outbound connections on ports 4444, 1337, 8888, or 31337 are classic reverse shell indicators. Any listening service you do not recognize — especially one owned by www-data or an unknown user — should be treated as a backdoor until proven otherwise. Identify the owning process with sudo lsof -i :[port] immediately.

Run Free Online Security Scans

Server-side checks tell you what is happening inside your system. External scans tell you what the world sees — malware injected into your HTML, blacklist status, and whether search engines have flagged your site as dangerous. Run these after completing your server-side audit.

🔒
Sucuri SiteCheck

The gold standard free WordPress malware scanner. Checks for injected malware, blacklist status across major databases, outdated software, and security anomalies visible in your page source.

Free

sitecheck.sucuri.netmalwareblacklist
🦠
VirusTotal

Scan your URL against 70+ security vendors simultaneously. Provides the most comprehensive external reputation check available for free. A clean result here is strong evidence your site is not compromised.

Free

virustotal.com70+ vendorsreputation

Run All Three in Under 2 Minutes

urlsscan-targets.txt
# Paste your domain into each of these:

https://sitecheck.sucuri.net
https://transparencyreport.google.com/safe-browsing/search
https://www.virustotal.com/gui/home/url

# All three should return clean results within 60 seconds each

Prevent Dangerous Auto-Upgrades on Alpine Linux

Alpine Linux does not auto-upgrade by default — but a single manual apk upgrade can silently bump critical packages like Podman across major versions, breaking your entire container stack. The safest approach is to always preview upgrades before applying them, and to use the –ignore flag to skip packages that could break your stack.

Always Preview Before Upgrading

bashsafe-upgrade.sh
# Step 1: Always simulate first — see exactly what will change
sudo apk upgrade –simulate

# Step 2: Review the output carefully for critical packages
# Look for: podman, crun, runc, slirp4netns, containers-common
# Any of these upgrading could affect your container stack

# Step 3: Upgrade everything EXCEPT podman
sudo apk upgrade –ignore podman

# Step 4: Upgrade podman only when you have time to troubleshoot
sudo apk add podman

⚠️
Why Podman Upgrades Are Risky

Podman v5 changed its default rootless networking (slirp4netns to pasta), default OCI runtime (runc to crun), and cgroup handling — all in a single major version bump. Without the right configuration in place, upgrading Podman will leave your containers unable to start after the next reboot. Always test Podman upgrades during a maintenance window, never during a routine system update.

Pin Critical Packages on Alpine Linux

Package pinning locks a specific package to its current version, preventing it from being upgraded during routine apk upgrade runs. On a production server hosting a live site, pinning Podman and its dependencies is a simple one-command protection against unplanned breakage.

Pin Podman to Current Version

bashpin-podman.sh
# Check currently installed version
apk info podman

# Pin to current version (replace 5.5.1-r0 with your actual version)
sudo apk add ‘podman=5.5.1-r0’

# Verify the pin is in place
apk info podman | head -1

# To unpin later when ready to upgrade intentionally
sudo apk add podman

Safe Update Workflow for Production Servers

  1.  
    Simulate First

    Always run sudo apk upgrade –simulate before any real upgrade. Read the full output and identify any container-related packages in the list.

  2.  
    Upgrade Safely Excluding Critical Packages

    Run sudo apk upgrade –ignore podman to get all security patches and library updates without touching your container runtime.

  3.  
    Test Podman Upgrades in a Maintenance Window

    When you are ready to upgrade Podman, do it when you have 30–60 minutes to troubleshoot. Have your containers.conf configuration backed up. Know the fallback steps.

  4.  
    Verify After Every Reboot

    After any system reboot run podman-compose ps immediately. Both containers should show status Up. If they show Created or Exited your container runtime configuration needs attention before the site will serve traffic.

Full Hack Detection Audit Checklist

Run through this checklist any time your site goes down unexpectedly, you notice unusual behavior, or you simply want confidence that your server is clean. The full checklist takes under 10 minutes on the command line.

Alpine Linux WordPress Hack Detection Checklist

Run grep -r “eval(base64_decode” on wp_data directory — no output means clean

Run grep -r “eval(gzinflate” on wp_data directory — no output means clean

Check for PHP files modified in the last 7 days — review any unexpected results

Audit wp_users table — confirm you recognize every user and their role

Review failed SSH logins — identify all source IPs in /var/log/messages

Run netstat -tulnp — confirm all listening ports match expected services

Run Sucuri SiteCheck on your domain — confirm clean result

Run VirusTotal URL scan — confirm zero detections across vendors

Check Google Safe Browsing status — confirm no warnings

Confirm podman is pinned — apk info podman shows correct locked version

Confirm containers.conf is correct — cgroups=disabled, runtime=crun, slirp4netns

Run apk upgrade –simulate before any future upgrades — review output before applying

<10mfull checklist completion time
$0all tools are free and built-in
9independent verification checks
100%command-line, works over SSH
SG
Steve Gopal
CISSP · Staff Security Researcher · OrcaSecure

Steve is a CISSP-certified security researcher specializing in defensive security, incident response, and self-hosted infrastructure hardening. He runs orcasecure.net on Alpine Linux using Podman containers and has hands-on experience recovering and hardening WordPress sites after real-world upgrade and intrusion events.

Scroll to Top