WordPress Security for Job Board Sites: Protecting Applicant Data
Secure your WordPress job board with strategies to protect applicant resumes, personal information, and employer data from breaches.
Job board websites handle sensitive personal information including resumes, contact details, work history, and salary expectations. Protecting this data requires comprehensive security measures tailored to recruitment platforms.
Job Board Security Challenges
Job sites face unique threats:
- Resume harvesting by data scrapers
- Fake job postings for phishing
- Account takeover of employer accounts
- Personal data theft targeting applicants
- Application injection through resume uploads
Sensitive Data Categories
Job boards typically store:
- Full names and contact information
- Home addresses and phone numbers
- Employment history and education
- Salary information and expectations
- References and their contact details
- Identification documents (in some cases)
Secure Resume Upload Handling
Resume uploads require strict validation:
function secure_resume_upload($file) {
$allowed_types = array('pdf', 'doc', 'docx');
$max_size = 5 * 1024 * 1024; // 5MB
$file_ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
if (!in_array($file_ext, $allowed_types)) {
return new WP_Error('invalid_type', 'Only PDF, DOC, and DOCX files allowed');
}
if ($file['size'] > $max_size) {
return new WP_Error('too_large', 'File exceeds 5MB limit');
}
// Verify MIME type matches extension
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
$valid_mimes = array(
'pdf' => 'application/pdf',
'doc' => 'application/msword',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
);
if ($mime !== $valid_mimes[$file_ext]) {
return new WP_Error('mime_mismatch', 'File content does not match extension');
}
return true;
}
Protected Resume Storage
Store resumes outside web-accessible directories:
function store_resume_securely($file, $applicant_id) {
$upload_dir = WP_CONTENT_DIR . '/private-resumes/';
if (!file_exists($upload_dir)) {
mkdir($upload_dir, 0750, true);
file_put_contents($upload_dir . '/.htaccess', 'deny from all');
}
$filename = $applicant_id . '_' . wp_generate_password(12, false) . '.' .
pathinfo($file['name'], PATHINFO_EXTENSION);
$destination = $upload_dir . $filename;
if (move_uploaded_file($file['tmp_name'], $destination)) {
return $filename;
}
return false;
}
Secure Resume Download
Serve resumes through PHP with access control:
function serve_resume($resume_id) {
if (!current_user_can('view_applications')) {
wp_die('Access denied');
}
$resume = get_resume_record($resume_id);
$filepath = WP_CONTENT_DIR . '/private-resumes/' . $resume['filename'];
if (!file_exists($filepath)) {
wp_die('File not found');
}
// Log access
log_resume_access($resume_id, get_current_user_id());
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="resume.pdf"');
header('Content-Length: ' . filesize($filepath));
readfile($filepath);
exit;
}
Employer Account Security
Protect employer accounts that access applicant data:
// Require strong passwords for employers
add_filter('wp_authenticate_user', function($user, $password) {
if (user_can($user, 'employer') && strlen($password) < 12) {
return new WP_Error(
'weak_password',
'Employer accounts require passwords of 12+ characters'
);
}
return $user;
}, 10, 2);
// Mandatory 2FA for employer accounts
add_action('wp_login', function($user_login, $user) {
if (user_can($user, 'employer') && !user_has_2fa($user->ID)) {
wp_redirect(admin_url('profile.php?setup_2fa=required'));
exit;
}
}, 10, 2);
Preventing Fake Job Postings
Verify employers before allowing job posts:
function verify_employer_posting($post_id, $post) {
if ($post->post_type !== 'job_listing') {
return;
}
$employer_id = $post->post_author;
$verified = get_user_meta($employer_id, 'employer_verified', true);
if (!$verified) {
wp_update_post(array(
'ID' => $post_id,
'post_status' => 'pending'
));
// Notify admin for review
wp_mail(
get_option('admin_email'),
'Unverified employer job submission',
'Review job post: ' . get_edit_post_link($post_id, '')
);
}
}
add_action('save_post', 'verify_employer_posting', 10, 2);
Applicant Privacy Controls
Give applicants control over their data:
// Profile visibility settings
function applicant_privacy_settings() {
$options = array(
'resume_visibility' => array(
'public' => 'Visible to all employers',
'applied' => 'Only employers I've applied to',
'hidden' => 'Completely hidden',
),
'contact_visibility' => array(
'always' => 'Show contact info',
'after_match' => 'After mutual interest',
'never' => 'Never show directly',
),
);
return $options;
}
Data Retention Policies
Implement automatic data cleanup:
function cleanup_old_applications() {
global $wpdb;
// Delete applications older than 2 years
$cutoff = date('Y-m-d', strtotime('-2 years'));
$old_applications = $wpdb->get_col($wpdb->prepare(
"SELECT id FROM applications WHERE created_at < %s",
$cutoff
));
foreach ($old_applications as $app_id) {
delete_resume_file($app_id);
$wpdb->delete('applications', array('id' => $app_id));
}
}
add_action('wpfs_daily_cleanup', 'cleanup_old_applications');
Conclusion
Job board security requires protecting sensitive applicant data through secure uploads, access controls, employer verification, and privacy settings. Regular audits ensure ongoing protection of personal information.
Written by Sarah Chen
WP Folder Shield Team