• Resolved joostgrunwald

    (@joostgrunwald)


    During setup, the plugin builds an otpauth URI that includes the user’s TOTP secret, then generates a QR code using a remote service. The full otpauth URI (including the secret) is sent to https://api.qrserver.com/v1/create-qr-code/ as a GET parameter.

    Technical:

    $display=$this->user->user_login;
    $name=parse_url(get_bloginfo('wpurl'),PHP_URL_HOST);
    $display=$name.'%3A'.$display;
    $data=sprintf("otpauth://totp/%s?secret=%s&issuer=%s",$display,$secret,$name);

    and then

    function getQrCodeUrl($data, $size=144){
    $data=urlencode($data);
    $qr_url=sprintf('https://api.qrserver.com/v1/create-qr-code/?size=%1$sx%1$s&data=%2$s',$size,$data);
    return $qr_url;
    }

    Impact

    • The TOTP secret is disclosed to a third party (the QR provider). Anyone with access to those logs can generate valid 2FA codes and bypass 2FA for that user. Even over HTTPS, the confidentiality breach exists at the remote endpoint.
    • If the setup page is loaded, the secret is transmitted externally. For existing users, reconfiguring or re‑enrolling can re‑expose secrets.

    CVSS v3.1: 8.2 (AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N)

    PoC (lab)

    • Enable 2SV and visit the setup page. Inspect the network: requests to https://api.qrserver.com/v1/create-qr-code/?size=…&data=otpauth://totp/…secret=<SECRET>&issuer=<SITE> contain the secret in plaintext query string.

    Fix

    • Render QR codes locally (server-side image or client-side library) without sending the secret to external services.
    • Do not embed secrets in third‑party requests.
Viewing 1 replies (of 1 total)
  • Plugin Author as247

    (@as247)

    Hi joostgrunwald,

    Thanks for your findings and concerns regarding the potential exposure of the TOTP secret to third-party QR code services.

    Before version 2.6.3, the plugin used Google’s QR code API to generate QR codes. While this method exposed the TOTP secret to a third-party service via HTTP requests, the risk of Google actively intercepting or misusing this data is very low, given their reputation and business model.

    Starting from version 2.6.3, we have switched to rendering QR codes entirely on the client side using JavaScript, without relying on any external QR code generation services. You can review the relevant code here:
    https://plugins.trac.wordpress.org/browser/wordpress-2-step-verification/tags/2.6.3/resources/js/components/authenticator.vue

    Here is the key snippet responsible for rendering the QR code locally:

    renderQrCodes() {
    let size = this.qr_size || 128;
    let qrCodeDivs = document.getElementsByClassName('wp2sv-qrcode-render');
    if (qrCodeDivs.length === 0 || typeof QRCode === 'undefined') {
    console.log('No QR code divs found or no data to render QR code', qrCodeDivs.length, typeof QRCode === 'undefined');
    return false;
    }
    try {
    for (let i = 0; i < qrCodeDivs.length; i++) {
    new QRCode(qrCodeDivs[i], {
    text: this.qr_data,
    width: size,
    height: size,
    correctLevel: QRCode.CorrectLevel.M,
    });
    }
    return true;
    } catch (e) {
    return false;
    }
    }

    The fallback to a third-party QR code image URL is included as a safety net but is almost never triggered in real usage.

    Unused external QR code services were removed in version 2.6.4 to further reduce any risk.

    Therefore, there is no vulnerability related to TOTP secret exposure via QR code generation.

Viewing 1 replies (of 1 total)

The topic ‘TOTP secret disclosed to third‑party QR service’ is closed to new replies.