---
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

 