CVE-2025-63958 — MILLENSYS Vision Tools Workspace Unauthenticated Configuration Disclosure
1. Overview
This advisory documents a critical unauthenticated configuration disclosure affecting multiple versions of MILLENSYS Vision Tools Workspace, a medical PACS/Reporting platform widely deployed across hospitals and radiology centers.
A missing access control on the /MILLENSYS/settings endpoint allows remote attackers to retrieve full backend configuration, including plaintext database credentials, file share paths, license server URLs, and sensitive system parameters.
CVE ID: CVE-2025-63958
2. Introduction
During an authorized security assessment, publicly accessible servers running MILLENSYS Vision Tools Workspace were identified. Multiple versions were verified as vulnerable:
- 6.5.0.2585
- 6.5.0.2596
- 5.10.5.2429
All versions exposed the same critical flaw.
3. Discovery & Enumeration
3.1. Shodan Search
The following Shodan dork was used to enumerate publicly accessible instances:
http.title:"Vision Tools Workspace"
This revealed live deployments in multiple countries.
3.2. Identifying Public Interfaces
Each host presented the same landing page:
- “Welcome to Millensys, Vision Tools Workspace”
- Hosted on Microsoft IIS
- Version shown on login pages (e.g., 6.5.0.2585)

4. Vulnerable Endpoint Identification
4.1. Direct Access to Administrative Panel
The following endpoint was found accessible without authentication:
/MILLENSYS/settings
This loads the WorkSpace Control Panel—normally reserved for administrators.
4.2. Accessing Web Settings
Clicking “Web Settings” redirects to:
/MILLENSYS/edit/Settings.MillenSys
This endpoint exposes sensitive backend configuration directly in HTML.
5. Sensitive Data Exposure
The settings page reveals:
MiGlobal Database:
- Server
- Database
- Username:
Example - Password: (masked, but retrievable through HTML)
MiReport Database:
- Same pattern: server, DB name, username, password
Other Exposed Data:
- Patient folder directory paths
- Report template directories
- Client update executables
- License server URL
- Profile paths
All sensitive values are rendered in plaintext in HTML without authentication.
6. Technical Root Cause
- Zero authentication checks on critical administrative endpoints.
- Credentials embedded directly in client-side HTML.
- Lack of role-based access control.
- Sensitive configuration stored in web-accessible pages.
7. Impact Assessment
Confidentiality
Severe breach — Full DB credentials exposed.
Integrity
Attackers can alter patient data, user accounts, reports, and configuration.
Availability
DB destruction or corruption is possible.
Business Impact
- PHI exposure (HIPAA/GDPR violation risk)
- Full system compromise
- Lateral movement into hospital networks
- Operational shutdown
8. Affected Versions
Confirmed on:
- 5.10.5.2429
- 6.5.0.2585
- 6.5.0.2596
Likely affects all versions exposing these endpoints.
9. Mitigation
Immediate
- Remove public exposure immediately.
- Restrict access behind VPN or IP whitelist.
Long‑Term
- Implement server-side authentication.
- Remove sensitive values from client-side HTML.
- Encrypt stored credentials.
10. Security Mapping
CWE
- CWE-306 — Missing Authentication for Critical Function
- CWE-200 — Sensitive Information Exposure
- CWE-284 — Improper Access Control
MITRE ATT&CK
- T1210: Exploitation of Remote Services
- T1552: Unsecured Credentials
11. Final CVE Summary
CVE-2025-63958 — MILLENSYS Vision Tools Workspace Unauthenticated Configuration Disclosure
A missing access control vulnerability allows unauthenticated attackers to access administrative configuration pages through /MILLENSYS/settings and /MILLENSYS/edit/Settings.MillenSys. These pages expose plaintext database credentials, file system paths, client update packages, and license server URLs. Exploitation results in full system compromise.
12. Safe Validation Approach
The following validation approach is designed for authorized defenders and asset owners. It confirms whether the vulnerable pages are reachable without publishing or storing exposed secrets.
Validation Command
python3 cve-2025-63958-safe-check.py -u http://TARGET:PORT/
Optional output:
python3 cve-2025-63958-safe-check.py -u http://TARGET:PORT/ --json result.json
Expected Result
Target: http://TARGET:PORT/
Settings endpoint: HTTP 200
Configuration endpoint: HTTP 200
Authentication required: No
Sensitive indicators found: Yes
Result: Vulnerable - restrict access and remove exposed secrets immediately
The script below intentionally redacts sensitive values. It reports the presence of exposed fields without printing database credentials, passwords, internal paths, or full configuration data.
Safe Validator Code
#!/usr/bin/env python3
"""
CVE-2025-63958 safe validator.
Purpose:
- Check whether the known configuration endpoints are reachable without authentication.
- Identify sensitive field names.
- Redact values by default.
Use only against systems you own or are explicitly authorized to test.
"""
import argparse
import json
import re
import sys
from dataclasses import dataclass, asdict
from typing import List, Optional
from urllib.parse import urljoin
import requests
from bs4 import BeautifulSoup
SETTINGS_PATH = "/MILLENSYS/settings"
CONFIG_PATH = "/MILLENSYS/edit/Settings.MillenSys"
SENSITIVE_FIELD_PATTERNS = re.compile(
r"(password|passwd|pwd|username|user|database|db|server|path|license|connection)",
re.IGNORECASE,
)
PAGE_INDICATORS = [
"WorkSpace",
"Control Panel",
"MiGlobal",
"MiReport",
"Settings.MillenSys",
]
@dataclass
class ValidationResult:
target: str
settings_status: Optional[int]
config_status: Optional[int]
settings_accessible: bool
config_accessible: bool
auth_required: bool
sensitive_indicators_found: bool
sensitive_field_names: List[str]
vulnerable: bool
recommendation: str
def fetch(session: requests.Session, url: str) -> Optional[requests.Response]:
try:
return session.get(url, timeout=(5, 10), allow_redirects=True, verify=True)
except requests.exceptions.SSLError:
print(f"[!] TLS verification failed for {url}", file=sys.stderr)
print(" Validate the certificate chain or use an internal CA bundle for enterprise testing.", file=sys.stderr)
return None
except requests.RequestException as exc:
print(f"[!] Request failed for {url}: {exc}", file=sys.stderr)
return None
def page_has_expected_indicators(html: str) -> bool:
return any(indicator in html for indicator in PAGE_INDICATORS)
def extract_sensitive_field_names(html: str) -> List[str]:
soup = BeautifulSoup(html, "html.parser")
names = set()
for tag in soup.find_all(["input", "select", "textarea"]):
name = tag.get("name") or tag.get("id")
if name and SENSITIVE_FIELD_PATTERNS.search(name):
names.add(name.strip())
for match in SENSITIVE_FIELD_PATTERNS.finditer(html):
names.add(match.group(0).lower())
return sorted(names)
def validate_target(target: str) -> ValidationResult:
base = target if target.endswith("/") else target + "/"
settings_url = urljoin(base, SETTINGS_PATH.lstrip("/"))
config_url = urljoin(base, CONFIG_PATH.lstrip("/"))
session = requests.Session()
session.headers.update({"User-Agent": "Ozex-Safe-Validator/1.0"})
settings_response = fetch(session, settings_url)
config_response = fetch(session, config_url)
settings_status = settings_response.status_code if settings_response else None
config_status = config_response.status_code if config_response else None
settings_accessible = bool(
settings_response
and settings_response.status_code == 200
and page_has_expected_indicators(settings_response.text)
)
config_accessible = bool(
config_response
and config_response.status_code == 200
and page_has_expected_indicators(config_response.text)
)
combined_html = ""
if settings_response:
combined_html += settings_response.text
if config_response:
combined_html += config_response.text
sensitive_fields = extract_sensitive_field_names(combined_html)
sensitive_found = len(sensitive_fields) > 0
# If both endpoints are directly accessible with page indicators and sensitive field names,
# the system should be treated as vulnerable.
vulnerable = (settings_accessible or config_accessible) and sensitive_found
auth_required = not (settings_accessible or config_accessible)
recommendation = (
"Restrict endpoint access immediately, require authentication and authorization, "
"rotate any exposed secrets, and remove sensitive values from client-rendered HTML."
if vulnerable
else "No unauthenticated exposure confirmed by this safe check. Continue manual validation if in scope."
)
return ValidationResult(
target=base,
settings_status=settings_status,
config_status=config_status,
settings_accessible=settings_accessible,
config_accessible=config_accessible,
auth_required=auth_required,
sensitive_indicators_found=sensitive_found,
sensitive_field_names=sensitive_fields,
vulnerable=vulnerable,
recommendation=recommendation,
)
def print_result(result: ValidationResult) -> None:
print(f"Target: {result.target}")
print(f"Settings endpoint HTTP status: {result.settings_status}")
print(f"Configuration endpoint HTTP status: {result.config_status}")
print(f"Authentication required: {'Yes' if result.auth_required else 'No'}")
print(f"Sensitive indicators found: {'Yes' if result.sensitive_indicators_found else 'No'}")
if result.sensitive_field_names:
print("Sensitive field names observed, values redacted:")
for name in result.sensitive_field_names:
print(f" - {name}: <redacted>")
print(f"Result: {'Vulnerable' if result.vulnerable else 'Not confirmed vulnerable'}")
print(f"Recommendation: {result.recommendation}")
def main() -> int:
parser = argparse.ArgumentParser(description="CVE-2025-63958 safe validator")
parser.add_argument("-u", "--url", required=True, help="Target base URL")
parser.add_argument("--json", help="Write redacted result to a JSON file")
args = parser.parse_args()
result = validate_target(args.url)
print_result(result)
if args.json:
with open(args.json, "w", encoding="utf-8") as handle:
json.dump(asdict(result), handle, indent=2, ensure_ascii=False)
print(f"Saved redacted result to: {args.json}")
return 1 if result.vulnerable else 0
if __name__ == "__main__":
raise SystemExit(main())
13. Disclosure Timeline
| Date | Event |
|---|---|
| 2025-10 | Issue identified during authorized security assessment. |
| 2025-10 | Vulnerability details prepared for responsible reporting. |
| 2025-11 | Public advisory draft prepared. |
| 2025-11 | CVE reference documented in this advisory. |
14. Remediation Checklist
- Remove public exposure of
/MILLENSYS/settingsand related administrative endpoints. - Enforce authentication and role-based authorization on all administrative functions.
- Move sensitive configuration values server-side; never render secrets in HTML.
- Rotate database credentials, service account passwords, and exposed secrets.
- Review IIS access logs for unauthenticated access to the affected endpoints.
- Add monitoring alerts for direct access to administrative configuration paths.
- Validate remediation from an unauthenticated browser session and from an external network path.
Author’s Note
Written by Khaled Al‑Refaee (Ozex)
Cybersecurity Consultant | Red Team Operator | Offensive Security Professional
Comments
Questions, corrections, and professional discussion are welcome.