Architecture Report March 1, 2026

Drupal 11 Security: Hardening Decoupled Architectures

AS
Andrei Sandu
Drupal Architect & Security Researcher

As the landscape of web development shifts towards Decoupled Architecture, the traditional security model of Drupal—long considered one of its strongest features—must be fundamentally reimagined.

In a monolithic setup, Drupal manages the entire request lifecycle, from session cookies to output filtering. In a decoupled environment, Drupal acts as a headless API provider, communicating over stateless protocols. This transition shifts the focus from Cross-Site Scripting (XSS) and CSRF in the frontend to API Authentication and Broken Object Level Authorization (BOLA) in the backend.

1. Implementing OAuth2 with Simple OAuth

The simple_oauth module is the industry standard for securing Drupal APIs. However, simply enabling it is not enough. You must configure secure token storage and enforce strict scope validation.

drupal/settings.php
// Enforce secure OAuth2 configuration
$settings['simple_oauth.private_key'] = '../keys/private.key';
$settings['simple_oauth.public_key'] = '../keys/public.key';

// Ensure your keys are stored OUTSIDE the web root
if (file_exists($settings['simple_oauth.private_key'])) {
    chmod($settings['simple_oauth.private_key'], 0600);
}

2. Hardening JSON:API Endpoints

By default, jsonapi exposes all entities. For a production-ready decoupled app, you should follow the Principle of Least Privilege. Use the jsonapi_extras module to disable every resource that isn't explicitly required by your frontend.

Furthermore, ensure that you are not leaking user information via the /user/user resource. In most decoupled apps, you should disable access to the user index entirely and only allow GET requests on the individual's own profile.

3. The CORS Challenge

CORS is not a security feature—it is a relaxation of the Same-Origin Policy. Misconfiguring it can open your API to unauthorized cross-origin requests. Never use wildcards in production.

drupal/services.yml
parameters:
  cors.config:
    enabled: true
    allowedHeaders: ['Content-Type', 'Authorization']
    allowedMethods: ['POST', 'GET', 'OPTIONS']
    allowedOrigins: ['https://frontend.andreisandu.net']
    exposedHeaders: []
    maxAge: 3600

Conclusion: Continuous Scanning

Security is not a checkbox; it's a constant process. Integrating automated vulnerability scanners (like the CyberHygiene Scanner I am currently building) into your CI/CD pipeline ensures that configuration drifts and new vulnerabilities are caught before they reach production.

In the next post, I will dive deep into Penetration Testing Drupal Modules and how to identify common logical flaws in custom entity access handlers.