Security Tip: strip_tags() Won't Save You from XSS!

[Tip #98] XSS doesn't just hide in <script> tags - it sneaks in through HTML attributes, links, and even inline styles! Don't rely on functions like strip_tags() to keep you safe...

Security Tip: strip_tags() Won't Save You from XSS!
💡
We're digging into the weaknesses identified in the updated Laravel Security Audits Top 10 list for 2024. This week we're looking at #1 Cross-Site Scripting (XSS)! You can find all of the articles here.

Last we we talked about Being Intentional with Your Outputs to avoid Cross-Site Scripting (XSS) sneaking their way into your applications. This was also something I spent some time talking about on in my recent Laracon AU talk.

In response to this security tip, I had a great email from Christian Taylor who shared an XSS mistake he made a few years ago:

Years ago I built an app that displayed WYSIWYG content submitted by users. I knew the input couldn’t be escaped because it required HTML, however I thought I could safely sanitize the input using a PHP function like this:

{!! strip_tags($wysiwyg_content, '<p><a><h1><ul><ol><li><img>’) !!}

What I later realized is that allowing the <img> tag meant users could input something bad like: <img src=“x” onerror=“alert('pwnd')"> because I hadn’t considered that HTML attributes could also be dangerous.

The strip_tags() function is one of those PHP staples that's been around for ever. It does a great job of removing HTML tags from strings, leaving the ones you tell it to ignore, but in terms of security - it has a massive caveat... as Christian discovered.

Let's look at a quick example to demonstrate the issue:

> $text = "You <b>cannot</b> pass! <img src=x onerror=alert(1)>";

> strip_tags($text);
= "You cannot pass! "

> strip_tags($text, "<img><b>");
= "You <b>cannot</b> pass! <img src=x onerror=alert(1)>"

A lot of folks forget that HTML supports Javascript through more than just the <script> tags. It's also executed through event attributes like onclick and onerror, in link href attributes with the javascript: protocol, and even inline styles!

XSS is sneaky and likes to pop up in all sorts of unexpected places, so be intentional with your outputs and make sure the tools you're using are right for the job.

In the case of strip_tags(), we looked at different ways it can be used back in Is strip_tags() Secure?, and you should really consider escaping and/or sanitising your output with more robust tools than blindly using strip_tags().


If you found this security tip useful, subscribe to get weekly Security Tips straight to your inbox. Upgrade to a premium subscription for exclusive monthly In Depth articles, or drop a coin in the tip jar to show your support.

Looking for a Laravel Security Audit / Penetration Test, or a budget-friendly Security Review? Feel free to reach out! You can also connect with me on Bluesky, or other socials. And don’t miss Practical Laravel Security, my interactive course designed to boost your Laravel security skills.