Docs / Remediation guide
Every finding in your dashboard includes a one-line suggested fix. This page goes deeper — the actual implementation options for each kind of finding, not just the command.
Missing headers are the single most common finding, and can be fixed in three different places depending on how the site is actually deployed — pick whichever matches your setup, you only need one.
OPTION A — AT THE CDN/EDGEIf the site sits behind a CDN (Cloudflare, Fastly, etc.), this is usually the best option — it works even when the origin server's own config is hard to change. In Cloudflare: Rules → Transform Rules → Modify Response Header, or their newer Snippets feature for more control. No application code changes needed.
OPTION B — AT THE WEB SERVERApplies to every request regardless of what the application does — a good single place to set this once.
Nginx:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;" always;
Apache (.htaccess or vhost):
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" Header always set X-Frame-Options "SAMEORIGIN" Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "strict-origin-when-cross-origin"OPTION C — INSIDE DRUPAL
Install the Security Kit (seckit) contrib module. It adds a UI at /admin/config/system/seckit covering all of these, including CSP — useful when you don't control the web server layer directly, which is common when hosting is managed by someone else.
A note on Content-Security-Policy specifically: don't jump straight to enforcing it. Ship it as Content-Security-Policy-Report-Only first, point report-uri/report-to somewhere you can actually see the reports, and watch for a week or two what it would have blocked — inline scripts, third-party widgets, tag managers — before switching to the real enforcing header. Going straight to enforcing is the most common way this breaks a production site.
A publicly reachable .git directory, .env file, or composer.lock is a deploy-process problem, not a code problem — the fix is making sure these never reach the webroot in the first place.
.git exposed — the deploy process is copying the whole repository, including .git/, into the web-served directory. Fix the deploy step to exclude it, or better, deploy from a build artifact that never contains it at all..env exposed — same root cause. Also confirm the web server explicitly denies dotfiles:
location ~ /\.(?!well-known) { deny all; }
composer.lock exposed — not sensitive on its own, but it hands an attacker your exact dependency versions for free. Block it explicitly alongside the dotfile rule above.Once the connector module is installed and a finding shows a confirmed version match, the finding itself gives you the exact upgrade command — but the full sequence that actually matters in practice:
composer require drupal/webform:^6.2.5drush updatedb -ydrush crA module flagged as unmaintained isn't necessarily vulnerable today, but it will never receive a security fix if one is needed later — there's no maintainer left to issue one. Options, in order of preference:
These findings only appear with the connector installed — they come from the site's actual role/permission configuration, not anything visible externally.
/admin/people/permissions. A permission like "Administer permissions" or "Execute PHP code" should never sit on a public-facing role./admin/config/development/logging or the relevant module's own settings page.