Introduction
Error handling in production systems is often overlooked โ until something goes wrong. Recently, while testing a WordPress site running the Contact Form 7 plugin, I came across a scenario where a 500 Internal Server Error exposed much more than it should have. This blog walks through the finding, the root cause, and the lessons developers can take away โ all without revealing any sensitive details about the site in question.
1. The Test Setup
- Target technology: WordPress + Contact Form 7 (a very popular contact form plugin).
- Testing method: Using Burp Suite's Repeater to replay and tweak HTTP requests to the Contact Form 7 REST API endpoint.
- Goal: Observe how the form submission API behaves under various inputs.
2. The Request
The test request was a standard Contact Form 7 form submission over the REST API. It looked like this:
POST /wp-json/contact-form-7/v1/contact-forms/{form_id}/feedback HTTP/2
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary123
...
------WebKitFormBoundary123
Content-Disposition: form-data; name="email-666"
invalid_email_format
------WebKitFormBoundary123--
Nothing unusual โ just a malformed form submission to see how the server handled errors.
3. The Response
Instead of a clean validation error, the server returned:
HTTP/2 500 Internal Server Error
Content-Type: application/json
...
{
"code": "internal_server_error",
"message": "<p>There has been a critical error on this website...</p>",
"data": {
"status": 500,
"error": {
"type": 1,
"message": "Uncaught Error: Call to undefined function PHPMailer\\PHPMailer\\mail() ...",
"file": "/home/{username}/{domain}/wp-includes/PHPMailer/PHPMailer.php",
"line": 880
}
}
}
4. What's the Vulnerability?
The key issue wasn't the malformed input โ it was the way the server handled internal failures.
When PHPMailer tried to send email via mail()
, the function wasn't available in the hosting environment. That triggered a fatal error, and because debugging was left enabled, the full stack trace was disclosed.
The response revealed:
- Absolute server file paths.
- Hosting environment structure (e.g.,
/home/username/domain/
). - Plugin and dependency details (Contact Form 7, PHPMailer).
- PHP internals.
While this doesn't grant instant access, it gives attackers valuable reconnaissance data that could later be chained with other exploits.
5. Why Did This Happen?
Likely causes:
WP_DEBUG
left enabled in production.display_errors = On
in PHP instead of logging errors privately.- Misconfigured mail transport (disabled or missing
mail()
function). - Plugin not sanitizing error output before sending it back in JSON.
Conclusion
This wasn't an exotic zero-day exploit. It was a simple misconfiguration combined with poor error handling. Yet it demonstrates how easy it is for attackers to gather intelligence from something as basic as an error response.
If you run WordPress (or any web application), take a moment to confirm your error handling setup. Sometimes the biggest leaks come from the smallest mistakes.