Compromise of 2FA secrets through read-only SQLi – (Shield Security <= 16.1.6)

Affected pluginShield Security
Active installs60,000+
Vulnerable version<= 16.1.6
Audited version16.1..1
Fully patched version
Recommended remediationRemoval of the plugin


The plugin stores users’ TOTP secrets as plaintext in the database.
An attacker that can obtain one of the seemingly never-ending read-only SQL-Injections will be able to bypass all 2FA checks for all users indefinitely.

Proof of concept

The following code is used to retrieve TOTP secrets from the “wp_usermeta” table:

protected function getSecret() {
	$secret = $this->getCon()->getUserMeta( $this->getUser() )->{static::SLUG.'_secret'};
	return empty( $secret ) ? static::DEFAULT_SECRET : $secret;

* “static::SLUG” is equal to “(string) ga”.

An attacker can obtain all TOTP secrets through his read-only SQLi by running the following query.

SELECT user_id, meta_value FROM wp_usermeta WHERE meta_key = 'icwp-wpsf-meta'

Each record is a serialized PHP array that contains all user meta for one user.

After deserializing the records using PHP’s unserialize function, each record has a “ga_secret” key which is the user’s TOTP secret.


==> ga_secret: TJD7I4OXNQNPU3RD


Vendor contactedSeptember 12, 2022
First ResponseSeptember 12, 2022
Fully patched at
Publicly disclosedApril 24, 2023


Leave a Reply

Your email address will not be published. Required fields are marked *