Drupal Injection Security Standards (OWASP A03:2021)
Source: Ivan Grynenko - drupal-injection.mdc Author: Ivan Grynenko License: MIT OWASP Reference: OWASP A03:2021
Full Documentation
View online: https://github.com/ivangrynenko/cursorrules/blob/main/.cursor/rules/drupal-injection.mdc
This security pattern covers:
- OWASP Top 10 classification
- Common vulnerabilities and anti-patterns
- Enforcement checks for code review
- Secure coding examples
- Best practices and remediation
Raw Content
---
description: Detect and prevent injection vulnerabilities in Drupal as defined in OWASP Top 10:2021-A03
globs: *.php, *.inc, *.module, *.install, *.info.yml, *.theme, **/modules/**, **/themes/**, **/profiles/**
alwaysApply: false
---
# Drupal Injection Security Standards (OWASP A03:2021)
This rule enforces security best practices to prevent injection vulnerabilities in Drupal applications, as defined in OWASP Top 10:2021-A03.
## Rule Details
- **Name:** drupal_injection
- **Description:** Detect and prevent injection vulnerabilities in Drupal as defined in OWASP Top 10:2021-A03
## Filters
- file extension pattern: `\\.(php|inc|module|install|theme)$`
- file path pattern: `(modules|themes|profiles|core)/.*`
## Enforcement Checks
- Conditions:
- pattern `db_query\\(['\"][^'\"]*\\$[^'\"]*['\"]` – Direct variables in SQL queries are vulnerable to SQL injection. Use parameterized queries with placeholders.
- Pattern 1: Raw SQL queries without placeholders
- pattern `->query\\(['\"][^'\"]*\\$[^'\"]*['\"]` – Use parameterized queries with placeholders to prevent SQL injection: ->query($sql, [$param1, $param2]).
- Pattern 2: Modern DB API without placeholders
- pattern `<?=|<?php\\s+echo\\s+(?!(t|\\\\t|\\$this->t))[^;]*;` – Direct output may lead to XSS. Use t(), escaped variables with Html::escape(), or Twig templates.
- Pattern 3: Unescaped output
- pattern `[\"']#markup[\"']\\s*=>\\s*(?!t\\(|\\\\t\\(|Xss::filterAdmin|Html::escape)\\$` – Never use unfiltered variables in #markup. Use t(), Xss::filterAdmin(), or Html::escape().
- Pattern 4: Unfiltered user input in render arrays
- pattern `->addJsSettings\\(\\[(?![^\\]]*(Xss::filter|Json::encode))\\$` – Filter variables before adding to JavaScript settings using Xss::filter() or properly encode with Json::encode().
- Pattern 5: Unescaped variables in JavaScript settings
- pattern `exec\\(|shell_exec\\(|system\\(|passthru\\(|proc_open\\(|popen\\(|`` – Command execution functions can lead to command injection. Use Symfony\Component\Process\Process if necessary.
- Pattern 6: Direct command execution
- pattern `->redirect\\(\\s*\\$(?!(this->|allowed_destinations|config))` – Unvalidated redirects can lead to open redirect vulnerabilities. Whitelist allowed destinations.
- Pattern 7: Unvalidated redirect
- pattern `->condition\\([^,]*,\\s*\\$(?!(this->|config|entity|storage))[^,]*,` – Use proper input validation before using variables in database conditions to prevent SQL injection.
- Pattern 8: Raw user input in conditions
- pattern `(?<!buildForm|getFormId)\\s*function\\s+[a-zA-Z0-9_]+Form\\s*\\([^{]*\\{[^}]*return\\s+\\$form;(?![^}]*FormBuilderInterface|[^}]*::TOKEN|[^}]*#token)` – Form submissions must include CSRF protection with $form['#token'].
- Pattern 9: Missing CSRF protection in forms
- pattern `file_get_contents\\(\\s*\\$(?!(this->|allowed_paths|config))` – Validate file paths before operations to prevent path traversal attacks.
- Pattern 10: Unvalidated file operations
## Suggestions
- Guidance:
**Drupal Injection Prevention Best Practices:**
1. **SQL Injection Prevention:**
- Always use parameterized queries with placeholders
- Use the Database API's condition methods: ->condition(), ->where()
- Properly escape table and field names with {}
- Consider using EntityQuery for entity operations
2. **XSS Prevention:**
- Use Drupal's t() function for user-visible strings
- Apply appropriate filtering: Html::escape(), Xss::filter(), Xss::filterAdmin()
- Use #plain_text instead of #markup when displaying user input
- Utilize Twig's automatic escaping in templates
- For admin UIs, be careful with Xss::filterAdmin() as it allows some tags
3. **CSRF Protection:**
- Always include form tokens with $form['#token']
- Validate form tokens with FormState->validateToken()
- For AJAX requests, utilize Drupal's ajax framework
- Use drupal_valid_token() for custom validation
4. **Command Injection Prevention:**
- Avoid command execution functions entirely
- Use Symfony\Component\Process\Process with escaped arguments
- Validate and whitelist any input used in command contexts
5. **Path Traversal Prevention:**
- Validate file paths with FileSystem::validatedLocalFileSystem()
- Use stream wrappers (public://, private://) instead of direct paths
- Implement strict input validation for any path components
## Validation Checks
- Conditions:
- pattern `->query\\(['\"][^'\"]*\\?[^'\"]*['\"],\\s*\\[[^\\]]*\\]\\)` – Properly using parameterized queries with placeholders.
- Check 1: Proper SQL query usage
- pattern `(t\\(|Xss::filter|Html::escape|#plain_text)` – Using proper XSS prevention techniques.
- Check 2: Proper XSS prevention
- pattern `#token|FormBuilderInterface::TOKEN|drupal_valid_token` – Implementing CSRF protection correctly.
- Check 3: Proper CSRF protection
- pattern `FileSystem::validatedLocalFileSystem|file_exists\\(\\s*DRUPAL_ROOT` – Using safe file operation practices.
- Check 4: Safe file operations
## Metadata
- Priority: high
- Version: 1.1
- Tags: security, drupal, injection, sql, xss, csrf, owasp, language:php, framework:drupal, category:security, subcategory:injection, standard:owasp-top10, risk:a03-injection
## References
- https://owasp.org/Top10/A03_2021-Injection/
- https://www.drupal.org/docs/security-in-drupal/writing-secure-code-for-drupal
- https://www.drupal.org/docs/8/security/drupal-8-sanitizing-output
- https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Component%21Utility%21Xss.php/class/Xss/9
Last verified: 2025-10-31