Laravel Security In Depth: Guessing Placeholders
[InDepth#4] Placeholders are incredibly useful, but you need to be careful with them.
One of the reasons I started this list was to analyse Laravel vulnerabilities as they are reported and fixed1. I find it incredibly valuable to understand how vulnerabilities work and how they are fixed, as it makes you consider your own code, and you’re reminded of it when you’ve building anything similar. Today’s Laravel Blade vulnerability is a perfect example of this - the fix is simple and very applicable to many similar situations.
In other news, I will be presenting the sequel to “Think Like a Hacker”2 at Laracon Online in February, with a whole new suite of vulnerabilities. The theme this time is: “What happens if a hacker breaks through your app, and gets to your server?”, and I’ll be exploring ways to prevent a single-app breach from become a catastrophic event. Please let me know if there are any vulnerabilities you’d like me to cover this time around!
Guessing Placeholders For Malicious Purposes
If you’re a developer, you would’ve encountered placeholders in some form or another. They are typically used in templates and reusable content, to inject dynamic content within a common context. Laravel uses them in various places, including Blade templates and language strings. It’s the use of system generated placeholders in Blade that lead to the recent ”Blade `
@parent` Exploitation Leading To Possible XSS” vulnerability in Laravel v8.74.0, which was reported by Kurita Takashi.
Let’s take a look at how that vulnerability worked.
Blade @parent Vulnerability
Security Advisory: https://github.com/laravel/framework/security/advisories/GHSA-66hf-2p6w-jqfw
Reported by: Kurita Takashi
When reading security advisories, I find it helpful to identify the key pieces of information. In this case, the vulnerability exposes a potential XSS attack vector3, through predicting placeholders with parent and child Blade templates.
The example code makes it trivial to reproduce, which I was able to do here to extract the cookie values:
But how does it actually work, why isn’t the output being escaped, and what can we do with it?
How Does It Work?
In an overly simplified way, this is what happens when Laravel renders blade templates: