GHSA-W2W5-W2PW-R929

Vulnerability from github – Published: 2026-07-13 17:22 – Updated: 2026-07-13 17:22
VLAI
Summary
NukeViet: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Details

Summary

A stored cross-site scripting (XSS) vulnerability exists in NukeViet CMS versions 4.x through 4.5.08. A low-privileged authenticated user can store a JavaScript payload in their profile's display name fields. The payload executes in the browser of any visitor — including administrators — who clicks the Reply ("Answer") link on a comment posted by that user.

Affected Component

The {COMMENT.post_name} template variable is interpolated without JavaScript-context escaping into an inline onclick handler in both comment block positions:

  • themes/default/modules/comment/comment.tpl line 27 (top-level comments)
  • themes/default/modules/comment/comment.tpl line 64 (nested/reply comments)
onclick="nv_commment_feedback(event, {COMMENT.cid}, '{COMMENT.post_name}')"

Root Cause

The first_name and last_name profile fields are sanitized with HTML numeric character references ('', ((, )), //) via Request::_get_title() with $specialchars = true. This encoding is correct for plain HTML attribute and element contexts, but insufficient for a JavaScript string literal embedded inside an HTML attribute.

Browsers decode HTML entities in attribute values before the JavaScript engine parses the string. As a result, ' is decoded back to ', which terminates the JS string early and allows the remainder of the value to be executed as JavaScript.

The combined display name (nv_show_name_user(first_name, last_name)) is what reaches the template, giving an attacker up to ~200 encoded characters across both fields — sufficient for any practical payload.

Proof of Concept

Set first_name to the following value in profile settings (/index.php?nv=users&op=editinfo), then post any comment:

a');alert(document.domain);//

The value is stored as a');alert(document.domain);//.

When a visitor clicks the Reply link on the comment, the browser renders:

nv_commment_feedback(event, 1, 'a');alert(document.domain);// Tester')

causing alert(document.domain) to execute in the visitor's browser context.

A data-exfiltration variant (split across both name fields) navigates the victim's browser to an attacker-controlled URL carrying document.cookie as a query parameter. End-to-end verification was performed using a local listener.

Exploitation Conditions (default configuration)

Condition Default value Effect
captcha_area_comm 1 No CAPTCHA for logged-in users — payload delivery requires no CAPTCHA solve
auto_postcomm enabled Comments are published immediately without moderation
active_editinfo_censor 0 Profile edits take effect immediately without admin review
CSP script-src 'unsafe-inline' Inline onclick handlers execute normally

Any registered member can set the payload and post a comment with no additional steps.

If captcha_area_comm is set to 0, the name field of anonymous comments (modules/comment/funcs/post.php) is processed by the same get_title(..., 1) call, making exploitation possible without authentication.

Impact

An attacker with a regular user account can execute arbitrary JavaScript in the browser of any visitor who interacts with the Reply button on their comment, including site administrators.

Practical consequences include:

  • Privilege escalation via admin session hijacking — forging administrative actions (content modification, account manipulation) in the context of an authenticated admin.
  • Credential phishing — injecting a fake login form into the page.
  • Data exfiltration — reading page content and non-HttpOnly cookies.

Note: NukeViet session cookies carry the HttpOnly flag, so they are not directly readable via document.cookie; however, the above attack vectors remain fully viable.

Remediation

Preferred fix: Remove post_name from the inline handler entirely. Pass only cid to nv_commment_feedback and have the function retrieve the display name from the already-rendered DOM (e.g., the adjacent <strong class="cm_item"> element).

Alternative fix: If the value must be passed inline, encode it with json_encode($post_name) (PHP) so that the output is a properly escaped JavaScript string literal, not an HTML-entity-encoded one. HTML numeric character references must not be relied upon for JavaScript string escaping.

As a general note, the result of get_title(..., $specialchars=true) is safe for HTML element content and quoted HTML attribute values, but unsafe when placed inside a JavaScript string literal within an attribute. Other locations in the codebase using the same pattern should be audited.

Resources

  • OWASP: Cross Site Scripting Prevention — Rule 2: Attribute Encoding is Not Sufficient for JS Contexts
  • CWE-79: Improper Neutralization of Input During Web Page Generation
  • CWE-116: Improper Encoding or Escaping of Output
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c 4.5.09"
      },
      "package": {
        "ecosystem": "Packagist",
        "name": "nukeviet/nukeviet"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.6.00"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-49259"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-79"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-13T17:22:26Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "## Summary\n\nA stored cross-site scripting (XSS) vulnerability exists in NukeViet CMS versions 4.x through 4.5.08. A low-privileged authenticated user can store a JavaScript payload in their profile\u0027s display name fields. The payload executes in the browser of any visitor \u2014 including administrators \u2014 who clicks the **Reply** (\"Answer\") link on a comment posted by that user.\n\n## Affected Component\n\nThe `{COMMENT.post_name}` template variable is interpolated without JavaScript-context escaping into an inline `onclick` handler in both comment block positions:\n\n- `themes/default/modules/comment/comment.tpl` line 27 (top-level comments)\n- `themes/default/modules/comment/comment.tpl` line 64 (nested/reply comments)\n\n```html\nonclick=\"nv_commment_feedback(event, {COMMENT.cid}, \u0027{COMMENT.post_name}\u0027)\"\n```\n\n## Root Cause\n\nThe `first_name` and `last_name` profile fields are sanitized with HTML numeric character references (`\u0027` \u2192 `\u0026#039;`, `(` \u2192 `\u0026#40;`, `)` \u2192 `\u0026#41;`, `/` \u2192 `\u0026#x002F;`) via `Request::_get_title()` with `$specialchars = true`. This encoding is correct for plain HTML attribute and element contexts, but **insufficient for a JavaScript string literal embedded inside an HTML attribute**.\n\nBrowsers decode HTML entities in attribute values **before** the JavaScript engine parses the string. As a result, `\u0026#039;` is decoded back to `\u0027`, which terminates the JS string early and allows the remainder of the value to be executed as JavaScript.\n\nThe combined display name (`nv_show_name_user(first_name, last_name)`) is what reaches the template, giving an attacker up to ~200 encoded characters across both fields \u2014 sufficient for any practical payload.\n\n## Proof of Concept\n\nSet `first_name` to the following value in profile settings (`/index.php?nv=users\u0026op=editinfo`), then post any comment:\n\n```text\na\u0027);alert(document.domain);//\n```\n\nThe value is stored as `a\u0026#039;\u0026#41;;alert\u0026#40;document.domain\u0026#41;;\u0026#x002F;\u0026#x002F;`.\n\nWhen a visitor clicks the Reply link on the comment, the browser renders:\n\n```js\nnv_commment_feedback(event, 1, \u0027a\u0027);alert(document.domain);// Tester\u0027)\n```\n\ncausing `alert(document.domain)` to execute in the visitor\u0027s browser context.\n\nA data-exfiltration variant (split across both name fields) navigates the victim\u0027s browser to an attacker-controlled URL carrying `document.cookie` as a query parameter. End-to-end verification was performed using a local listener.\n\n## Exploitation Conditions (default configuration)\n\n| Condition | Default value | Effect |\n|---|---|---|\n| `captcha_area_comm` | `1` | No CAPTCHA for logged-in users \u2014 payload delivery requires no CAPTCHA solve |\n| `auto_postcomm` | enabled | Comments are published immediately without moderation |\n| `active_editinfo_censor` | `0` | Profile edits take effect immediately without admin review |\n| CSP `script-src` | `\u0027unsafe-inline\u0027` | Inline `onclick` handlers execute normally |\n\nAny registered member can set the payload and post a comment with no additional steps.\n\nIf `captcha_area_comm` is set to `0`, the `name` field of anonymous comments (`modules/comment/funcs/post.php`) is processed by the same `get_title(..., 1)` call, making exploitation possible without authentication.\n\n## Impact\n\nAn attacker with a regular user account can execute arbitrary JavaScript in the browser of any visitor who interacts with the Reply button on their comment, including site administrators.\n\nPractical consequences include:\n\n- **Privilege escalation via admin session hijacking** \u2014 forging administrative actions (content modification, account manipulation) in the context of an authenticated admin.\n- **Credential phishing** \u2014 injecting a fake login form into the page.\n- **Data exfiltration** \u2014 reading page content and non-`HttpOnly` cookies.\n\n\u003e Note: NukeViet session cookies carry the `HttpOnly` flag, so they are not directly readable via `document.cookie`; however, the above attack vectors remain fully viable.\n\n## Remediation\n\n**Preferred fix:** Remove `post_name` from the inline handler entirely. Pass only `cid` to `nv_commment_feedback` and have the function retrieve the display name from the already-rendered DOM (e.g., the adjacent `\u003cstrong class=\"cm_item\"\u003e` element).\n\n**Alternative fix:** If the value must be passed inline, encode it with `json_encode($post_name)` (PHP) so that the output is a properly escaped JavaScript string literal, not an HTML-entity-encoded one. HTML numeric character references must not be relied upon for JavaScript string escaping.\n\nAs a general note, the result of `get_title(..., $specialchars=true)` is safe for HTML element content and quoted HTML attribute values, but **unsafe when placed inside a JavaScript string literal within an attribute**. Other locations in the codebase using the same pattern should be audited.\n\n## Resources\n\n- OWASP: Cross Site Scripting Prevention \u2014 Rule 2: Attribute Encoding is Not Sufficient for JS Contexts\n- CWE-79: Improper Neutralization of Input During Web Page Generation\n- CWE-116: Improper Encoding or Escaping of Output",
  "id": "GHSA-w2w5-w2pw-r929",
  "modified": "2026-07-13T17:22:26Z",
  "published": "2026-07-13T17:22:26Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/nukeviet/nukeviet/security/advisories/GHSA-w2w5-w2pw-r929"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/nukeviet/nukeviet"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "NukeViet: Improper Neutralization of Input During Web Page Generation (\u0027Cross-site Scripting\u0027)"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…