Reflected XSS CVSS 6.1 Medium

CVE-2026-38579: Multiple Reflected XSS in damasac/thaipalliative_lte

CVE ID
CVE-2026-38579
CVSS
6.1 Medium (AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N)
Vendor
damasac
Product
thaipalliative_lte
Affected
1.0 through 3.0 (all releases)
Fixed in
No patch available
Reporter
Jackson Mittag (0dayscyber)

Summary

Three reflected cross-site scripting sinks live in thaipalliative_lte, all reachable through /substudy/ezform.php. User input from three URL parameters lands directly inside HTML attribute and inline JavaScript contexts with no encoding step in between. Any unauthenticated attacker who can get a victim to click a crafted link executes arbitrary JavaScript in the victim's browser under the application's origin.

The product is a palliative care records system, so the same origin that carries an XSS payload also holds session cookies for staff who view patient data. That combination lifts what would otherwise be a routine reflection into a session hijack and data exfiltration primitive.

Affected component

Everything below points at a single file, /substudy/ezform.php, pinned to commit 57b5763. Line numbers are quoted straight from that commit.

Vulnerability details

Sink 1: idFormMain in an href attribute (line 24)

The parameter is dropped into the value of an href attribute with no escaping. The surrounding double quotes are the only thing keeping the attribute closed, and a payload containing "> pops out of the attribute and into element content, where a <script> tag runs as normal.

// Line 24
<a target="_blank" href="../eform/table2.php?task=public&idFormMain=<?php echo $_GET["idFormMain"]?>">
PoC
/substudy/ezform.php?idFormMain="><script>alert(document.domain)</script>

Sink 2: id in a JavaScript string and an attribute value (lines 25 and 75)

The id parameter comes through $_REQUEST, so it can be delivered via GET, POST, or a cookie. It reaches two contexts. Line 25 pastes it inside single-quoted arguments to an inline onclick handler, which means breaking out only needs a stray single quote. Line 75 drops it into a hidden input value, which is the classic attribute breakout case.

// Line 25
<a onclick="remove_ezform('remove', '<?php echo $_REQUEST["id"];?>', '...');">

// Line 75
<input type="hidden" name="id" id="id" value="<?php echo $id;?>">
PoC, line 25 (JavaScript context)
/substudy/ezform.php?idFormMain=1&id=');alert(document.domain);//
PoC, line 75 (attribute context)
/substudy/ezform.php?idFormMain=1&id="><script>alert(document.domain)</script>

Sink 3: ptid_key in an href and a form action (lines 26 and 42)

The line 26 case is the same attribute breakout pattern as sink 1. Line 42 base64-encodes the value into a Redirect parameter, so it will not produce reflected XSS on this page directly, but the downstream handler on insertdata.php decodes it before using it. If that handler ever emits the decoded string into HTML or a Location header without validation, the same payload becomes a stored or open-redirect primitive there. Worth pursuing during a full audit.

// Line 26
<a href="?ptid=<?php echo $_GET['ptid_key']; ?>">

// Line 42
<form action="../eform/insertdata.php?Redirect=<?php echo base64_encode("emr/?ptid=".$_GET['ptid_key']); ?>">
PoC, line 26 (href breakout)
/substudy/ezform.php?idFormMain=1&ptid_key="><script>alert(document.domain)</script>

Impact

Every sink runs code in the origin of the target install. Practical impact:

Attacker prerequisites are limited to one click on a crafted link. No credentials, no CSRF token, no local access.

Root cause

The file passes $_GET and $_REQUEST values through echo into HTML with no encoding at any layer. There is no htmlspecialchars(), no output filter, no templating engine performing auto-escape, and no Content Security Policy header to blunt the impact. The vulnerable pattern is uniform across every sink, which suggests the same fix template applies to all of them.

Remediation

Encode at the sink, not at the source. Every value that reaches HTML needs htmlspecialchars() with ENT_QUOTES; every value that reaches a JavaScript string context should be emitted through json_encode() so the runtime handles quoting for you.

// Vulnerable
echo $_GET["idFormMain"];

// Fixed for HTML attribute or content
echo htmlspecialchars($_GET["idFormMain"], ENT_QUOTES, 'UTF-8');

// Fixed for a JavaScript string literal
<script>
  var id = <?php echo json_encode($_REQUEST["id"]); ?>;
</script>

Two hardening steps sit on top of that. Ship a Content Security Policy that blocks inline scripts, or at minimum uses nonces, so a missed sink does not lead straight to execution. And when a parameter is only ever expected to be numeric, coerce it with (int) or validate against a whitelist before it reaches any output.

Timeline

DateEvent
Vulnerability discovered by Jackson Mittag (0dayscyber)
CVE-2026-38579 reserved by MITRE
Public disclosure

References