Security
When to Use
Use this when handling user-generated content in components, passing data from untrusted sources, or working with attributes and HTML markup.
Decision
| Security Mechanism | Use Case | Why |
|---|---|---|
| Auto-escaping | All Twig output | Prevents XSS attacks by default |
| Attribute object | Dynamic attributes | Safe attribute value escaping |
| Props validation | User input in props | Prevents invalid data injection |
| Sanitization functions | User-generated content | Filter dangerous HTML tags |
Pattern
Auto-Escaping in Twig:
{# Auto-escaped by default #}
<h1>{{ title }}</h1> <!-- Safe: HTML entities encoded -->
{# Explicitly mark as safe (only for trusted markup) #}
<div>{{ content|raw }}</div> <!-- DANGER: No escaping -->
Attribute Object for Safe Handling:
{# Safe: Attribute object handles escaping #}
<div{{ attributes.addClass('my-class') }}>
{# DANGER: Manual attribute string concatenation #}
<div class="{{ classes }}"> <!-- Vulnerable to XSS -->
Props Validation:
props:
type: object
properties:
url:
type: string
format: uri
pattern: '^https?://'
email:
type: string
format: email
heading_level:
type: integer
enum: [1, 2, 3, 4, 5, 6]
Sanitizing User Input:
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\Xss;
$build = [
'#type' => 'component',
'#component' => 'my_theme:card',
'#props' => [
// Plain text: HTML escape
'title' => Html::escape($user_input),
// Allow limited HTML: filter tags
'description' => Xss::filter($user_input, ['p', 'br', 'strong', 'em']),
],
];
Common Mistakes
- Wrong: Using
|rawfilter on user-generated content → Right: Only use on trusted, pre-sanitized markup - Wrong: Building attributes as strings → Right: Use Attribute object for safe attribute handling
- Wrong: Not validating props with schema in development → Right: Always test with validation enabled