# Drupal Security

> Drupal security for routes, controllers, forms, and queries. Add route permissions, access checks, CSRF protection, XSS prevention, SQL injection prevention, and secure file upload validation.

- **Type:** Skill
- **Install:** `agentstack add skill-edutrul-drupal-ai-drupal-security`
- **Verified:** Pending review
- **Seller:** [edutrul](https://agentstack.voostack.com/s/edutrul)
- **Installs:** 0
- **Category:** [Databases](https://agentstack.voostack.com/c/databases)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [edutrul](https://github.com/edutrul)
- **Source:** https://github.com/edutrul/drupal-ai/tree/main/.claude/skills/drupal-security
- **Website:** https://eduardotelaya.com/drupal-ai/

## Install

```sh
agentstack add skill-edutrul-drupal-ai-drupal-security
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Drupal Security

## Critical Security Patterns

### SQL Injection Prevention

**NEVER concatenate user input into queries:**

```php
// VULNERABLE - SQL injection
$query = "SELECT * FROM users WHERE name = '" . $name . "'";
$result = $connection->query($query);

// SAFE - parameterized query
$result = $connection->select('users', 'u')
  ->fields('u')
  ->condition('name', $name)
  ->execute();

// SAFE - placeholder
$result = $connection->query(
  'SELECT * FROM {users} WHERE name = :name',
  [':name' => $name]
);
```

### XSS Prevention

**Always escape output. Trust the render system:**

```php
// VULNERABLE - raw HTML output
return ['#markup' => $user_input];
return ['#markup' => '' . $title . ''];

// SAFE - plain text (auto-escaped)
return ['#plain_text' => $user_input];

// SAFE - use proper render elements
return [
  '#type' => 'html_tag',
  '#tag' => 'div',
  '#value' => $title,  // Escaped automatically
];

// SAFE - Twig auto-escapes
{{ variable }}  // Escaped
{{ variable|raw }}  // DANGEROUS - only for trusted HTML
```

**For admin-only content:**
```php
use Drupal\Component\Utility\Xss;

// Filter but allow safe HTML tags
$safe = Xss::filterAdmin($user_html);
```

Note: Never pass untrusted user input into `#markup`. Prefer `#plain_text`, Twig auto-escaping, or safe render elements.

### Access Control

**Always verify permissions:**

```php
// In routing.yml
my_module.admin:
  path: '/admin/my-module'
  requirements:
    _permission: 'administer my_module'  # Required!

// In code
if (!$this->currentUser->hasPermission('administer my_module')) {
  throw new AccessDeniedHttpException();
}

// Entity queries - check access!
$query = $this->entityTypeManager
  ->getStorage('node')
  ->getQuery()
  ->accessCheck(TRUE)  // CRITICAL - never FALSE unless intentional
  ->condition('type', 'article');
```

### CSRF Protection

Forms automatically include CSRF tokens. For custom AJAX:

```php
// Include token in AJAX requests
$build['#attached']['drupalSettings']['myModule']['token'] =
  \Drupal::csrfToken()->get('my_module_action');
```
Note: Prefer dependency injection over direct `\Drupal::service()` or `\Drupal::` calls in classes.

```php
// Validate in controller
if (!$this->csrfToken->validate($token, 'my_module_action')) {
  throw new AccessDeniedHttpException('Invalid token');
}
```

### File Upload Security

```php
$validators = [
  'file_validate_extensions' => ['pdf doc docx'],  // Whitelist extensions
  'file_validate_size' => [25600000],  // 25MB limit
  'FileSecurity' => [],  // Drupal 10.2+ - blocks dangerous files
];

// NEVER trust file extension alone - check MIME type
$file_mime = $file->getMimeType();
$allowed_mimes = ['application/pdf', 'application/msword'];
if (!in_array($file_mime, $allowed_mimes)) {
  // Reject file
}
```

### Sensitive Data

```php
// NEVER log sensitive data
$this->logger->info('User @user logged in', ['@user' => $username]);
// NOT: $this->logger->info('Login: ' . $username . ':' . $password);

// NEVER expose in error messages
throw new \Exception('Database error');  // Generic
// NOT: throw new \Exception('Query failed: ' . $query);

// Use environment variables for secrets
$api_key = getenv('MY_API_KEY');
// NOT: $api_key = 'hardcoded-secret-key';
```

## Red Flags to Watch For

When you see these patterns, **immediately warn**:

| Pattern | Risk | Fix |
|---------|------|-----|
| String concatenation in SQL | SQL injection | Use query builder |
| `#markup` with variables | XSS | Use `#plain_text` |
| `accessCheck(FALSE)` | Access bypass | Use `accessCheck(TRUE)` |
| Missing `_permission` in routes | Unauthorized access | Add permission |
| Custom controller with no access check | Unauthorized access | Add route permission or access callback |
| `{{ var\|raw }}` in Twig | XSS | Remove `\|raw` |
| Hardcoded passwords/keys | Credential exposure | Use env vars |
| `eval()` or `exec()` | Code injection | Avoid entirely |
| `unserialize()` on user data | Object injection | Use JSON |
| Missing CSRF validation in custom endpoints | CSRF attack | Validate token using csrf_token service |
| File upload without validation | Malicious file upload | Validate extension, size, and MIME type |
| Direct `\Drupal::` usage in classes | Hard to test / bad practice | Use dependency injection |
| Logging sensitive data | Information disclosure | Mask or avoid logging sensitive fields |

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [edutrul](https://github.com/edutrul)
- **Source:** [edutrul/drupal-ai](https://github.com/edutrul/drupal-ai)
- **License:** MIT
- **Homepage:** https://eduardotelaya.com/drupal-ai/

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** yes

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-edutrul-drupal-ai-drupal-security
- Seller: https://agentstack.voostack.com/s/edutrul
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
