Jobify Theme
Unauthenticated Arbitrary File Read
This blog post is about an unauthenticated arbitrary file read vulnerability on the Jobify theme. If you’re a Jobify user, please delete or deactivate the theme until the patch is released by the vendor.
All paid Patchstack users are protected from this vulnerability. Sign up for the free Community account first, to scan for vulnerabilities and apply protection for only $5 / site per month with Patchstack. For plugin developers, we have security audit services and Enterprise API for hosting companies.
About Jobify theme
The theme Jobify (premium version), which has over 14,000 sales, is one of the popular premium themes for quickly setting up a job board. It offers an easy way to setup the job listings and provide a user-friendly interface to apply for the jobs.
The security vulnerability
In the version 4.2.3 and below, the theme is vulnerable to an arbitrary file read vulnerability that allows any user to view all the contents of any file of the server running the WordPress site. Moreover, it is not only limited to file read, if the allow_url_fopen
is enabled in PHP, due to how the user-input is passed to a dangerous function, it is vulnerable to full-read SSRF allowing access to all the internally connected web servers as well. The vulnerability is still unpatched in the latest version and is tracked as the CVE-2024-52481.
Jobify Theme: Unauthenticated Arbitrary File Read
The underlying vulnerable code exists in the download_image_via_ai function:
add_action('wp_ajax_download_image', 'download_image_via_ai');
add_action('wp_ajax_nopriv_download_image', 'download_image_via_ai');
function download_image_via_ai() {
$image_url = $_POST['radioValue']; \\ [1]
$image_data = file_get_contents($image_url); \\ [2]
$image_base64 = base64_encode($image_data); \\ [3]
$filename = 'jobify_image_' . time() . '.jpg';
$upload_dir = wp_upload_dir();
$upload_path = $upload_dir['path'] . '/' . $filename;
file_put_contents($upload_path, base64_decode($image_base64)); \\ [4]
// Prepare the attachment data
$attachment = array(
'guid' => $upload_dir['url'] . '/' . $filename,
'post_mime_type' => 'image/jpeg',
'post_title' => 'Image Title',
'post_content' => 'Image Description',
'post_status' => 'inherit'
);
$attachment_id = wp_insert_attachment($attachment, $upload_path);
$attachment_data = wp_generate_attachment_metadata($attachment_id, $upload_path);
wp_update_attachment_metadata($attachment_id, $attachment_data);
$inside_image_uploaded_url = wp_get_attachment_url( $attachment_id );
echo $inside_image_uploaded_url; \\ [5]
die();
}
The above function is hooked to the wp_ajax_nopriv_download_image
action without any permission and nonce check. In [1], the $image_url
value is being retrieved from the 'radioValue'
which is controlled by the user. It then gets passed to file_get_contents()
function directly without any sanitization at all and stored in the $image_data
variable [2]. The response is base64 encoded and stored on yet another variable $image_base64
[3] which is then base64 decoded and uploaded to a file on WordPress [4]. After the file is uploaded, the URL of the created file is responded to the user [5].
When the user requests an arbitrary file, the server responds with a URL to an JPG file. However, the contents of the JPG file contains all the content of the arbitrary file that is requested. If, instead of absolute path, a HTTP URL is sent and allow_url_fopen is enabled in php.ini, it allows a full-read SSRF leading to accessing all the internal networks/servers. If the WordPress site is running on cloud like AWS or Azure, it can lead to the access of secret keys leading to full server compromise.
The patch
The vulnerability is still unpatched in the latest version 4.2.3 at the time of publishing this article. If/when the vendor patches the issue, we will update the article accordingly with the information on how it is patched.
Conclusion
Since the feature requires fetching remote images only, the usage of wp_safe_remote_get()
is secure and optimal without giving up any functionality. Alternatively, when using the file_get_contents()
function, it is necessary to ensure that no user-input is passed to the function. If needed to pass the user-input, the whole parameter should not be upto the user to pass. Only the filename should be allowed to be accessed whilst ensuring that it is sanitized properly to prevent accessing potentially sensitive files through path traversal.
Want to learn more about finding and fixing vulnerabilities?
Explore our Academy to master the art of finding and patching vulnerabilities within the WordPress ecosystem. Dive deep into detailed guides on various vulnerability types, from discovery tactics for researchers to robust fixes for developers. Join us and contribute to our growing knowledge base.
Timeline
Help us make the Internet a safer place
Making the WordPress ecosystem more secure is a team effort, and we believe that plugin developers and security researchers should work together.
- If you’re a plugin developer, join our mVDP program that makes it easier to report, manage and address vulnerabilities in your software.
- If you’re a security researcher, join Patchstack Alliance to report vulnerabilities & earn rewards.