Skip to main content
Signocore
// signocore toolkit docs

Security hardening

What Signocore Toolkit hardens by default: XML-RPC, security headers and the REST API media endpoint, plus feeds and automatic updates.

Signocore Toolkit hardens a site as soon as it is active. Some protections have a switch on Signocore Toolkit → Security, others are always on. This page covers what each one does and how to adjust it. Login protection and the hidden login page have their own page, Login protection, and SVG uploads are covered in Performance and media.

What is on by default

Protection Default Setting
XML-RPC logins switched off On XML-RPC in the Hardening card
Pingbacks refused Always on None
RSS feeds removed Off RSS Feeds in the Hardening card
REST API media endpoint restricted On Restrict WP Rest API, shown only when WooCommerce is active
Security headers Always on None, but you can override them
One generic error for failed logins Always on None
Your own automatic update rules Off Custom update management in the Automatic Updates card

XML-RPC

XML-RPC is an old interface that lets apps and services log in and publish remotely. It is also a common target for password guessing. XML-RPC, on by default, switches off every XML-RPC method that needs a login and removes the RSD link from the page head.

Leave it on unless a service you use publishes or manages the site over XML-RPC. Such services stop working while it is on.

Pingbacks are refused whatever the setting: the Toolkit removes the pingback methods from XML-RPC and the X-Pingback header from frontend pages.

RSS feeds

RSS Feeds ("Remove default RSS feeds") is off by default. When you turn it on:

  • Every feed address, including category, tag and comment feeds in RSS, RSS 2.0, Atom and RDF, redirects to the home page with a 301.
  • The feed links disappear from the page head.

Feed readers, newsletter tools that build emails from your feed, and other services that read it stop getting updates. Leave it off if anyone subscribes to your site.

REST API media endpoint

The WordPress REST API lists every file in the media library at /wp-json/wp/v2/media, including files you never linked anywhere. With the restriction on:

  • Visitors who are not logged in, and logged-in users who cannot edit posts, such as subscribers and customers, get a 403 response: "Access to the media endpoint is restricted."
  • Zip files and WooCommerce download files are left out of the endpoint's answers for everyone, so paid downloads cannot be found through it.

The rest of the REST API is not affected.

The Restrict WP Rest API switch appears in the Hardening card only when WooCommerce is active. On sites without WooCommerce, the restriction is always on and there is no setting to turn it off. Keep that in mind if an app or a headless frontend reads your media library without logging in.

Security headers

The Toolkit adds these HTTP headers to frontend pages. The admin area, the login page and REST API responses do not get them, and neither do files your web server serves directly, such as images.

Header Value When
Content-Security-Policy See below Unless the response already carries a Content-Security-Policy or Content-Security-Policy-Report-Only header
Strict-Transport-Security max-age=31536000; includeSubDomains When the site runs on HTTPS. Replaces any value set earlier in WordPress
Referrer-Policy strict-origin-when-cross-origin Unless the response already carries a Referrer-Policy header

The Content-Security-Policy is sent as one line, with the directives separated by semicolons:

default-src 'self'
base-uri 'self'
form-action 'self'
frame-ancestors 'self'
object-src 'none'
img-src 'self' https: data: blob:
font-src 'self' https: data:
media-src 'self' https: blob:
connect-src 'self' https:
script-src 'self' https: 'unsafe-inline'
style-src 'self' https: 'unsafe-inline'
frame-src https:
upgrade-insecure-requests

What the policy blocks

The policy allows scripts, styles, images, fonts and embeds from your own domain and from any HTTPS address, including inline scripts and styles. It blocks:

  • Code that uses eval(), because 'unsafe-eval' is not allowed. Google Tag Manager's Custom JavaScript variables and some page builders and script libraries need it.
  • Forms that submit to another domain, because of form-action 'self'. Examples are newsletter sign-up forms that post straight to an email marketing service, and payment forms that post to a payment provider.
  • Your pages inside frames on other domains, because of frame-ancestors 'self'.
  • Plain HTTP resources. upgrade-insecure-requests loads them over HTTPS, so a resource that only exists on HTTP fails.

When something is blocked, the browser console shows a Content Security Policy error that names the directive. Check pages with forms, maps, video and checkout after you activate the plugin.

Important: Strict-Transport-Security with includeSubDomains tells browsers to use HTTPS for your domain and every subdomain for one year, even after you remove the plugin. Before you run the Toolkit on an HTTPS site, make sure all subdomains, such as mail.example.com or shop.example.com, work over HTTPS, or change the header as shown below.

Override the headers

Adjust the headers with the signocore_toolkit_security_headers filter, from a child theme's functions.php or a must-use plugin. It runs just before WordPress sends the headers and receives the Content-Security-Policy, Strict-Transport-Security and Referrer-Policy headers of the page, keyed by header name. Change a value, add another header, or return an empty value or unset a key to drop that header.

Allow eval() for Google Tag Manager's Custom JavaScript variables, and let the site's forms post to a newsletter service:

add_filter('signocore_toolkit_security_headers', function (array $headers): array {
    if (isset($headers['Content-Security-Policy'])) {
        $headers['Content-Security-Policy'] = str_replace(
            ["script-src 'self' https: 'unsafe-inline'", "form-action 'self'"],
            ["script-src 'self' https: 'unsafe-inline' 'unsafe-eval'", "form-action 'self' https://newsletter.example.com"],
            $headers['Content-Security-Policy']
        );
    }

    return $headers;
});

HSTS without subdomains:

add_filter('signocore_toolkit_security_headers', function (array $headers): array {
    if (isset($headers['Strict-Transport-Security'])) {
        $headers['Strict-Transport-Security'] = 'max-age=31536000';
    }

    return $headers;
});

To drop the Toolkit's policy altogether, use unset($headers['Content-Security-Policy']); in the same filter.

To send a policy of your own instead, set Content-Security-Policy in a WordPress wp_headers callback at a priority below 10. The Toolkit sees that the header is already there and leaves it alone, and the same goes for Referrer-Policy. To try a policy without enforcing it, set Content-Security-Policy-Report-Only that way. The Toolkit then sends no policy of its own, and the browser console reports what the new policy would block.

Note: Headers that your web server, host or CDN adds are not visible to WordPress, so the Toolkit still sends its own. If both send a Content-Security-Policy, browsers enforce both, and a resource must pass each of them. Keep the policy in one place.

Other protections without a setting

  • Generic login errors: a failed login shows "Invalid login credentials." instead of saying whether the username or the password was wrong.
  • Emoji scripts: WordPress's emoji detection script and styles are removed from the frontend and embeds, and emoji in feeds and emails are no longer swapped for images. Emoji still show, drawn by the visitor's own device.
  • oEmbed and REST discovery: the oEmbed discovery links and the REST API links in the page head and HTTP headers are removed, so other sites that look for those links no longer show your posts as embedded cards. Your site's oEmbed endpoints stay, because the block editor's Embed block uses them for its previews, and WordPress keeps cleaning the HTML that embed providers return.
  • Heartbeat: the heartbeat script is removed from the frontend.
  • Core update emails: WordPress only emails you about an automatic core update when it fails.

Automatic updates

With Custom update management off, which is the default, WordPress handles automatic updates as usual. Turn it on to set your own rules in the Automatic Updates card:

Setting Default What it updates automatically
WordPress Core (minor) On Maintenance and security releases of WordPress
WordPress Core (major) Off New feature versions of WordPress
Plugins On All plugins
Themes On All themes
Translations On Translation files

These rules apply to all plugins and themes at once and take precedence over the auto-update choices you make for single plugins and themes on the Plugins and Themes screens.

Stuck on something the docs don't cover?

Questions go straight to the developer who builds the plugins. Replies usually within a day.

September Sale

€20 off Signocore SEO Pro

Pay €49 instead of €69, one time for unlimited sites. code SEP20