• Resolved akgt

    (@akgt)


    im having issues with
    “HTTP → HTTPS redirect0/1

    The site is reachable over plain HTTP without a redirect to HTTPS”

    and Im getting the “Administrator login detected” email to my “Additional Recipients” email but not the email code for some reason.

Viewing 7 replies - 1 through 7 (of 7 total)
  • Plugin Author Fernando Tellado

    (@fernandot)

    Hi again @akgt 🙂

    Two separate things here, let me take them one at a time.

    HTTP -> HTTPS redirect: That check asks your own server for the plain http:// version of your home URL and passes only if the very first answer is a 3xx redirect whose Location starts with https://. It fails in a few cases that are not really a broken site: a two hop redirect (http://domain -> http://www.domain -> https://www.domain), a redirect done by a CDN at the edge (Cloudflare “Always Use HTTPS”), or a cached page served without running PHP.

    Could you run these two from any machine and paste the output?

    curl -I http://yourdomain.com/
    curl -I http://www.yourdomain.com/

    Also, do you use Cloudflare or a page cache plugin, and is “Force HTTPS” enabled in Vigilant under Headers? If your first Location line already points to an https:// URL, the site is fine and the probe is what needs fixing on my side.

    The 2FA code: This one is working as designed, the verification code is always sent to the email address of the account that is logging in, the one in your user profile, never to the Additional Recipients list. That list is only for administrative notices (admin login, scan results, alerts), and codes are deliberately kept out of it so a login secret never lands in a shared mailbox.

    One thing makes me think something else is going on, though. The “Administrator login detected” notice is sent on wp_login, which only fires once the login is fully completed. So if you get that email and you were never asked for a code, 2FA by email is not running for your account at all. Could you check: does the login screen ask you for a code? In Vigilant, under Login Security, is the 2FA method set to Email or to Authenticator app, and is your role included in the enforced roles? And what address does your own user profile have?

    Fernando

    Thread Starter akgt

    (@akgt)

    I’m not using Cloudflare at the moment, my site is loading as HTTPS, and redirects to https but its not detecting. im not using a cache plugin, and on most sites its working but not some new sites I’m working on, i’ve kept the setting the same. any setting to select or reinstall Really Simple Security again ?

    Hi Fernando,

    Regarding HTTP -> HTTPS redirect: I’m not using Cloudflare or a page cache plugin on these new sites. my settings https://ibb.co/0yms8P0v . The site loads fine via HTTPS in a browser, but when running curl on plain HTTP, the server returns a 403 Forbidden instead of a redirect.

    Here is the curl -I output:

    Plaintext

    HTTP/1.1 403 Forbidden
    Connection: Keep-Alive
    Keep-Alive: timeout=5, max=100
    Content-Type: text/html; charset=UTF-8
    Expires: Wed, 11 Jan 1984 05:00:00 GMT
    Cache-Control: no-cache, must-revalidate, max-age=0, no-store, private
    Date: Tue, 22 Sep 2026 21:41:22 GMT
    Vary: User-Agent
    X-Frame-Options: SAMEORIGIN
    X-Content-Type-Options: nosniff
    Referrer-Policy: strict-origin-when-cross-origin
    Strict-Transport-Security: max-age=31536000; includeSubDomains
    Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(self), usb=()
    Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https: blob:; font-src 'self' data: https:; connect-src 'self' https: wss: blob:; media-src 'self' https: blob:; frame-src 'self' https: blob:; frame-ancestors 'self'; base-uri 'self'; form-action 'self' https:; object-src 'none'; worker-src 'self' blob:; upgrade-insecure-requests
    Cross-Origin-Opener-Policy: same-origin-allow-popups
    Cross-Origin-Resource-Policy: cross-origin
    

    Regarding the 2FA Code: You were spot on! The user profile email address was set differently on these new sites. Once I updated my user profile email to match, the 2FA verification code emails started coming through right away. That part is now completely resolved.

    Thanks!

    Plugin Author Fernando Tellado

    (@fernandot)

    Good news on the 2FA side, and thanks for confirming it 🙂

    About the redirect check, that 403 is Vigilant itself, not your server. The firewall blocks the curl user agent as a bad bot, which is why the response carries all of Vigilant’s security headers: WordPress ran, the firewall stopped the request, and it never reached the redirect. So that output tells us nothing about whether your site redirects.

    Could you run these two instead, from any machine?

    curl -I -A 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36' http://yourdomain.com/
    curl -I -A 'Vigilant-Security-Analyzer/1.0' http://yourdomain.com/

    The second one uses the exact user agent the Security Check uses for its own probe, so the two together tell us which of these is happening:

    • Browser gets a 301 to https and the analyzer one gets 403 or 429: the firewall is blocking my own probe, the redirect works fine, and the fix belongs in the plugin.
    • Both get a 301: your site is fine and the probe fails only when it runs from the server itself.
    • Both get a 200: the redirect really is not happening on plain HTTP.

    Two more questions: is Really Simple Security still active alongside Vigilant, and do you also have “Force HTTPS” enabled in Vigilant under Headers? You only need one of the two doing the redirect. There is nothing to reinstall, and no setting to change while we find out which case this is.

    Either way, if your site loads over HTTPS in a browser, you are not exposed. That line is one point in the score and I would rather fix the check than have you change a working setup.

    Thanks!

    Fernando

    Thread Starter akgt

    (@akgt)

    Hi Fernando

    I’ve got the following results.

    HTTP/1.1 200 OK
    Connection: Keep-Alive
    Keep-Alive: timeout=5, max=100
    Content-Type: text/html; charset=UTF-8
    Expires: Wed, 11 Jan 1984 05:00:00 GMT
    Cache-Control: no-cache; private
    Date: Tue, 22 Sep 2026 22:16:38 GMT
    Vary: User-Agent
    X-Frame-Options: SAMEORIGIN
    X-Content-Type-Options: nosniff
    Referrer-Policy: strict-origin-when-cross-origin
    Strict-Transport-Security: max-age=31536000; includeSubDomains
    Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(self), usb=()
    Content-Security-Policy: default-src ‘self’; script-src ‘self’ ‘unsafe-inline’ ‘unsafe-eval’ https:; style-src ‘self’ ‘unsafe-inline’ https:; img-src ‘self’ data: https: blob:; font-src ‘self’ data: https:; connect-src ‘self’ https: wss: blob:; media-src ‘self’ https: blob:; frame-src ‘self’ https: blob:; frame-ancestors ‘self’; base-uri ‘self’; form-action ‘self’ https:; object-src ‘none’; worker-src ‘self’ blob:; upgrade-insecure-requests
    Cross-Origin-Opener-Policy: same-origin-allow-popups
    Cross-Origin-Resource-Policy: cross-origin

    HTTP/1.1 200 OK
    Connection: Keep-Alive
    Keep-Alive: timeout=5, max=100
    Content-Type: text/html; charset=UTF-8
    Expires: Wed, 11 Jan 1984 05:00:00 GMT
    Cache-Control: no-cache; private
    Date: Tue, 22 Sep 2026 22:17:46 GMT
    Vary: User-Agent
    X-Frame-Options: SAMEORIGIN
    X-Content-Type-Options: nosniff
    Referrer-Policy: strict-origin-when-cross-origin
    Strict-Transport-Security: max-age=31536000; includeSubDomains
    Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(self), usb=()
    Content-Security-Policy: default-src ‘self’; script-src ‘self’ ‘unsafe-inline’ ‘unsafe-eval’ https:; style-src ‘self’ ‘unsafe-inline’ https:; img-src ‘self’ data: https: blob:; font-src ‘self’ data: https:; connect-src ‘self’ https: wss: blob:; media-src ‘self’ https: blob:; frame-src ‘self’ https: blob:; frame-ancestors ‘self’; base-uri ‘self’; form-action ‘self’ https:; object-src ‘none’; worker-src ‘self’ blob:; upgrade-insecure-requests
    Cross-Origin-Opener-Policy: same-origin-allow-popups
    Cross-Origin-Resource-Policy: cross-origin.

    Im getting  301: on my other sites

    No, I dont use Really Simple Security

    Thanks

    Plugin Author Fernando Tellado

    (@fernandot)

    Thanks, that settles it: the check is right and this is not a false positive. Both requests, the browser one and the one with my analyzer’s user agent, came back 200 over plain HTTP. Your site really is answering on http:// without redirecting.

    Here is the interesting part. Your screenshot shows HSTS enabled with no red warning next to it, which means your WordPress Address is already an https:// one. On a site like that, WordPress redirects http to https all by itself through redirect_canonical(), with no plugin involved. So if neither WordPress nor Vigilant redirects, it is because PHP never sees an HTTP request: your host is terminating TLS in front of PHP and telling WordPress that every request is already HTTPS. Vigilant’s redirect checks is_ssl() first and steps aside when it says yes, which is exactly what is happening.

    That also explains why your other sites answer 301: different hosting setup, not different settings.

    To confirm it, I made you a small diagnostic file. Drop it in wp-content/mu-plugins/ via FTP and edit the VIGDBG_TOKEN line near the top first, putting any random word there. Then request, over plain HTTP:

    http://yourdomain.com/?vigdbg=YOUR-WORD

    <?php
    /**
    * Plugin Name: Vigilant Debug — HTTPS redirect
    * Description: Reports what PHP sees about the scheme of a plain HTTP request, so a site that answers 200 over http:// can be told apart from one whose host makes WordPress believe every request is already HTTPS. Temporary tool — delete the file via FTP when finished.
    * Version: 1.0.0
    * Author: Fernando Tellado
    * Requires at least: 6.2
    * Requires PHP: 7.4
    *
    * Drop this file in wp-content/mu-plugins/ via FTP. No activation needed.
    * Then request, over plain HTTP:
    *
    * http://yourdomain.com/?vigdbg=TOKEN
    *
    * replacing TOKEN with the value of VIGDBG_TOKEN below. Copy the whole answer.
    * Delete the file from FTP when you're done.
    *
    * @package Vigilante
    */

    if ( ! defined( 'ABSPATH' ) ) {
    exit;
    }

    // Change this before sending the file to anyone. The report is plain text and
    // says nothing secret, but a token keeps it out of crawlers and scanners.
    define( 'VIGDBG_TOKEN', 'YOUR-WORD' );

    /**
    * True when this request asked for the report.
    *
    * @return bool
    */
    function vigdbg_requested() {
    if ( empty( $_GET['vigdbg'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only diagnostic, gated by the token below.
    return false;
    }
    $given = sanitize_text_field( wp_unslash( $_GET['vigdbg'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Same read-only diagnostic.
    return hash_equals( VIGDBG_TOKEN, $given );
    }

    /**
    * Print the report and stop.
    *
    * Hooked at template_redirect priority 0, one step before Vigilant's own
    * redirect (priority 1). Reaching this point proves the request got as far as
    * template_redirect, so a missing redirect is a decision and not a page served
    * by something earlier.
    */
    function vigdbg_report() {
    if ( ! vigdbg_requested() ) {
    return;
    }

    $server = array();
    foreach ( array( 'HTTPS', 'SERVER_PORT', 'REQUEST_SCHEME', 'HTTP_HOST', 'SERVER_NAME', 'HTTP_X_FORWARDED_PROTO', 'HTTP_X_FORWARDED_SSL', 'HTTP_X_FORWARDED_PORT', 'HTTP_CF_VISITOR', 'HTTP_FRONT_END_HTTPS', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR', 'SERVER_SOFTWARE' ) as $key ) {
    $server[ $key ] = isset( $_SERVER[ $key ] ) ? sanitize_text_field( wp_unslash( $_SERVER[ $key ] ) ) : '(not set)';
    }

    $options = get_option( 'vigilante_options', array() );
    $headers = isset( $options['security_headers'] ) ? $options['security_headers'] : array();
    $modules = isset( $options['modules'] ) ? $options['modules'] : array();

    $lines = array();
    $lines[] = '=== Vigilant HTTPS redirect diagnostic ===';
    $lines[] = '';
    $lines[] = '-- What PHP thinks of this request --';
    $lines[] = 'is_ssl() : ' . ( is_ssl() ? 'TRUE' : 'false' );
    foreach ( $server as $key => $value ) {
    $lines[] = str_pad( $key, 26 ) . ': ' . $value;
    }
    $lines[] = '';
    $lines[] = '-- What the site declares --';
    $lines[] = 'home option : ' . get_option( 'home' );
    $lines[] = 'siteurl option : ' . get_option( 'siteurl' );
    $lines[] = 'WP_HOME constant : ' . ( defined( 'WP_HOME' ) ? WP_HOME : '(not defined)' );
    $lines[] = 'WP_SITEURL constant : ' . ( defined( 'WP_SITEURL' ) ? WP_SITEURL : '(not defined)' );
    $lines[] = 'FORCE_SSL_ADMIN : ' . ( defined( 'FORCE_SSL_ADMIN' ) ? ( FORCE_SSL_ADMIN ? 'true' : 'false' ) : '(not defined)' );
    $lines[] = '';
    $lines[] = '-- Vigilant settings that govern the redirect --';
    $lines[] = 'security_headers.enabled : ' . ( ! empty( $headers['enabled'] ) ? 'on' : 'OFF' );
    $lines[] = 'redirect_http_to_https : ' . ( ! empty( $headers['redirect_http_to_https'] ) ? 'on' : 'OFF' );
    $lines[] = 'modules.security_headers : ' . ( isset( $modules['security_headers'] ) ? ( $modules['security_headers'] ? 'on' : 'OFF' ) : '(key absent)' );
    $lines[] = 'enforcer hook registered : ' . ( has_action( 'template_redirect' ) ? 'template_redirect has ' . count( $GLOBALS['wp_filter']['template_redirect']->callbacks ) . ' priority levels' : 'no callbacks' );
    $lines[] = '';
    $lines[] = '-- Anything serving pages before WordPress --';
    $lines[] = 'WP_CACHE : ' . ( defined( 'WP_CACHE' ) ? ( WP_CACHE ? 'true' : 'false' ) : '(not defined)' );
    $lines[] = 'advanced-cache.php : ' . ( file_exists( WP_CONTENT_DIR . '/advanced-cache.php' ) ? 'present' : 'absent' );
    $lines[] = 'object-cache.php : ' . ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ? 'present' : 'absent' );
    $lines[] = '';
    $lines[] = '-- Reading --';
    $lines[] = 'If is_ssl() says TRUE on this plain HTTP request, that is the answer: your host';
    $lines[] = 'terminates TLS in front of PHP and tells WordPress every request is already';
    $lines[] = 'HTTPS, so neither WordPress nor Vigilant ever sees an HTTP request to redirect.';
    $lines[] = '';
    $lines[] = 'Delete this file from wp-content/mu-plugins/ when you are done.';

    nocache_headers();
    header( 'Content-Type: text/plain; charset=utf-8' );
    echo esc_html( implode( "\n", $lines ) );
    exit;
    }
    add_action( 'template_redirect', 'vigdbg_report', 0 );

    Paste the answer here. If the first line says is_ssl() TRUE, that is the whole story. Delete the file from FTP afterwards.

    If it does confirm it, the redirect has to be done by the server, because PHP cannot see the difference. The safest route is your hosting panel: most have a “Force HTTPS” switch that does it at the server level. Failing that, this at the very top of your .htaccess, above the WordPress block:

    <IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTP:X-Forwarded-Proto} !https
    RewriteCond %{HTTPS} !=on
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    </IfModule>

    Test it in a private window and keep your FTP client open while you do. If your proxy does not send X-Forwarded-Proto at all, that rule can loop, and you want to be able to undo it.

    And thanks for the report, because there is something for me to fix here too: when that checkbox is ticked and the server never lets PHP see an HTTP request, Vigilant should say so on screen instead of leaving you with a checkbox that looks enabled and a score line that says 0/1.

    Fernando

    Plugin Author Fernando Tellado

    (@fernandot)

    Hi @akgt

    Any news?

    Plugin Author Fernando Tellado

    (@fernandot)

    Since there hasn’t been a response for several days, I have to assume the issue has been addressed, so I’m marking the thread as resolved.

Viewing 7 replies - 1 through 7 (of 7 total)

You must be logged in to reply to this topic.