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"]?>">
/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;?>">
/substudy/ezform.php?idFormMain=1&id=');alert(document.domain);//
/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']); ?>">
/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:
- Session cookie theft where the session cookie lacks
HttpOnly - DOM-level phishing and credential harvesting rendered on the real site
- Silent redirect to attacker infrastructure from within a staff workflow
- Patient record exfiltration through authenticated fetch calls once the payload is running as the logged-in user
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
| Date | Event |
|---|---|
| Vulnerability discovered by Jackson Mittag (0dayscyber) | |
| CVE-2026-38579 reserved by MITRE | |
| Public disclosure |