← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2026-28299 · CWE-770 · Disclosed 2026-06-02

SolarWinds Web Help Desk is found to be affected by a denial-of-service vulnerability

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a fire alarm that can empty the building, not a master key that opens every room

CVE-2026-28299 is a SolarWinds Web Help Desk memory-exhaustion denial-of-service issue in WHD 2026.1 and all previous versions, fixed in WHD 2026.2. The published impact is straightforward: a remote attacker can send crafted traffic to the WHD web service and push the server into insufficient-memory conditions, crashing the application.

SolarWinds scored it HIGH 8.2, but that overstates real enterprise urgency. The bug is unauthenticated and network-reachable, which matters, but the practical outcome is usually service interruption of one application, not code execution or tenant/domain takeover; and Web Help Desk is an on-premises product that many enterprises keep internal, behind VPN, reverse proxy, or ACLs, which sharply narrows the exposed population.

"Remote and unauthenticated, yes—but this is mostly an app-crash bug in a usually non-public ITSM box."
02 · The Attack Path

3 steps from start to impact.

STEP 01

Reach the WHD web listener with a basic HTTP client

The attacker only needs network access to the Web Help Desk web interface, using nothing fancier than curl, Burp Suite, or a custom Python requests loop. This is the biggest real-world gate: if the WHD instance is not internet-exposed and is only reachable from inside, over VPN, or from a management segment, the vuln is already post-initial-access rather than an external-entry bug.
Conditions required:
  • Network path to the WHD web UI
  • Target runs SolarWinds Web Help Desk 2026.1 or earlier
  • WHD service is up and reachable over HTTP/HTTPS
Where this breaks in practice:
  • Many WHD deployments are internal-only because the product is self-hosted/on-premises
  • Reverse proxies, VPN requirements, IP allowlists, or admin-segment placement cut exposure hard
  • WAF/CDN/body-size limits may block some malformed or oversized requests before they hit WHD
Detection/coverage: External attack-surface scanners will find exposed WHD, but host-based vuln scanners need product/version detection rather than network banners alone.
STEP 02

Trigger resource exhaustion against the JVM-backed service

The attacker then sends repeated crafted requests intended to consume memory until the WHD process becomes unstable or exits. SolarWinds' own description points to insufficient memory as the failure mode, and the system requirements note WHD's backend JVM defaults to -Xmx1024m, which gives an attacker a finite memory ceiling to push against.
Conditions required:
  • The vulnerable request path is reachable without authentication
  • The target has enough request throughput available to sustain pressure
  • No upstream control rate-limits or rejects the abusive pattern
Where this breaks in practice:
  • No public exploit kit or broad PoC was easy to locate as of 2026-06-04
  • Rate limiting, reverse proxies, and request normalization can raise attacker cost
  • Heavier-sized deployments may have more RAM headroom than the minimum config
Detection/coverage: Watch for sudden request bursts to WHD followed by JVM heap pressure, OOM events, wrapper/service restarts, or sharp latency spikes in app monitoring.
STEP 03

Crash or destabilize the help desk service

Once memory pressure wins, the practical result is application outage: tickets stop flowing, web access fails, and technicians lose their console until the process restarts or an operator intervenes. In a single-instance deployment this is an immediate operational hit, but it is still usually bounded to the WHD host and service rather than becoming a wider infrastructure compromise.
Conditions required:
  • The target is single-instance or lacks resilient failover
  • Service restart automation does not fully mask the outage
  • The organization depends on WHD for live ticket intake
Where this breaks in practice:
  • Service managers often auto-restart crashed processes, shortening outage duration
  • Load balancers or standby nodes can dilute impact
  • Blast radius is primarily the help desk workflow, not domain-wide control
Detection/coverage: Synthetic monitoring, service-health alerts, Windows Event Log/systemd logs, and JVM crash/OOM telemetry should catch the failure quickly.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusAs of 2026-06-04, I found no direct evidence that CVE-2026-28299 itself is being exploited. Important nuance: Microsoft documented active exploitation of other internet-exposed SolarWinds WHD flaws in February 2026, which proves attackers watch this product line, but that is not evidence for this specific DoS CVE.
Proof-of-concept availabilityI found no obvious public GitHub PoC or weaponized exploit write-up for CVE-2026-28299 as of 2026-06-04. That is a real downward pressure on urgency for a DoS bug.
EPSS0.00059 from the user-supplied intel/NVD-linked ecosystem data, which is extremely low and consistent with a fresh, non-weaponized application DoS.
KEV statusNot listed in CISA KEV as of 2026-06-04. CISA's catalog contains other SolarWinds Web Help Desk entries, but not this CVE.
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H = remote, low-complexity, no-auth, no-user-action. That baseline is why the vendor score starts high, but the published narrative still describes server crash from insufficient memory, so the business effect is much closer to availability outage than hostile takeover.
Affected versionsSolarWinds Web Help Desk 2026.1 and all previous versions per the vendor advisory.
Fixed versionSolarWinds Web Help Desk 2026.2. No distro-backport channel is relevant here because WHD is a vendor-distributed application, not an OS package maintained by RHEL/Ubuntu.
Exposure realityWHD is a self-hosted/on-premises product and SolarWinds says it runs entirely within customer infrastructure. That cuts both ways: some orgs expose it for external users, but many keep it internal or VPN-gated, which materially shrinks the reachable population.
Platform/architecture noteCurrent WHD supports Windows Server, RHEL/CentOS/Fedora, and macOS, so exposure is cross-platform. The 2026.2 documentation also notes the backend JVM defaults to -Xmx1024m, which aligns with the memory-exhaustion failure mode.
Disclosure and reporterPublished 2026-06-02. The advisory credits Tenable in acknowledgments, and NVD shows SolarWinds as the CVE source.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (5.6/10)

The decisive factor is blast radius: this is a remote unauthenticated bug, but the published effect is an application crash, not code execution or privilege gain. The second major downtick is exposure reality—WHD is an on-premises service that many enterprises do not publish broadly, so the reachable population is much smaller than a generic AV:N score implies.

HIGH Affected versions and fixed release
MEDIUM Real-world exploitability and exposure assumptions
MEDIUM Assessment that the vendor score overstates enterprise patch urgency

Why this verdict

  • Vendor baseline starts high because it is unauthenticated, network-reachable, and low-complexity.
  • First downgrade: impact is mostly service availability. The advisory describes a crash from insufficient memory, which is bad for operations but not equivalent to RCE or credential compromise.
  • Second downgrade: attacker position often requires exposure you may not have. If WHD is internal-only or VPN-gated, exploitation already assumes prior access or a trusted network foothold.
  • Third downgrade: exposed population is narrower than the CVSS vector suggests because WHD is an on-premises ticketing product, not a ubiquitous public SaaS edge service.
  • Fourth downgrade: no KEV and no clear public PoC as of 2026-06-04 reduce the odds this becomes a near-term mass exploitation event.
  • Small upward adjustment remains because service desk outages hurt incident intake, user support, and IT operations—especially in single-instance deployments.

Why not higher?

I am not taking this to HIGH or CRITICAL because the currently published outcome is denial of service, not remote execution, auth bypass, or data theft. Even where reachable, the blast radius is usually the WHD service itself, and many enterprises already reduce reachability by keeping WHD off the public internet.

Why not lower?

I am not dropping this to LOW because the bug is still remote and unauthenticated, and a help desk outage can meaningfully disrupt operations. If you knowingly expose WHD externally or run it as a single point of failure for support intake, the operational risk is real even without adversary code execution.

05 · Compensating Control

What to do — in priority order.

  1. Put WHD behind VPN or IP allowlists — If the service does not need public access, stop giving attackers step one. For a MEDIUM finding there is no noisgate mitigation SLA; do this in the next routine change window while you work toward patching within the 365-day remediation window.
  2. Rate-limit and size-limit upstream requests — Apply reverse-proxy, WAF, or load-balancer controls that cap abusive request rates and reject oversized or malformed bodies before they reach WHD. Again, there is no noisgate mitigation SLA here, so use normal change control unless the instance is externally exposed.
  3. Enable aggressive service-health monitoring — Alert on WHD process exits, JVM OOM conditions, wrapper restarts, and sustained memory growth so a crash becomes a short outage instead of a blind spot. This is especially valuable for single-instance service desks and should be folded into regular monitoring work while patching proceeds.
  4. Remove single-instance fragility where practical — If WHD is business-critical, add restart automation, standby capacity, or maintenance failover so one process crash does not become full ticketing paralysis. There is no noisgate mitigation SLA for MEDIUM, but externally reachable environments should still prioritize resilience sooner.
What doesn't work
  • Endpoint AV alone does not prevent a memory-exhaustion DoS; there may be no payload to catch.
  • MFA does not help when the published attack path is unauthenticated.
  • Credential rotation does not address this flaw because the issue is resource exhaustion, not account compromise.
  • Internal segmentation helps only if WHD is actually off the attacker path; once the app is reachable, segmentation does not stop the request pattern itself.
06 · Verification

Crowdsourced verification payload.

Run this on the target WHD host or from an auditor workstation with filesystem access to the WHD install directory. Invoke it as python3 whd_cve_2026_28299_check.py --root /opt/webhelpdesk on Linux/macOS or py whd_cve_2026_28299_check.py --root "C:\Program Files\WebHelpDesk" on Windows; it needs read access only, though elevated rights may help when reading Program Files or service-owned directories.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# CVE-2026-28299 local version check for SolarWinds Web Help Desk
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 1=vulnerable, 0=patched, 2=unknown

import argparse
import os
import platform
import re
import sys
from typing import List, Optional, Tuple

FIXED = (2026, 2)
VERSION_RE = re.compile(r'\b(20\d{2})\.(\d+)\b')
TEXT_EXTS = {'.txt', '.log', '.cfg', '.conf', '.ini', '.xml', '.json', '.properties', '.yml', '.yaml', '.html', '.htm', '.md'}
FILE_HINTS = {
    'version', 'release', 'readme', 'build', 'manifest', 'application.properties',
    'wrapper.conf', 'whd.env', 'package.json'
}


def normpath(p: str) -> str:
    return os.path.abspath(os.path.expanduser(p))


def default_roots() -> List[str]:
    system = platform.system().lower()
    roots = []
    if system == 'windows':
        roots.extend([
            r'C:\Program Files\WebHelpDesk',
            r'C:\Program Files\SolarWinds\WebHelpDesk',
            r'C:\Program Files (x86)\WebHelpDesk',
            r'C:\Program Files (x86)\SolarWinds\WebHelpDesk',
        ])
    elif system == 'darwin':
        roots.extend([
            '/Applications/WebHelpDesk.app/Contents/Resources',
            '/usr/local/webhelpdesk',
            '/opt/webhelpdesk',
            '/usr/local/solarwinds/webhelpdesk',
        ])
    else:
        roots.extend([
            '/opt/webhelpdesk',
            '/usr/local/webhelpdesk',
            '/opt/solarwinds/webhelpdesk',
            '/usr/local/solarwinds/webhelpdesk',
        ])
    return [r for r in roots if os.path.exists(r)]


def parse_version_tuple(s: str) -> Optional[Tuple[int, int]]:
    m = VERSION_RE.search(s)
    if not m:
        return None
    return int(m.group(1)), int(m.group(2))


def compare_versions(a: Tuple[int, int], b: Tuple[int, int]) -> int:
    return (a > b) - (a < b)


def should_read_file(path: str) -> bool:
    base = os.path.basename(path).lower()
    ext = os.path.splitext(base)[1].lower()
    if ext in TEXT_EXTS:
        return True
    return any(h in base for h in FILE_HINTS)


def candidate_files(root: str, max_depth: int = 3) -> List[str]:
    out = []
    root = normpath(root)
    for cur, dirs, files in os.walk(root):
        rel = os.path.relpath(cur, root)
        depth = 0 if rel == '.' else rel.count(os.sep) + 1
        if depth > max_depth:
            dirs[:] = []
            continue
        for name in files:
            p = os.path.join(cur, name)
            try:
                if should_read_file(p) and os.path.getsize(p) <= 2 * 1024 * 1024:
                    out.append(p)
            except OSError:
                pass
    return out


def extract_versions_from_file(path: str) -> List[Tuple[int, int, str]]:
    found = []
    try:
        with open(path, 'r', encoding='utf-8', errors='ignore') as f:
            data = f.read()
    except Exception:
        return found
    for m in VERSION_RE.finditer(data):
        year = int(m.group(1))
        minor = int(m.group(2))
        found.append((year, minor, path))
    return found


def assess_root(root: str) -> Tuple[str, str]:
    root = normpath(root)
    if not os.path.exists(root):
        return 'UNKNOWN', f'Path does not exist: {root}'

    versions = []
    for path in candidate_files(root):
        versions.extend(extract_versions_from_file(path))

    # Prefer explicit WHD 20xx.x style versions from nearby files
    versions = sorted(set(versions))
    if versions:
        # Choose the highest discovered version as the most likely installed version
        highest = max((v[:2] for v in versions), key=lambda x: (x[0], x[1]))
        evidence = [v for v in versions if v[0] == highest[0] and v[1] == highest[1]][:3]
        if compare_versions(highest, FIXED) >= 0:
            src = '; '.join(x[2] for x in evidence)
            return 'PATCHED', f'Detected WHD version {highest[0]}.{highest[1]} (evidence: {src})'
        else:
            src = '; '.join(x[2] for x in evidence)
            return 'VULNERABLE', f'Detected WHD version {highest[0]}.{highest[1]} which is earlier than 2026.2 (evidence: {src})'

    # Heuristic fallback: Caddy 2.11.1 presence strongly suggests 2026.2+, but keep UNKNOWN if no explicit WHD version found.
    caddy_hits = []
    for path in candidate_files(root, max_depth=4):
        try:
            with open(path, 'r', encoding='utf-8', errors='ignore') as f:
                sample = f.read(200000)
            if 'Caddy 2.11.1' in sample or 'caddy 2.11.1' in sample.lower():
                caddy_hits.append(path)
        except Exception:
            pass
    if caddy_hits:
        return 'UNKNOWN', 'Found references to Caddy 2.11.1, which aligns with WHD 2026.2 documentation, but no explicit installed WHD version string was located.'

    return 'UNKNOWN', 'Could not determine the installed WHD version from local files. Re-run with --root pointing to the exact WHD install directory.'


def main() -> int:
    parser = argparse.ArgumentParser(description='Check SolarWinds Web Help Desk for CVE-2026-28299 exposure by local version.')
    parser.add_argument('--root', action='append', help='WHD install root path. Can be supplied multiple times.')
    args = parser.parse_args()

    roots = [normpath(r) for r in (args.root or [])]
    if not roots:
        roots = default_roots()

    if not roots:
        print('UNKNOWN - No candidate WHD install paths found. Supply --root explicitly.')
        return 2

    overall = []
    for root in roots:
        status, detail = assess_root(root)
        overall.append((status, root, detail))

    # Precedence: VULNERABLE > PATCHED > UNKNOWN
    for status in ('VULNERABLE', 'PATCHED', 'UNKNOWN'):
        matches = [x for x in overall if x[0] == status]
        if matches:
            chosen = matches[0]
            print(f'{status} - {chosen[2]}')
            if status == 'VULNERABLE':
                return 1
            if status == 'PATCHED':
                return 0
            return 2

    print('UNKNOWN - Unexpected state')
    return 2


if __name__ == '__main__':
    sys.exit(main())
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, identify every SolarWinds Web Help Desk 2026.1 and earlier instance, confirm whether it is externally reachable, and queue an upgrade to 2026.2. For this MEDIUM reassessment there is no noisgate mitigation SLA — go straight to the 365-day remediation window, which puts the patch deadline at 2027-06-02 under the noisgate remediation SLA; that said, if any WHD system is internet-facing or single-instance for business-critical support intake, move access behind VPN/ACLs in your next normal change window and patch those exposed nodes earlier than the formal deadline.

Sources

  1. SolarWinds advisory for CVE-2026-28299
  2. NVD entry for CVE-2026-28299
  3. WHD 2026.2 system requirements
  4. WHD release history
  5. SolarWinds Web Help Desk pricing/deployment model
  6. Microsoft analysis of active exploitation of other WHD flaws
  7. CISA Known Exploited Vulnerabilities catalog
  8. SolarWinds WHD introduction
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.