Security is a never-ending journey. While Symfony takes security vulnerabilities seriously and follows a well-defined process for handling them, there's another category of improvements that doesn't get as much attention: security hardening.

These are changes that make Symfony safer by default, closing potential attack vectors and reducing the risk of misconfigurations. They're not CVE-worthy vulnerabilities, but they strengthen the framework's overall security posture.

Recent Hardening Improvements

These issues are handled as regular bug fixes rather than security advisories because they don't represent immediate exploitable vulnerabilities. However, they significantly improve Symfony's defense-in-depth strategy.

Signed Messages in Messenger

Nicolas Grekas
Contributed by Nicolas Grekas in #62230

One notable addition in Symfony 7.4 is the ability to sign messages per handler. If someone is able to inject a forged payload into your message queue, they could potentially trigger any handler, including sensitive ones like RunProcessHandler or RunCommandHandler.

While queues should always be protected from arbitrary payload injection, this new feature adds an extra layer of defense. Handlers can now opt into message signing via the sign attribute on the #[AsMessageHandler] attribute or the messenger.message_handler DependencyInjection tag.

When enabled, a SigningSerializer decorator computes a signature when encoding messages and verifies it when decoding. The RunProcessHandler and RunCommandHandler have this enabled by default.

Safer HTML Sanitizer Defaults

Nicolas Grekas
Contributed by Nicolas Grekas in #62201

The HtmlSanitizer component now removes srcdoc from allowed attributes by default. The srcdoc attribute on <iframe> elements can be dangerous because it allows embedding arbitrary HTML content. If you need to use it, you must now explicitly enable it, and we strongly recommend also forcing the sandbox attribute when doing so:

1
$sanitizer->forceAttribute('iframe', 'sandbox', '');

Stricter URL Parsing

Nicolas Grekas
Contributed by Nicolas Grekas in #62324

HttpFoundation now implements stricter parsing of URL hosts and schemes. This change aligns Symfony's URL interpretation more closely with the WHATWG URL Standard, helping close potential semantic gaps between different layers of your infrastructure. When your application and reverse proxy interpret URLs differently, security issues can arise.

Safer HTTP Method Override

Nicolas Grekas
Contributed by Nicolas Grekas in #61949 and #61979

HTTP method overriding (verb tunneling) was designed to let HTML forms submit requests using HTTP methods that browsers don't support natively, like PUT, PATCH, or DELETE. However, allowing override to methods like GET, HEAD, CONNECT, or TRACE was never necessary and could lead to security-sensitive situations.

Symfony 7.4 deprecates HTTP method override for these methods and introduces new configuration to control which methods can be overridden:

1
2
3
# config/packages/framework.yaml
framework:
    allowed_http_method_override: ['PUT', 'DELETE', 'PATCH']

You can also disable verb tunneling entirely by passing an empty array.

Improved CSRF Protection

Nicolas Grekas
Contributed by Nicolas Grekas in #62077

The SameOriginCsrfTokenManager now supports the Sec-Fetch-Site header for same-origin verification. This modern browser header provides a reliable way to verify request origin without needing to configure X-Forwarded-* headers when using a reverse proxy. Browser support is excellent across modern browsers.

Deprecating Ambiguous Input Access

Nicolas Grekas
Contributed by Nicolas Grekas in #61948

The Request::get() method has been deprecated in Symfony 7.4 because it blurs the origin of input data. This method searches across multiple input bags ($request->attributes, $request->query, $request->request), making it unclear where the data actually came from.

From a security perspective, knowing the exact source of user input is crucial. Use the specific properties directly instead:

1
2
3
4
5
6
7
// Before (ambiguous)
$value = $request->get('param');

// After (explicit)
$value = $request->query->get('param');      // GET parameter
$value = $request->request->get('param');    // POST parameter
$value = $request->attributes->get('param'); // Route parameter

Reporting Security Issues

If you discover a security vulnerability in Symfony, please do not use the public bug tracker or discuss it publicly. Instead, send your report to security [at] symfony.com. This email is forwarded to the Symfony core team's private mailing list.

We want to thank all community members who responsibly report security issues. We also thank the Symfony Core Team for their continued work on security improvements, and especially the members of the Symfony security team:

Stay Secure

Security is a shared responsibility. Keep your Symfony applications updated, follow security best practices, and use the check:security command to verify your dependencies don't have known vulnerabilities:

1
$ symfony check:security

For more details about our security process and severity scoring, check the full security policy in our documentation.

Published in #Symfony