# NukeViet: Unauthenticated Reflected XSS in Comment Module

Unauthenticated reflected XSS in NukeViet's comment module: base64-encoded HTML in status_comment is decoded and rendered unescaped, with a static checkss token enabling URL delivery.

- Payout: Research
- Severity: high
- Program: NukeViet
- Found by: 0xGunrunner
- Disclosed: 2026-07-13
- CVE: CVE-2026-48118
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-mxpf-qgg6-v3ff
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-mxpf-qgg6-v3ff
- Tags: area:web domain:web impact:ato impact:data-leak kind:research platform:ghsa sev:high tech:php technique:chained technique:source-review vuln:xss

**Target:** Comment module (index.php comment_load endpoint, status_comment parameter)
**Root cause:** status_comment is filtered with strip_tags() while still base64-encoded, then decoded and rendered unescaped into the template; the checkss anti-forgery token is derived from static site-wide NV_CACHE_PREFIX instead of the session, making it reusable across users.
**Steps:**
1. Read the `checkss` value from the `data-checkss` attribute in the HTML of any article with a comment block.
2. Base64-encode an HTML/JS payload (e.g. a credential-phishing overlay).
3. Send the victim `https://<target>/index.php?language=vi&nv=comment&comment_load=1&module=news&area=<area>&id=<id>&allowed=<allowed>&checkss=<value_from_step_1>&status_comment=<base64_payload>`.
4. Decoded payload renders raw inside a `<div>` in the site origin; captured credentials are sent to the attacker server.
**How found:** Noticed the sanitizer (strip_tags via get_title) runs on the base64-encoded form, so its charset passes unchanged and the filter is useless post-decode; separately observed checkss was built from static NV_CACHE_PREFIX rather than NV_CHECK_SESSION, unlike modules/contact and modules/banners.
**Exploitation:** Attacker harvests the static checkss token from public HTML, base64-encodes a phishing overlay, and delivers a single crafted URL; the victim's browser decodes and renders it in-origin with access to cookies, session storage and authenticated requests. A phishing form was confirmed to exfiltrate plaintext credentials to an attacker-controlled server. No auth required; CSP's `script-src 'unsafe-inline'` does not block it.
**Escalation:** Chained the ineffective encoded-form filter with the session-independent checkss token to convert a reflected sink into a one-click, cross-user delivery vector.
**Insight:** When a parameter is base64-decoded server-side, check whether sanitization runs before or after decoding — filters on the encoded form are no-ops. Also diff token derivation across modules: a sibling module using session-bound NV_CHECK_SESSION reveals the vulnerable one using a static prefix.

## Proof of concept (copied exactly from the original report)

**Crafted URL delivering base64 XSS payload**

```
https://<target>/index.php?language=vi&nv=comment&comment_load=1
     &module=news&area=<area>&id=<id>&allowed=<allowed>
     &checkss=<value_from_step_1>
     &status_comment=<base64_payload>
```

**Static checkss token derivation formula**

```
checkss = md5(module + area + id + allowed + NV_CACHE_PREFIX)
```

