Security Tip: Hide Sensitive Parameters from Stack Traces

[Tip#60] Stack traces are essential for debugging complex (and even simple) issues, but there is a risk that something sensitive might be exposed within your trace... Let's ensure that doesn't happen!

Security Tip: Hide Sensitive Parameters from Stack Traces

🕵️ Just a reminder that I only have one slot left in December for a Laravel Security Audit and Penetration Test - after that I’m booked until March, so get in quick for an audit before the end of the year!

Stack traces are incredibly useful debugging tools. They tell you exactly what methods were called in your app, making it trivial to step through exactly what happened leading up to an exception. While we all expect them to contain class, method, and function names, did you know they can also contain the values of attributes within the functions?

Consider this code:

function authorise(string $username, string $password)
    throw new Exception("Error!");

authorise('Gandalf', 'mellon');

It produces the following error when run:

$ php /tmp/example.php
PHP Fatal error:  Uncaught Exception: Error! in /tmp/example.php:5
Stack trace:
#0 /tmp/example.php(8): authorise('Gandalf', 'mellon')
#1 {main}
  thrown in /tmp/example.php on line 5

If you check the first line of the stack trace (the line starting with `#0`) you’ll see quite clearly both the username (“Gandalf”) and the password (“mellon”)! While this information can be incredibly helpful when debugging, it’s also a huge security risk.

We normally expect stack traces so only be accessible through our app logs, however it’s not that uncommon to find debug mode turned on1 on world-accessible apps. If this is the case, your parameters will be on public display. Even without that, your logs are sitting in plaintext on your server or sent off to some third-party collection system. This makes them incredibly vulnerable and is not a secure way to store sensitive information.

How tightly do you manage access to your logs? Who on your team can access them? What sensitive information could be included within your logs? What if the third-party log collector has a breach?

Now, at this point, some of you are probably wondering:
Why can’t I seeing parameters in my stack traces?

Well, it turns out that PHP has a `php.ini` setting, `zend.exception_ignore_args`, which excludes all arguments from stack traces. The setting was introduced in PHP 7.42, and is enabled by default on many configurations, including Laravel Forge.

Here’s how it appears on my Forge configuration:

; Allows to include or exclude arguments from stack traces generated for exceptions.
; In production, it is recommended to turn this setting on to prohibit the output
; of sensitive information in stack traces
; Default Value: Off
; Development Value: Off
; Production Value: On
zend.exception_ignore_args = On

So my advice here is quite simple: if you don’t need parameters in stack traces, make sure you’ve got this enabled.

There is a good chance you do, but it’s worth checking to make sure.

But wait, we’re not done…

If you do need parameters included in your stack traces, then PHP 8.2 introduces a new attribute: `#[\SensitiveParameter]` for you.

If we add this attribute to our code above:

function authorise(
    string $username, 
    #[\SensitiveParameter] string $password
) {
    throw new Exception("Error!");

authorise('Gandalf', 'mellon');

And then run the code:

$ php /tmp/example.php
PHP Fatal error:  Uncaught Exception: Error! in /tmp/example.php:5
Stack trace:
#0 /tmp/example.php(8): authorise('Gandalf', Object(SensitiveParameterValue))
#1 {main}
  thrown in /tmp/example.php on line 5

You’ll see the sensitive `$password` parameter is now excluded from the stack trace. 🎉

If you need parameters in your stack trace, check this one out!

There is more information about it in the RFC:

is touched, any weaknesses in dev code can’t be easily exploited.

Looking to learn more?
Security Tip #41: Safely Rendering JSON in Blade
▶️ In Depth #14: Securing Randomness Without Breaking Things

  1. For more about Debug Mode in World-Accessible Apps, checkout our last security tip.

    I actually started to write this tip first, but realised I hadn’t written about debug mode, so I went to write that one instead. Now a week later, I’m finishing this tip!