Every CVE Search/ Get API key

CVE-2026-33488

AVideo has a PGP 2FA Bypass via Cryptographically Broken 512-bit RSA Key Generation in LoginControl Plugin

7.4 High

WWBN AVideo is an open source video platform. In versions up to and including 26.0, the createKeys() function in the LoginControl plugin's PGP 2FA system generates 512-bit RSA keys, which have been publicly factorable since 1999. An attacker who obtains a target user's public key can factor the 512-bit RSA modulus on commodity hardware in hours, derive the complete private key, and decrypt any PGP 2FA challenge issued by the system — completely bypassing the second authentication factor. Additionally, the generateKeys.json.php and encryptMessage.json.php endpoints lack any authentication checks, exposing CPU-intensive key generation to anonymous users. Commit 00d979d87f8182095c8150609153a43f834e351e contains a patch.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
High
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
None

Exploit likelihood

0.26%Up 0.2 points since Mar 24, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.4

AVideo has a PGP 2FA Bypass via Cryptographically Broken 512-bit RSA Key Generation in LoginControl Plugin

WWBN AVideo is an open source video platform. In versions up to and including 26.0, the createKeys() function in the LoginControl plugin's PGP 2FA system generates 512-bit RSA keys, which have been publicly factorable since 1999. An attacker who obtains a target user's public key can factor the 512-bit RSA modulus on commodity hardware in hours, derive the complete private key, and decrypt any PGP 2FA challenge issued by the system — completely bypassing the second authentication factor. Additionally, the generateKeys.json.php and encryptMessage.json.php endpoints lack any authentication checks, exposing CPU-intensive key generation to anonymous users. Commit 00d979d87f8182095c8150609153a43f834e351e contains a patch.

Record
CVE-2026-33488
CVSS 3.1
7.4 HighCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-326
Updated
2026-11-02
EUVDEUVD-2026-14449 7.4

WWBN AVideo is an open source video platform. In versions up to and including 26.0, the createKeys() function in the LoginControl plugin's PGP 2FA system generates 512-bit RSA keys, which have been publicly factorable since 1999. An attacker who obtains a target user's public key can factor the 512-bit RSA modulus on commodity hardware in hours, derive the complete private key, and decrypt any PGP 2FA challenge issued by the system — completely bypassing the second authentication factor. Additionally, the generateKeys.json.php and encryptMessage.json.php endpoints lack any authentication checks, exposing CPU-intensive key generation to anonymous users. Commit 00d979d87f8182095c8150609153a43f834e351e contains a patch.

Record
EUVD-2026-14449
CVSS 3.1
7.4 HighCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-6m5f-j7w2-w953 7.4

AVideo has a PGP 2FA Bypass via Cryptographically Broken 512-bit RSA Key Generation in LoginControl Plugin

Summary

The createKeys() function in the LoginControl plugin's PGP 2FA system generates 512-bit RSA keys, which have been publicly factorable since 1999. An attacker who obtains a target user's public key can factor the 512-bit RSA modulus on commodity hardware in hours, derive the complete private key, and decrypt any PGP 2FA challenge issued by the system — completely bypassing the second authentication factor. Additionally, the generateKeys.json.php and encryptMessage.json.php endpoints lack any authentication checks, exposing CPU-intensive key generation to anonymous users.

Details

The vulnerability originates in plugin/LoginControl/pgp/functions.php at line 26:

// plugin/LoginControl/pgp/functions.php:26
$privateKey = RSA::createKey(512);

This code was copied from the singpolyma/openpgp-php library's example/demo code, which was never intended for production use. The entire PGP 2FA flow relies on these weak keys:

  1. Key generation: When a user enables PGP 2FA, the UI calls createKeys() which generates a 512-bit RSA keypair. The public key is saved to the database via savePublicKey.json.php.

  2. Challenge creation (LoginControl.php:520-531): During login, a uniqid() token is generated, stored in the session, and encrypted with the user's stored public key:

// LoginControl.php:525-530
$_SESSION['user']['challenge']['text'] = uniqid();
$encMessage = self::encryptPGPMessage(User::getId(), $_SESSION['user']['challenge']['text']);
  1. Challenge verification (LoginControl.php:533-539): The user must decrypt the challenge and submit the plaintext. Verification is a simple equality check:
// LoginControl.php:534
if ($response == $_SESSION['user']['challenge']['text']) {

Since 512-bit RSA was publicly factored in 1999 (RSA-155 challenge), an attacker who obtains the public key can factor the modulus using freely available tools (CADO-NFS, msieve, yafu) in a matter of hours on modern hardware, reconstruct the complete private key from the prime factors, and decrypt any challenge encrypted with that key.

Unauthenticated endpoints (compounding issue):

generateKeys.json.php does not include configuration.php and has no authentication check:

// plugin/LoginControl/pgp/generateKeys.json.php:1-2
<?php
require_once  '../../../plugin/LoginControl/pgp/functions.php';

Similarly, encryptMessage.json.php has no authentication. Both are accessible to anonymous users, enabling abuse of CPU-intensive RSA key generation for denial-of-service.

PoC

Step 1: Obtain the target user's 512-bit public key

The public key must be obtained through a side channel (e.g., the user sharing it per PGP conventions, another vulnerability leaking database contents, or admin access). The key is stored in the users_externalOptions table under the key PGPKey.

Step 2: Extract the RSA modulus from the public key

# Extract the modulus from the PGP public key
echo "$PUBLIC_KEY_ARMOR" | gpg --import 2>/dev/null
gpg --list-keys --with-key-data | grep '^pub'
# Or use Python:
python3 -c "
from Crypto.PublicKey import RSA
# Parse the PGP key and extract RSA modulus N
# N will be a ~155-digit number (512 bits)
print(f'N = {key.n}')
"

Step 3: Factor the 512-bit modulus

# Using CADO-NFS (typically completes in 2-8 hours on a modern desktop)
cado-nfs.py <modulus_decimal>
# Or using msieve:
msieve -v <modulus_decimal>
# Output: p = <factor1>, q = <factor2>

Step 4: Reconstruct the private key and decrypt the 2FA challenge

from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse

# From factoring step
p = <factor1>
q = <factor2>
n = p * q
e = 65537
d = inverse(e, (p-1)*(q-1))

# Reconstruct private key
privkey = RSA.construct((n, e, d, p, q))

# Decrypt the PGP-encrypted challenge from the login page
# and submit the plaintext to verifyChallenge.json.php

**Step 5: Submit decrypted challenge to…

Record
GHSA-6m5f-j7w2-w953
CVSS 3.1
7.4 HighCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-326
Updated
2026-11-02
NVD 7.4

WWBN AVideo is an open source video platform. In versions up to and including 26.0, the createKeys() function in the LoginControl plugin's PGP 2FA system generates 512-bit RSA keys, which have been publicly factorable since 1999. An attacker who obtains a target user's public key can factor the 512-bit RSA modulus on commodity hardware in hours, derive the complete private key, and decrypt any PGP 2FA challenge issued by the system — completely bypassing the second authentication factor. Additionally, the generateKeys.json.php and encryptMessage.json.php endpoints lack any authentication checks, exposing CPU-intensive key generation to anonymous users. Commit 00d979d87f8182095c8150609153a43f834e351e contains a patch.

Record
CVE-2026-33488
CVSS 3.1
7.4 HighCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
CVSS 3.1
8.1 HighCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-326
Updated
2026-11-02
OSV 7.4

AVideo has a PGP 2FA Bypass via Cryptographically Broken 512-bit RSA Key Generation in LoginControl Plugin

WWBN AVideo is an open source video platform. In versions up to and including 26.0, the createKeys() function in the LoginControl plugin's PGP 2FA system generates 512-bit RSA keys, which have been publicly factorable since 1999. An attacker who obtains a target user's public key can factor the 512-bit RSA modulus on commodity hardware in hours, derive the complete private key, and decrypt any PGP 2FA challenge issued by the system — completely bypassing the second authentication factor. Additionally, the generateKeys.json.php and encryptMessage.json.php endpoints lack any authentication checks, exposing CPU-intensive key generation to anonymous users. Commit 00d979d87f8182095c8150609153a43f834e351e contains a patch.

Record
CVE-2026-33488
CVSS 3.1
7.4 HighCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-326
Updated
2026-11-02
OSVGHSA-6m5f-j7w2-w953 7.4

AVideo has a PGP 2FA Bypass via Cryptographically Broken 512-bit RSA Key Generation in LoginControl Plugin

Summary

The createKeys() function in the LoginControl plugin's PGP 2FA system generates 512-bit RSA keys, which have been publicly factorable since 1999. An attacker who obtains a target user's public key can factor the 512-bit RSA modulus on commodity hardware in hours, derive the complete private key, and decrypt any PGP 2FA challenge issued by the system — completely bypassing the second authentication factor. Additionally, the generateKeys.json.php and encryptMessage.json.php endpoints lack any authentication checks, exposing CPU-intensive key generation to anonymous users.

Details

The vulnerability originates in plugin/LoginControl/pgp/functions.php at line 26:

// plugin/LoginControl/pgp/functions.php:26
$privateKey = RSA::createKey(512);

This code was copied from the singpolyma/openpgp-php library's example/demo code, which was never intended for production use. The entire PGP 2FA flow relies on these weak keys:

  1. Key generation: When a user enables PGP 2FA, the UI calls createKeys() which generates a 512-bit RSA keypair. The public key is saved to the database via savePublicKey.json.php.

  2. Challenge creation (LoginControl.php:520-531): During login, a uniqid() token is generated, stored in the session, and encrypted with the user's stored public key:

// LoginControl.php:525-530
$_SESSION['user']['challenge']['text'] = uniqid();
$encMessage = self::encryptPGPMessage(User::getId(), $_SESSION['user']['challenge']['text']);
  1. Challenge verification (LoginControl.php:533-539): The user must decrypt the challenge and submit the plaintext. Verification is a simple equality check:
// LoginControl.php:534
if ($response == $_SESSION['user']['challenge']['text']) {

Since 512-bit RSA was publicly factored in 1999 (RSA-155 challenge), an attacker who obtains the public key can factor the modulus using freely available tools (CADO-NFS, msieve, yafu) in a matter of hours on modern hardware, reconstruct the complete private key from the prime factors, and decrypt any challenge encrypted with that key.

Unauthenticated endpoints (compounding issue):

generateKeys.json.php does not include configuration.php and has no authentication check:

// plugin/LoginControl/pgp/generateKeys.json.php:1-2
<?php
require_once  '../../../plugin/LoginControl/pgp/functions.php';

Similarly, encryptMessage.json.php has no authentication. Both are accessible to anonymous users, enabling abuse of CPU-intensive RSA key generation for denial-of-service.

PoC

Step 1: Obtain the target user's 512-bit public key

The public key must be obtained through a side channel (e.g., the user sharing it per PGP conventions, another vulnerability leaking database contents, or admin access). The key is stored in the users_externalOptions table under the key PGPKey.

Step 2: Extract the RSA modulus from the public key

# Extract the modulus from the PGP public key
echo "$PUBLIC_KEY_ARMOR" | gpg --import 2>/dev/null
gpg --list-keys --with-key-data | grep '^pub'
# Or use Python:
python3 -c "
from Crypto.PublicKey import RSA
# Parse the PGP key and extract RSA modulus N
# N will be a ~155-digit number (512 bits)
print(f'N = {key.n}')
"

Step 3: Factor the 512-bit modulus

# Using CADO-NFS (typically completes in 2-8 hours on a modern desktop)
cado-nfs.py <modulus_decimal>
# Or using msieve:
msieve -v <modulus_decimal>
# Output: p = <factor1>, q = <factor2>

Step 4: Reconstruct the private key and decrypt the 2FA challenge

from Crypto.PublicKey import RSA
from Crypto.Util.number import inverse

# From factoring step
p = <factor1>
q = <factor2>
n = p * q
e = 65537
d = inverse(e, (p-1)*(q-1))

# Reconstruct private key
privkey = RSA.construct((n, e, d, p, q))

# Decrypt the PGP-encrypted challenge from the login page
# and submit the plaintext to verifyChallenge.json.php

**Step 5: Submit decrypted challenge to…

Record
GHSA-6m5f-j7w2-w953
CVSS 3.1
7.4 HighCVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N
Weakness
CWE-326
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
wwbn/avideo
Packagist
through 26.0 None known
wwbn/avideo
Packagist
through 26.0, plus listed versions
10.410.81111.111.1.1
Show 11 moreShow less
11.511.612.414.314.3.114.418.021.022.024.025.0
None known

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-33488 is a high vulnerability (CVSS 7.4) in Wwbn Avideo, published March 20, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.26%, the 17th percentile. No source names a fixed version.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open