In short: You find rogue admin accounts only if you check all layers: the CMS or shop, the hosting panel, the server's system users, the SSH access and the database users. Do not rely on the user list in the backend, because injected code can hide accounts there. Document and lock findings first, then clarify the cause, and only then delete.
Why an unknown administrator is so dangerous
An additional admin account is the most convenient backdoor for attackers. It needs no malicious code, does not show up in file scans and survives every update. Whoever later logs in with this account looks like a normal editor in the log.
After PHP2Shell, this check gains weight. The vulnerabilities CVE-2026-109618 and CVE-2026-109619 allow the execution of malicious code without logging in. Whoever can execute code on the server can also write to the database and thereby create accounts. A PHP update closes the vulnerability but removes no account that was created beforehand.
For PHP2Shell there are no published, confirmed indicators of compromise, that is, no list of typical traces. An unknown account is therefore no proof of PHP2Shell, but a clear sign of unauthorized access, whichever way it came about. An overview of further signs is at Am I already compromised?.
Where rogue admin accounts can hide
Many operators look only in the CMS. Attackers think in layers, and each layer has accounts of its own:
| Layer | Where to look | What to watch for |
|---|---|---|
| CMS or shop | User management and the database table of users | Administrator role, creation date, foreign email address |
| Hosting panel | Users, additional accounts, FTP accounts | Accounts that nobody on the team created |
| Linux server | /etc/passwd, groups sudo or wheel, sudoers |
further accounts with UID 0, new login shells |
| SSH | authorized_keys of all users |
Keys with no known owner |
| Database | User table of the database server | Users with global privileges or host % |
| External services | Domain, DNS, Search Console, CDN | additional owners or authorized persons |
The SSH layer is self-contained enough for an article of its own: Finding and removing unknown SSH keys.
Finding rogue admin accounts in the CMS, including hidden ones
The user list in the backend is generated by the application itself. If injected code runs along, it can filter out individual entries. Tools that look directly at the stored data are therefore more reliable. For WordPress, WP-CLI lists all administrators with their creation date:
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered
A read-only query in the database goes one level deeper. It shows every account to which the administrator role is assigned, regardless of what the interface displays. Adjust the table prefix wp_ to your installation:
SELECT u.ID, u.user_login, u.user_email, u.user_registered
FROM wp_users u
JOIN wp_usermeta m ON m.user_id = u.ID
WHERE m.meta_key = 'wp_capabilities'
AND m.meta_value LIKE '%administrator%'
ORDER BY u.user_registered DESC;
Compare the results of backend, WP-CLI and database. If an account appears only in the database, that is a strong warning sign, because code that hides it is then also involved. For other systems such as Shopware, TYPO3 or Joomla, the same principle applies: query the user table directly and compare it with the display in the backend. Which tables these are is stated in the vendor's documentation.
Checking system users and database users
On the server itself, accounts with root rights and accounts that can log in are of most interest. The following commands only read:
# Accounts with UID 0 (normally only root)
awk -F: '$3 == 0 {print $1}' /etc/passwd
# Accounts with a real login shell
grep -vE '(nologin|false)$' /etc/passwd
# Members of the admin groups
getent group sudo wheel
# Additional sudo rules
sudo ls -la /etc/sudoers.d/
sudo grep -rvE '^\s*(#|$)' /etc/sudoers /etc/sudoers.d/
# Most recent logins with full date
last -F | head -30
On the database server, you check which users exist and which privileges they have:
SELECT user, host FROM mysql.user ORDER BY user;
SHOW GRANTS FOR 'anwendung'@'localhost';
An application usually needs a user with privileges on exactly one database. An additional user with global privileges that may connect from any host (%) needs to be clarified.
Do not forget the accounts outside the server. Whoever has access to the domain contract or the DNS management can redirect visitors or have certificates issued on foreign servers. An additional owner in Google Search Console can submit sitemaps and change settings. At the registrar, DNS provider, CDN and Search Console, therefore go through the list of authorized persons and compare it with what your team knows.
How to handle a find correctly
The first impulse is to delete the rogue account immediately. But that also removes an important trace: the creation date often narrows down when the attacker was in the system. This order is better:
- Document: Record user name, ID, email, creation date, role and last activity with the time, preferably as a screenshot and export.
- Lock instead of delete: Revoke the role, replace the password with a random value or deactivate the account.
- Narrow down the period: Check logs around the creation date. Which requests were there shortly before, which files changed?
- Check further layers: Whoever creates one account rarely leaves only one. Also go through files, cron jobs, SSH keys and the database.
- Clean up and renew credentials: Only after cleanup and the PHP update renew all passwords, keys and sessions.
A note of caution: not every unknown account is malicious. Agencies, former service providers or maintenance plugins sometimes create accounts of their own. Clarify that before you raise the alarm, but clarify it promptly.
Preventing recurrence
After the cleanup, admin accounts should be the exception, not the rule. Personal accounts instead of shared access, as few administrators as possible and two-factor authentication for admin access have proven their worth. Also decide who may create new admin accounts and where that is documented.
A regular query like the ones above, for example weekly and compared with the previous week, makes new accounts quickly visible. For WordPress, the guide Finding backdoors in WordPress helps in addition.
How does PHP SOS help?
- We check all account layers from the CMS through the server to the database and compare the backend display with the stored data.
- We secure findings with timestamps before accounts are locked or removed.
- Within incident response, we clarify how the account came about and whether further backdoors exist.
- We renew access in the right order and set up ongoing monitoring of new admin accounts.
Frequently asked questions
Should I delete an unknown admin account immediately?
Better not immediately. First document user name, creation date, email address and last activity, and lock the account. Delete only once the traces are secured, because the creation date is often an important clue to the time of the break-in.
Can an admin account be invisible in the backend?
Yes. Injected code can hide individual accounts from the interface's user list. A direct database query or a command-line tool, by contrast, shows all stored accounts. That is why you should not look only in the backend.
Which layers besides the CMS do I have to check?
Hosting panel, FTP and SFTP access, the server's system users including sudo rights, SSH keys, database users and accounts at the domain registrar, DNS and Search Console. An attacker needs only one of these doors to come back.
Is it enough to change all passwords after the find?
No. A rogue account shows that someone had access. The entry point, further backdoors and possible data leaks must then be clarified too. Change passwords only after the cleanup and from a clean device.