<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Matteo Cisilino</title>
	<atom:link href="https://www.cisilino.com/en/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.cisilino.com/en/</link>
	<description>Guide su WordPress, server e sicurezza</description>
	<lastBuildDate>Sat, 31 Oct 2026 10:03:49 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.4</generator>
	<item>
		<title>Database credential rotation after an ISPConfig breach</title>
		<link>https://www.cisilino.com/en/2026/10/31/database-credential-rotation-ispconfig-breach/</link>
					<comments>https://www.cisilino.com/en/2026/10/31/database-credential-rotation-ispconfig-breach/#respond</comments>
		
		<dc:creator><![CDATA[matteocisilino]]></dc:creator>
		<pubDate>Sat, 31 Oct 2026 10:03:56 +0000</pubDate>
				<category><![CDATA[Servers and databases]]></category>
		<category><![CDATA[bash script]]></category>
		<category><![CDATA[credential rotation]]></category>
		<category><![CDATA[incident response]]></category>
		<category><![CDATA[ISPConfig]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[server management]]></category>
		<guid isPermaLink="false">https://www.cisilino.com/?p=1412</guid>

					<description><![CDATA[<p>I rotate credentials the moment I suspect a breach. Not after I&#8217;ve confirmed one. Database credential rotation on an ISPConfig server sounds like routine maintenance. It stops being routine the day you find a web shell on a hosted site. Or a configuration file you can&#8217;t explain, sitting in a public backup. At that point, [&#8230;]</p>
<p>The post <a href="https://www.cisilino.com/en/2026/10/31/database-credential-rotation-ispconfig-breach/">Database credential rotation after an ISPConfig breach</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">I rotate credentials the moment I suspect a breach. Not after I&#8217;ve confirmed one. Database credential rotation on an ISPConfig server sounds like routine maintenance. It stops being routine the day you find a web shell on a hosted site. Or a configuration file you can&#8217;t explain, sitting in a public backup. At that point, every password tied to that database stack needs to be new. Verified. Documented. Not just assumed to be fine.</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" src="https://www.cisilino.com/wp-content/uploads/2026/10/database-credential-rotation-ispconfig.webp" alt="database credential rotation lock and key rotating above an ISPConfig database" width="1200" height="630"/></figure>



<h2 class="wp-block-heading">When does rotation stop being optional?</h2>



<p class="wp-block-paragraph">A few scenarios bring this up often enough that I keep a rotation plan ready for them. I&#8217;d rather not improvise one under pressure.</p>



<p class="wp-block-paragraph">A plugin or CMS on a hosted site gets compromised. I wrote about one real case on this kind of server in <a href="https://www.cisilino.com/en/2026/10/29/php2shell-cve-2026-109618-server-mitigation/">PHP2Shell: how I protected my servers while waiting for the patch</a>, a PHP vulnerability that let an attacker drop a web shell before a patch existed. Once a web shell runs under a hosting user, it can often read that site&#8217;s own config.inc.php. On a shared ISPConfig box, that file sits next to credentials for the control panel&#8217;s own database. Not only the one credential the attacker was actually after.</p>



<p class="wp-block-paragraph">A configuration file ends up somewhere it shouldn&#8217;t. A backup archive left in a public folder. A repository pushed with a stray file in it. A log that&#8217;s more readable than anyone intended. config.inc.php and mysql_clientdb.conf have no business in any of those places. Mistakes happen anyway, including mine.</p>



<p class="wp-block-paragraph">A system administrator leaves the team. However amicable the departure, shared database credentials they once held are credentials I no longer fully trust. Trust doesn&#8217;t transfer automatically when someone walks out the door.</p>



<p class="wp-block-paragraph">A suspected intrusion, even an unconfirmed one. This case is hardest to explain to anyone who hasn&#8217;t run a server under suspicion of attack. You don&#8217;t wait for proof before acting. You assume compromise and rotate. An unnecessary rotation costs an afternoon. A skipped one, after a real breach, can cost every site the server hosts.</p>



<h2 class="wp-block-heading">Why manual database credential rotation is so error-prone</h2>



<p class="wp-block-paragraph">The first time I rotated ISPConfig&#8217;s database credentials by hand, I underestimated how many files were involved. They all have to change together, or something quietly breaks a few hours later.</p>



<p class="wp-block-paragraph">There&#8217;s config.inc.php on the server side, and a second copy on the interface side. Both need the same new values. There&#8217;s mysql_clientdb.conf, which ISPConfig reads to manage every hosted site&#8217;s own database, not just its own housekeeping. Dovecot, Pure-FTPd and Postfix each keep their own copy of some of the same credentials. Mail and FTP can stop authenticating silently if you update the database user and forget just one of those three.</p>



<p class="wp-block-paragraph">Then there&#8217;s the Master/Slave topology some of my setups use. A Slave node authenticates to its Master&#8217;s database over the network, under a separate password. That password has to be rotated on the Master itself, not only locally. Get the sequence wrong, and a Slave can lock itself out of the very Master it&#8217;s supposed to be replicating from.</p>



<p class="wp-block-paragraph">None of that is conceptually difficult. It&#8217;s a lot of files. Several services to restart, in a sensible order. Almost no tolerance for a typo, especially while you&#8217;re doing it under pressure, right after finding something you didn&#8217;t want to find. That combination is exactly why database credential rotation kept feeling riskier by hand than the task itself should be. It&#8217;s why I wrote reset_DB_password.sh, after living through the problem myself more than once.</p>



<h2 class="wp-block-heading">What reset_DB_password.sh actually does</h2>



<p class="wp-block-paragraph">reset_DB_password.sh detects whether the node is Standalone, Master or Slave. It then runs only the phases that role needs.</p>



<p class="wp-block-paragraph">Phase A rotates the local MySQL root password. That&#8217;s the password ISPConfig itself uses to manage every hosted site&#8217;s database. The script updates mysql_clientdb.conf to match the new value.</p>



<p class="wp-block-paragraph">Phase B rotates the ispconfig control user&#8217;s password. It updates config.inc.php on both the server and interface side. Then it updates the matching credentials inside Dovecot, Pure-FTPd and Postfix, so mail and FTP keep authenticating without a separate manual pass through three more config files.</p>



<p class="wp-block-paragraph">Phase C runs only on a Slave. It connects to the Master&#8217;s database remotely. It rotates the Slave user&#8217;s password there, then updates dbmaster_password locally, so replication keeps authenticating correctly against the new value.</p>



<p class="wp-block-paragraph">After Phase B, the script offers to restart Dovecot, Pure-FTPd and Postfix for you. I almost always say yes. A credential rotation that leaves a mail service running on the old password isn&#8217;t finished, it&#8217;s just quiet about being broken. Restarting in the same run, right after the config files change, keeps the whole thing inside one short maintenance window instead of three separate ones discovered later.</p>



<h2 class="wp-block-heading">Backups before anything changes</h2>



<p class="wp-block-paragraph">Before touching a single file, the script takes a full rsync copy of /usr/local/ispconfig/ into a timestamped folder. It also attempts a non-blocking mysqldump of the mysql and dbispconfig databases. Non-blocking on purpose: I&#8217;d rather finish a credential rotation than sit waiting on a dump that&#8217;s stuck for some unrelated reason. Every configuration file it edits gets its own .bak copy first, before any string inside it gets replaced.</p>



<p class="wp-block-paragraph">None of that replaces an independent backup strategy. I still take a separate snapshot, or a full backup, before running this on any server that actually matters. The script&#8217;s own disclaimer says the same thing, more bluntly than I just did.</p>



<h2 class="wp-block-heading">Dry run first, every time</h2>



<p class="wp-block-paragraph">Every phase asks for confirmation before changing anything. &#8211;dry-run simulates an entire run without touching a single file. I use dry-run first on every server, every time. Even on ones I&#8217;ve rotated credentials on before, and think I know well. &#8211;skip-local-root skips Phase A, for when only the control user&#8217;s password needs rotating. &#8211;role=master or &#8211;role=slave overrides the automatic detection, for the rare case where it doesn&#8217;t read a server&#8217;s topology correctly on its own.</p>



<p class="wp-block-paragraph">The passwords it generates are 32 characters, letters and digits only. Long enough to resist guessing. Plain enough that MySQL&#8217;s and PHP&#8217;s own parsers never trip over a stray symbol in a connection string. I&#8217;ve tested the script on ISPConfig 3.3.1p1. I haven&#8217;t run it against older or newer branches. I wouldn&#8217;t assume identical behaviour there, without checking first myself.</p>



<p class="wp-block-paragraph">A node&#8217;s role isn&#8217;t always obvious at a glance, especially on a server you inherited rather than built yourself. That&#8217;s why &#8211;role exists, and why the dry-run output is worth reading line by line the first time, not skimmed. I&#8217;d rather spend two minutes confirming a Slave is really a Slave than find out the hard way mid-rotation.</p>



<h2 class="wp-block-heading">What I&#8217;d tell you before you run it</h2>



<p class="wp-block-paragraph"><strong>Disclaimer</strong>: the script is provided as-is, for informational purposes. You use it entirely at your own risk: I accept no responsibility for data loss, downtime, or any error caused by incorrect use or by running it in a context different from the one I use it in myself. Always keep an independent backup or VM snapshot before running it in production, regardless of what the script&#8217;s own backup step already captures for you.</p>



<p class="wp-block-paragraph">It&#8217;s free software. You can redistribute and modify it, with attribution to me as the original author. The source for reset_DB_password.sh, and the rest of the ispconfig-fast-tools collection, is on GitHub at <a href="https://github.com/matteocisilino/ispconfig-fast-tools" target="_blank" rel="noopener">github.com/matteocisilino/ispconfig-fast-tools</a>.</p>



<h2 class="wp-block-heading">Database credential rotation is a habit, not a cleanup job</h2>



<p class="wp-block-paragraph">Database credential rotation after a confirmed breach is just competent incident response. Most administrators would do it without being told twice. The harder habit is doing it after a merely suspected one, before anyone has proof. That&#8217;s the only version of the plan that actually limits the damage, while it&#8217;s still limitable. A script that runs the right phases for a server&#8217;s role, takes its own backups first, and lets me dry-run the whole thing before touching anything real. That&#8217;s what makes the habit practical on a Tuesday night, instead of theoretical in a blog post.</p>



<p class="wp-block-paragraph">ISPConfig, MySQL, PHP, Dovecot, Pure-FTPd, Postfix and the other names mentioned are trademarks of their respective owners. They are used only to identify the products.</p><p>The post <a href="https://www.cisilino.com/en/2026/10/31/database-credential-rotation-ispconfig-breach/">Database credential rotation after an ISPConfig breach</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.cisilino.com/en/2026/10/31/database-credential-rotation-ispconfig-breach/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Linux Kernel Vulnerability: a Use-After-Free in TCP IPv4</title>
		<link>https://www.cisilino.com/en/2026/10/31/linux-kernel-vulnerability-tcp-ipv4-cve-2026-98432/</link>
					<comments>https://www.cisilino.com/en/2026/10/31/linux-kernel-vulnerability-tcp-ipv4-cve-2026-98432/#respond</comments>
		
		<dc:creator><![CDATA[matteocisilino]]></dc:creator>
		<pubDate>Sat, 31 Oct 2026 09:19:23 +0000</pubDate>
				<category><![CDATA[Servers and databases]]></category>
		<category><![CDATA[CVE]]></category>
		<category><![CDATA[Debian]]></category>
		<category><![CDATA[Linux kernel]]></category>
		<category><![CDATA[server security]]></category>
		<guid isPermaLink="false">https://www.cisilino.com/?p=1403</guid>

					<description><![CDATA[<p>A Linux kernel vulnerability (CVE-2026-98432) causes a use-after-free in TCP IPv4. Debian is already patched; RHEL and Ubuntu are still waiting for a fix.</p>
<p>The post <a href="https://www.cisilino.com/en/2026/10/31/linux-kernel-vulnerability-tcp-ipv4-cve-2026-98432/">Linux Kernel Vulnerability: a Use-After-Free in TCP IPv4</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">I&#8217;ve been running Debian servers in production for years. Every time a kernel CVE comes out, I stop to read the details. Then I decide whether to patch right away or wait. This time the story is more tangled than usual: there&#8217;s a <strong>Linux kernel vulnerability</strong> in TCP IPv4, a CVSS score that vendors can&#8217;t agree on, and even a reported root exploit built by an AI model. Let&#8217;s start with a question that looks like a side note, but isn&#8217;t: what is MPTCP, and why does it matter even if you don&#8217;t use it.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.cisilino.com/wp-content/uploads/2026/10/vulnerabilita-kernel-linux-tcp-cve-2026-98432.webp" alt="Linux kernel vulnerability in TCP IPv4, stylised penguin with a patched Debian shield" width="1200" height="630"/></figure>



<h2 class="wp-block-heading">What MPTCP is, and why it matters even if you don&#8217;t use it</h2>



<p class="wp-block-paragraph">Multipath TCP (MPTCP) is the RFC 8684 standard. It extends classic TCP so a single connection can travel over several network paths at once. A phone can use WiFi and mobile data at the same time, for the same connection. A server with several interfaces can do the same, for redundancy or for combined bandwidth. Apple has used it in production since iOS 7, back in 2013, for Siri: it&#8217;s the best-known real-world case. Some mobile carriers, for example in South Korea, use it for WiFi/LTE bonding. Several data centres adopt it for multi-homing across different uplinks. It&#8217;s been in the mainline Linux kernel since 5.6.</p>



<p class="wp-block-paragraph">The point that made me raise an eyebrow is a different one. From version 1.24 onwards, programs written in Go require MPTCP by default for listening sockets. The Go Security Team confirmed this on 29 October. Along with it, they gave an uncomfortable warning: the bug we&#8217;re talking about today isn&#8217;t MPTCP-specific. A system with no active MPTCP listeners can still be exposed to similar attacks. The vulnerable code sits in the generic IPv4 TCP path, not in an optional module. You can disable MPTCP per program, with the <code>GODEBUG=multipathtcp=0</code> runtime variable. But the Go Security Team calls this mitigation &#8220;fragile&#8221;: a single MPTCP listener left exposed is enough to undo it. Nobody has shown that every working exploit actually depends on MPTCP. That&#8217;s why the MPTCP code stays an attack surface, even if you never consciously enable it in your stack: it just needs to be compiled into the kernel and reachable.</p>



<p class="wp-block-paragraph">The MPTCP project itself states, on its own page, that the main current Linux distributions ship the kernel with MPTCP support compiled in by default (<code>CONFIG_MPTCP=y</code>). It explicitly names Debian, Ubuntu, RHEL and Fedora. That&#8217;s a statement from the project itself, not an independent distro-by-distro check, but the underlying point still holds: support is switched on at the kernel level, not &#8220;opt-in&#8221; at the operating system level. Only the per-connection negotiation is left to the application.</p>



<h2 class="wp-block-heading">CVE-2026-98432, the Linux kernel vulnerability, in brief</h2>



<p class="wp-block-paragraph">The Linux kernel CVE team published CVE-2026-98432 on 15 October 2026. The upstream fix had already landed ten days earlier, on 5 October. It often happens that publication lags behind the commit. The CVSS score of 9.8 (critical) only arrived on 24 October, nine days after the CVE was published.</p>



<p class="wp-block-paragraph">The problem lies in TCP handshake handling for IPv4, specifically in the <code>tcp_v4_syn_recv_sock()</code> function. When a connection is created, the IP options from the SYN packet are passed from the pending request socket to the new socket. For example Record Route or Timestamp, if the client includes them in a crafted SYN. The problem is that they&#8217;re passed by reference, not by copy, and without the listener&#8217;s lock. According to the technical analysis of the patch, the structures involved are called <code>inet_opt</code> and <code>ireq_opt</code>. A second CPU can free that buffer with <code>kfree()</code>, called from <code>inet_sock_destruct()</code> or from <code>tcp_v4_reqsk_destructor()</code>. Meanwhile a first CPU is still reading it in <code>ip_options_build()</code>, to build the SYNACK. It&#8217;s a classic use-after-free caused by a race condition. The equivalent IPv6 path, <code>tcp_v6_syn_recv_sock()</code>, copies the options instead of passing them by reference: it isn&#8217;t vulnerable to the main race. There&#8217;s also a second attack route, through request-socket migration: <code>net.ipv4.tcp_migrate_req=1</code> or an eBPF <code>BPF_SK_REUSEPORT_SELECT_OR_MIGRATE</code> program. Both are disabled by default.</p>



<p class="wp-block-paragraph">The bug is remote and needs no authentication or user interaction, according to the kernel team&#8217;s assessment. It&#8217;s been present since kernel version 4.4. The fix is signed off by Eric Dumazet, reported by Xinyang Ge of Anthropic. It moves the memory release to after an RCU grace period, with <code>kfree_rcu()</code>: that way no CPU can read a buffer that&#8217;s already been freed. The fixed stable versions are 5.10.272, 5.15.223, 6.1.190, 6.6.159, 6.12.113, 6.18.56, 7.2.10 and mainline from 7.3-rc7.</p>



<h2 class="wp-block-heading">Conflicting CVSS scores: not every vendor agrees</h2>



<p class="wp-block-paragraph">Here&#8217;s where the story gets complicated. The kernel CVE team and Ubuntu rate attack complexity as low, and give it 9.8 (critical). Oracle and SUSE instead give 8.1 (important): same CVSS vector, but high attack complexity. Red Hat, oddly, has two assessments that don&#8217;t match each other. The public CVE page shows &#8220;Moderate, 5.9&#8221;. The machine-readable advisory file, updated on 29 October, shows instead &#8220;Important, 8.1&#8221;, with high impact on confidentiality and integrity. The same day, Red Hat&#8217;s internal bug tracker raised the severity from medium to high. Amazon, for its part, assigns 7.0. At the time of writing, the NVD hasn&#8217;t yet published a score of its own.</p>



<p class="wp-block-paragraph">It&#8217;s worth saying this plainly. This internal inconsistency at Red Hat isn&#8217;t a detail I worked out myself: it&#8217;s reported that way by the original article from The Hacker News, my main source for this data. It&#8217;s not the first time a vendor has published two different numbers for the same bug, on different channels. But here the jump from &#8220;moderate&#8221; to &#8220;important&#8221; on the same day says a lot. Even for the people who write the code, reliably estimating the real exploitability of a kernel race condition is hard.</p>



<h2 class="wp-block-heading">Patch status: Debian already fixed, others not yet</h2>



<p class="wp-block-paragraph">This is the point that affects me most directly: the hosting servers I manage run Debian stable. And here the facts speak for themselves, no need to add emphasis: <strong>Debian has already fixed this Linux kernel vulnerability</strong>, on both trixie and bookworm. Debian trixie (stable) was fixed on 16 October 2026, with package <code>linux 6.12.113-1</code>, advisory DSA-6568-1. Debian 12 (bookworm) was fixed in two steps: on 17 and 22 October 2026, with <code>linux 6.1.190-1</code> (advisory DLA-4841-1) and <code>linux-6.12 6.12.113-1~deb12u1</code> (advisory DLA-4850-1). In its own tracking table, Debian doesn&#8217;t list a separate CVSS score for this CVE. It simply marks the fix status for each release: that&#8217;s the information that actually matters, for anyone deciding whether to reboot a server.</p>



<p class="wp-block-paragraph">Comparing this with the status of other widely used distributions helps put it in perspective. As of 30 October, Red Hat has updated the status for RHEL 8, 9, 10 and OpenShift 4. It used to be &#8220;fix deferred&#8221; (marked on 29 October), now it&#8217;s &#8220;affected&#8221;. No release date has been given. Ubuntu, across all supported versions (22.04, 24.04, 26.04, 26.10), is still listed as &#8220;in progress&#8221;, with no date. Ubuntu 16.04, 18.04 and 20.04 are listed as vulnerable, with no fix listed at all. SUSE Linux Enterprise Server, from SP4 through SP7 plus 16.0, is in the same situation. Oracle Linux (UEK), openSUSE Leap 16.0, SUSE Linux Micro 6.2 and Amazon Linux 2023 are, instead, already fixed. RHEL 7 isn&#8217;t affected: the vulnerable code path was never shipped on that release.</p>



<p class="wp-block-paragraph">I&#8217;m not saying this to score points against Ubuntu or RHEL. They remain serious distributions, with solid security processes. I&#8217;m saying it because, on this specific bug, in this time window, the facts are these: anyone relying on hosting built on Debian stable already has the fix installed. On other very widely used distributions, the server stays exposed for an indefinite period. It&#8217;s a concrete, verifiable advantage, just by looking at the dates. It isn&#8217;t an opinion about the Debian project in general.</p>



<h2 class="wp-block-heading">Anthropic&#8217;s exploit (reported, not independently verified)</h2>



<p class="wp-block-paragraph">The most unusual part of this story involves Anthropic, the company that first reported the bug through Xinyang Ge. According to industry reports, one of its internal AI models, not released publicly, built a working root exploit entirely on its own. Starting from nothing but the patch and the report as a prompt. The two-stage attack reportedly works like this. In the first stage, the race makes the kernel&#8217;s response leak extra bytes to the attacker. From there the attacker recovers a kernel address, defeating KASLR. In the second stage, the same bug reportedly causes a buffer overflow. It overwrites a callback pointer with the address of a payload the attacker has already placed in kernel memory. When the kernel calls that pointer, the payload runs an arbitrary shell command as root. A lost race would only fail that single connection attempt, without crashing the system: so repeated attempts would be possible. In the test described by Anthropic: 48 minutes to steal the kernel address, another 5 minutes to reach command execution.</p>



<p class="wp-block-paragraph">Red Hat says a remote attacker reaching an exposed TCP service can generally trigger the race. The root exploit described by Anthropic, though, reportedly targeted specifically servers with an active multipath TCP listener. Anthropic&#8217;s post doesn&#8217;t clarify whether a server without MPTCP is exploitable in the same way. Neither the CVE record nor the upstream fix mention MPTCP anywhere. It&#8217;s trade press, not a primary source, reporting this link: so I&#8217;m writing it with the scepticism it deserves, not as a hundred-percent established fact. Anthropic hasn&#8217;t published the exploit code, the exact kernel version used, or the target server&#8217;s configuration. Another company, Innora, has published a root-cause analysis, with a QEMU reproduction environment. It stated it won&#8217;t release a weaponised exploit in the short term. At the moment there&#8217;s no evidence of real-world exploitation by vendors or CERTs. The bug isn&#8217;t in the CISA KEV catalogue, according to the copy maintained by Luxembourg&#8217;s CIRCL, updated as of 28 October.</p>



<h2 class="wp-block-heading">What to do on your servers right now</h2>



<p class="wp-block-paragraph">No vendor has published an officially sanctioned workaround for this <strong>Linux kernel vulnerability</strong>. Red Hat states explicitly that none of the measures circulating so far meet its standard for ease of deployment and stability. The primary mitigation remains applying the fixed kernel and rebooting, once the patch is available for your distribution. On Debian it already is. On RHEL and Ubuntu, not yet, at the time of writing.</p>



<p class="wp-block-paragraph">As defence in depth, not as a definitive fix, a few things are worth doing. Check that <code>net.ipv4.tcp_migrate_req</code> is set to 0. Check that no <code>BPF_SK_REUSEPORT_SELECT_OR_MIGRATE</code> eBPF programs are loaded. Consider filtering incoming IPv4 packets that carry Record Route or Timestamp options. Monitor for any crashes mentioning <code>ip_options_build</code>, <code>ip_build_and_send_pkt</code> or <code>skb_under_panic</code>. Take stock of any exposed MPTCP listeners, and avoid leaving them reachable without a reason. If you also manage defences against more common application-level attacks, <a href="https://www.cisilino.com/en/2026/10/29/php2shell-cve-2026-109618-server-mitigation/">how I protected my servers while waiting for the PHP2Shell patch</a> takes the same approach: mitigate what you can while waiting for the definitive fix, without promising protections that don&#8217;t exist.</p>



<p class="wp-block-paragraph">For anyone asking me whether to patch now: if you run Debian stable, the fixed kernel is already in the security repositories. The update is straightforward, and the exposure window is already closed. If you run other distributions, there&#8217;s no patch to install yet today. It&#8217;s worth following your vendor&#8217;s advisories closely over the coming days: the situation is changing quickly.</p>



<p class="wp-block-paragraph">Sources: <a href="https://thehackernews.com/2026/10/linux-kernel-tcp-flaw-with-98-cvss.html" target="_blank" rel="nofollow noopener">The Hacker News</a>, the <a href="https://security-tracker.debian.org/tracker/CVE-2026-98432" target="_blank" rel="nofollow noopener">Debian Security Tracker</a> and the <a href="https://github.com/torvalds/linux/commit/e3f33b0a1d89d738e2b913dab519226eaf76e15b" target="_blank" rel="noopener">fix commit</a>. Debian, Red Hat, Ubuntu and the other names mentioned are trademarks of their respective owners.</p><p>The post <a href="https://www.cisilino.com/en/2026/10/31/linux-kernel-vulnerability-tcp-ipv4-cve-2026-98432/">Linux Kernel Vulnerability: a Use-After-Free in TCP IPv4</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.cisilino.com/en/2026/10/31/linux-kernel-vulnerability-tcp-ipv4-cve-2026-98432/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>WordPress email log: why I check it with FluentSMTP</title>
		<link>https://www.cisilino.com/en/2026/10/31/wordpress-email-log-why-i-check-it-fluentsmtp/</link>
					<comments>https://www.cisilino.com/en/2026/10/31/wordpress-email-log-why-i-check-it-fluentsmtp/#respond</comments>
		
		<dc:creator><![CDATA[matteocisilino]]></dc:creator>
		<pubDate>Sat, 31 Oct 2026 08:00:00 +0000</pubDate>
				<category><![CDATA[Servers and databases]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[FluentSMTP]]></category>
		<category><![CDATA[SMTP]]></category>
		<category><![CDATA[WordPress plugin]]></category>
		<guid isPermaLink="false">https://www.cisilino.com/?p=1312</guid>

					<description><![CDATA[<p>Why I check the WordPress email log in FluentSMTP before server logs: failed sends, manual resending, encrypted SMTP credentials, backup connections, and the log's honest limits.</p>
<p>The post <a href="https://www.cisilino.com/en/2026/10/31/wordpress-email-log-why-i-check-it-fluentsmtp/">WordPress email log: why I check it with FluentSMTP</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">I manage several WordPress sites. On each one, more emails go out than anyone would guess: contact notifications, password resets, order confirmations, alerts to site managers. The WordPress email log in FluentSMTP is the tool I check as soon as a client writes &#8220;I never got anything.&#8221; I used to look at the SMTP server logs from the command line. I had to match grep output and timestamps by hand. Now I open a page in the WordPress dashboard and it&#8217;s all right there.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.cisilino.com/wp-content/uploads/2026/10/fluent-smtp-log-invii-email-wordpress.webp" alt="WordPress email log shown in the FluentSMTP dashboard" width="1200" height="630"/></figure>



<h2 class="wp-block-heading">Why I check the WordPress email log before the server logs</h2>



<p class="wp-block-paragraph">The typical case is always the same. A contact form that &#8220;isn&#8217;t arriving&#8221;. A client who never gets the password reset email. An order left without a confirmation. Without a log at hand, the first guess is the spam folder. Then the SMTP server logs. Then maybe the firewall. With FluentSMTP I skip those steps. I can see straight away whether WordPress actually tried to send that email. To whom, when, and with what response from the sending server.</p>



<p class="wp-block-paragraph">FluentSMTP logs every call to <code>wp_mail()</code>. Not just emails from third-party plugins, but also the ones generated by core: new-user notifications, update reminders, error alerts. For every send, the log shows the sender, recipient, subject, full headers, and message body. And the response from the SMTP provider or API used. If an email failed, that server response is right there. I don&#8217;t have to guess it.</p>



<h2 class="wp-block-heading">What I actually find in the sending log</h2>



<p class="wp-block-paragraph">The plugin supports dozens of connectors: Amazon SES, SendGrid, Mailgun, Brevo, Postmark, SparkPost. Also Google Workspace and Microsoft 365 via OAuth, as well as plain authenticated SMTP. On the sites I manage I almost always use authenticated SMTP with the client&#8217;s own domain. Sometimes a dedicated API, when the email volume grows. Either way, the WordPress email log doesn&#8217;t change. Every row has a status, sent or failed. There&#8217;s a button to review the content or resend the message, without the user having to repeat the action that triggered it.</p>



<p class="wp-block-paragraph">Manual resending is the feature I use most. A form filled in twice because &#8220;it never arrived&#8221; becomes one click in the log. Not a fresh complaint from the client. For repeated failures I&#8217;ve set up notifications on Telegram. As soon as a connection stops working, I know before anyone writes to tell me. Instead of finding out from a support ticket.</p>



<p class="wp-block-paragraph">The log isn&#8217;t only about notifications aimed at me or the client who manages the site. Every outgoing email the site generates towards third parties ends up there too: the order confirmation an online shop sends to its customer, a payment receipt, a shipping notice. If that confirmation doesn&#8217;t arrive, I see it in the WordPress email log exactly like an internal notification, with the same button to resend it to the right recipient without making them repeat the purchase.</p>



<h2 class="wp-block-heading">How I set up FluentSMTP on the sites I manage</h2>



<p class="wp-block-paragraph">After connecting the right connector, I change the log retention. By default it stays on for a long time. I set it to 30-60 days, depending on the site&#8217;s traffic. That&#8217;s enough to trace back a problem reported late. Without filling the database with rows I&#8217;ll never look at. I then turn on at least one notification channel for failures, Telegram or Slack depending on the client. The log alone doesn&#8217;t alert anyone: it has to be opened to be read.</p>



<p class="wp-block-paragraph">On sites with contact forms I also use <a href="https://www.cisilino.com/en/2026/10/29/wordpress-security-plugin/">Cisilino Site Defense Network</a> to block bots. Less incoming spam means fewer emails generated by the forms. The log stays easier to read, with less noise to filter through when I&#8217;m looking for the right message.</p>



<h2 class="wp-block-heading">SMTP credentials don&#8217;t stay in plain text in the database</h2>



<p class="wp-block-paragraph">One detail I always check before saving a connection: where the credentials end up. FluentSMTP encrypts them by default with WordPress&#8217;s own SALT keys, the ones already present in <code>wp-config.php</code> for session security. Encryption can be switched off, but the plugin itself flags that as not recommended. On the sites I manage I prefer another option: saving the API or SMTP password directly in <code>wp-config.php</code>, outside the database, by defining the constants before the plugin reads them. That way, even a database dump or unauthorised access to the dashboard doesn&#8217;t expose the sending provider&#8217;s key. It&#8217;s the same principle I apply elsewhere: fewer secrets in the database, the better.</p>



<h2 class="wp-block-heading">Several connections together, not just one at a time</h2>



<p class="wp-block-paragraph">FluentSMTP lets you configure several connections together, not just one at a time. On one site I set a default connection and add a second one as a backup: if the first provider doesn&#8217;t respond, sending switches automatically to the backup connection, without me having to step in. Which connection gets used depends on the sender address: each connection has its own &#8220;From&#8221;, everything else goes through the default one, with the backup kicking in only if the default one really fails (a provider error, not an email that ended up in spam). It&#8217;s one of the reasons I prefer it to a single SMTP setup with no alternative: if SendGrid or Amazon SES has a problem for a few hours, the site keeps sending anyway, and I see it straight away in the WordPress email log. All included in the free version, with no paid pro version: you only pay the sending provider you choose, not the plugin.</p>



<h2 class="wp-block-heading">A daily health check, not just when something breaks</h2>



<p class="wp-block-paragraph">Besides the row-by-row log, FluentSMTP runs a connection health check every day, automatically. If the provider stops responding, the alert arrives before a client writes to tell me &#8220;the site isn&#8217;t sending emails any more&#8221;. The same dashboard shows a chart with daily totals of successful and failed sends: useful for seeing at a glance whether a drop is normal or a sign that something is breaking, without having to open the WordPress email log row by row every time. There&#8217;s also a periodic email summary, with the week&#8217;s totals: it isn&#8217;t a failure alert, it&#8217;s a bulletin I skim through to know whether the sending volume is within the norm.</p>



<p class="wp-block-paragraph">For anyone who, like me, manages several sites from the command line, FluentSMTP also exposes WP-CLI commands: a test send, a connection health check, statistics, and cleanup of old logs. I use them in the same scripts that already run on the servers for other maintenance checks, without having to open every site&#8217;s dashboard one by one.</p>



<h2 class="wp-block-heading">The honest limits of the WordPress email log</h2>



<p class="wp-block-paragraph">It isn&#8217;t a magic solution. Retention is based on days, not on a maximum number of rows. On a site with a lot of transactional traffic the log table can grow quickly. It&#8217;s worth keeping an eye on it, or setting a shorter retention period. Failure notifications only arrive on the chat channels you&#8217;ve configured, not by email. That makes sense: an email warning about a failed email risks failing in turn too. But it&#8217;s worth knowing before relying on it.</p>



<p class="wp-block-paragraph">Finally, the log records what happened on the WordPress side and the provider&#8217;s side. It doesn&#8217;t guarantee delivery into the recipient&#8217;s inbox. If an email is marked as sent but ends up in spam, that&#8217;s a domain reputation or SPF/DKIM configuration issue. Not something a log can fix on its own. It&#8217;s still the first place I look, before any other check.</p>



<p class="wp-block-paragraph">The plugin is free and open source. Official page on <a href="https://wordpress.org/plugins/fluent-smtp/" target="_blank" rel="nofollow noopener">wordpress.org</a>, with no features locked behind a pro version. For anyone managing even a single site with a contact form, it&#8217;s worth installing just for the WordPress email log. The first time it turns &#8220;I never got the email&#8221; into a one-minute fix instead of half an hour, it&#8217;s paid for itself.</p><p>The post <a href="https://www.cisilino.com/en/2026/10/31/wordpress-email-log-why-i-check-it-fluentsmtp/">WordPress email log: why I check it with FluentSMTP</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.cisilino.com/en/2026/10/31/wordpress-email-log-why-i-check-it-fluentsmtp/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Deactivation, uninstallation and personal data</title>
		<link>https://www.cisilino.com/en/2026/10/30/deactivation-uninstallation-personal-data/</link>
					<comments>https://www.cisilino.com/en/2026/10/30/deactivation-uninstallation-personal-data/#respond</comments>
		
		<dc:creator><![CDATA[matteocisilino]]></dc:creator>
		<pubDate>Fri, 30 Oct 2026 16:06:04 +0000</pubDate>
				<category><![CDATA[CSDN manual]]></category>
		<category><![CDATA[Cisilino Site Defense Network]]></category>
		<category><![CDATA[privacy]]></category>
		<guid isPermaLink="false">https://www.cisilino.com/?p=1058</guid>

					<description><![CDATA[<p>What happens when you deactivate or delete Cisilino Site Defense Network, which data stays, and how to list it in your privacy notice.</p>
<p>The post <a href="https://www.cisilino.com/en/2026/10/30/deactivation-uninstallation-personal-data/">Deactivation, uninstallation and personal data</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Before you uninstall the plugin CSDN it&#8217;s worth knowing the difference between deactivating it and deleting it, because the consequences differ. Deactivation switches off the rules and keeps the data. Uninstallation deletes the plugin&#8217;s data from your site. At the end you&#8217;ll also find the list of personal data it processes, to mention in your privacy notice.</p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" src="https://www.cisilino.com/wp-content/uploads/2026/10/manuale-csdn-disattivazione-disinstallazione.webp" alt="Diagram of the WordPress Installed Plugins screen to uninstall the plugin CSDN with Deactivate and Delete" width="1200" height="630"/></figure>
<h2>Where it is</h2>
<p>Open <strong>Plugins &gt; Installed Plugins</strong> (point 1 in the image). On the row for <strong>Cisilino Site Defense Network</strong> (point 3) you&#8217;ll find the <strong>Deactivate</strong> link. After deactivation (point 4) the same row shows <strong>Activate</strong> and <strong>Delete</strong>.</p>
<h2>What happens on deactivation</h2>
<p>Deactivating the plugin stops it without touching the data. On deactivation the plugin does four things.</p>
<ol>
<li>it logs the event “Plugin deactivated on this site” and tries to deliver it to the panel, if configured.</li>
<li>it cancels the three scheduled tasks.</li>
<li>it empties both <code>.htaccess</code> blocks, the blocked-IPs one and the hardening one.</li>
<li>it updates WordPress&#8217;s rewrite rules.</li>
</ol>
<p><strong>Warning:</strong> while deactivated, no rule stays in force. Blocked IPs can access the site again, and hardening no longer applies. The plugin isn&#8217;t even loaded, so the other protections don&#8217;t act either. The security headers stop too, though a browser that already received HSTS will remember it for the time that was set.</p>
<p>The database stays intact. If you reactivate the plugin, the <code>.htaccess</code> blocks are rebuilt, and you&#8217;ll find the settings exactly as you left them.</p>
<h2>How to uninstall the plugin</h2>
<p>To uninstall the plugin you need to press <strong>Delete</strong> in <strong>Installed Plugins</strong>, after deactivating it. Before you do, follow these steps.</p>
<ol>
<li>In the <strong>Activity log</strong> tab, check that the “awaiting delivery to the panel” row is at zero, if you use the panel.</li>
<li>In the <strong>Debug log</strong> tab, download any files you need. Then, if you want, press <strong>Delete all files</strong>.</li>
<li>Back up the site, if you haven&#8217;t already.</li>
<li>Deactivate the plugin and press <strong>Delete</strong>.</li>
</ol>
<h2>What gets removed and what stays</h2>
<p>When you choose to uninstall the plugin, it first logs “Plugin uninstalled from this site: local data removed” and tries to deliver that to the panel. Then it deletes everything, whatever happened with delivery.</p>
<p>The following is removed.</p>
<ul>
<li>the four tables <code>csdn_events</code>, <code>csdn_overrides</code>, <code>csdn_rate_hits</code> and <code>csdn_activity</code>.</li>
<li>almost every option whose name starts with <code>csdn_</code>, including the panel credentials, the whitelist and the tab settings. Three remain, listed below.</li>
<li>the rate limiting suspension data on every user.</li>
<li>the plugin&#8217;s temporary data.</li>
<li>the rules in the plugin&#8217;s two <code>.htaccess</code> blocks and the rewrite rules. The <code># BEGIN</code> and <code># END</code> markers stay in the file, empty.</li>
</ul>
<p>The following stays instead.</p>
<ul>
<li>the debug log files in the <code>csdn-debug-*</code> folder inside <code>uploads</code>, because they are your own data: delete them by hand, or with the <strong>Delete all files</strong> button, before uninstalling.</li>
<li>the history already delivered to the panel, which sits on the panel, not on your site.</li>
<li>the lines in <code>.htaccess</code> that sit outside the plugin&#8217;s markers.</li>
<li>three minor options: <code>csdn_registration_lock</code> (the User registration policy), <code>csdn_remote_ban_reasons</code> (the reasons for blocks received) and <code>csdn_trigger_token</code> (the token received from the panel). The user data <code>csdn_registration_blocked_at</code> also stays, if present, along with the temporary <code>csdn_rl_block_*</code> data, which expires on its own. These can be removed by hand from the database.</li>
</ul>
<p><strong>Warning:</strong> uninstalling the plugin also deletes the local activity log. Rows not yet delivered to the panel are lost if the panel doesn&#8217;t respond.</p>
<h2>Personal data processed by the plugin</h2>
<p>The plugin keeps its data on your own site, in the database. Never the password. Here&#8217;s what it processes.</p>
<ul>
<li><strong>Failed logins</strong>: IP address, username tried, number of attempts, first and last occurrence, and block status. There&#8217;s no automatic deletion: they stay in the database until you uninstall the plugin.</li>
<li><strong>Activity log</strong>: date and time, WordPress user (id, login, role), IP, type of action, the object involved (for content, its title) and a short description. In some cases it adds details: for a new user, the email and roles; for a profile edit, the previous and new values of email, login, display name and website. It doesn&#8217;t save the content of posts, comments or files. For options with a suspicious name, such as keys or tokens, it only logs that they changed.</li>
<li><strong>Rate limiting</strong>: the IP and type of submission from guests, kept for one day. Author suspensions sit in the user&#8217;s own data.</li>
<li><strong>IP overrides, whitelist and the blacklist received</strong>.</li>
<li><strong>Debug log</strong>, if you switch it on: files that can contain paths and fragments of data.</li>
</ul>
<p>The local log keeps 30 days by default, and at most 500 rows. You can change both values in the <strong>Activity log</strong> tab.</p>
<h3>What leaves the site</h3>
<p>Only if you connect the panel. Every 15 minutes the plugin sends the failed logins: IP, username, outcome “failed” and date. It sends up to 200 at a time. It adds the customer code and the site&#8217;s URL. It receives the blocked IPs. The activity log, with the details above, is normally sent straight away, at the end of the request, and whatever is left queued goes out with the 15-minute round. It only runs if both the log and the “Send activity to the panel” option are on. Manual overrides are never sent.</p>
<h3>What to write in your privacy notice</h3>
<p>For as long as you haven&#8217;t decided to uninstall the plugin, your site&#8217;s privacy notice should mention at least these points.</p>
<ul>
<li>that the site logs the IP and username of failed login attempts, for security reasons.</li>
<li>that it keeps a log of user actions, with IP addresses, and for how many days it keeps them.</li>
<li>that, if you&#8217;ve connected the panel, some of this data is sent to the external service.</li>
<li>who the data controller is, and how users can exercise their rights.</li>
</ul>
<p>Adapt the text to your own situation, with your advisor if you have one: this manual is no substitute for legal advice. For the basics on plugins, the <a href="https://wordpress.org/documentation/article/manage-plugins/" target="_blank" rel="noopener">official WordPress guide</a> also explains the difference between deactivating and deleting.</p>
<h2>If something goes wrong</h2>
<p>If the site shows an error after deactivation, check <code>.htaccess</code> via FTP and see the chapter <a href="https://www.cisilino.com/en/?p=986">Troubleshooting and frequently asked questions</a>. If you decided to uninstall the plugin by mistake, the local data doesn&#8217;t come back: you&#8217;ll need a site backup.</p>
<p>Previous chapter: <a href="https://www.cisilino.com/en/?p=986">Troubleshooting and frequently asked questions</a>. Back to the index with the <a href="https://www.cisilino.com/en/?p=972">introduction to the CSDN manual</a>.</p><p>The post <a href="https://www.cisilino.com/en/2026/10/30/deactivation-uninstallation-personal-data/">Deactivation, uninstallation and personal data</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.cisilino.com/en/2026/10/30/deactivation-uninstallation-personal-data/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Troubleshooting CSDN: FAQ</title>
		<link>https://www.cisilino.com/en/2026/10/30/troubleshooting-csdn-faq/</link>
					<comments>https://www.cisilino.com/en/2026/10/30/troubleshooting-csdn-faq/#respond</comments>
		
		<dc:creator><![CDATA[matteocisilino]]></dc:creator>
		<pubDate>Fri, 30 Oct 2026 16:06:02 +0000</pubDate>
				<category><![CDATA[CSDN manual]]></category>
		<category><![CDATA[Cisilino Site Defense Network]]></category>
		<category><![CDATA[frequently asked questions]]></category>
		<guid isPermaLink="false">https://www.cisilino.com/?p=1057</guid>

					<description><![CDATA[<p>Solutions to the typical problems with Cisilino Site Defense Network: blocks, 500 errors, suspensions, the panel and logs.</p>
<p>The post <a href="https://www.cisilino.com/en/2026/10/30/troubleshooting-csdn-faq/">Troubleshooting CSDN: FAQ</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>This troubleshooting CSDN page collects the situations where Cisilino Site Defense Network can cause you trouble, with the fix for each one. You&#8217;ll need it if you&#8217;ve locked yourself out, if the site responds with a 500 error, or if a user can no longer publish. The answers are organised as frequently asked questions.</p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" src="https://www.cisilino.com/wp-content/uploads/2026/10/manuale-csdn-risoluzione-problemi.webp" alt="Checklist for troubleshooting CSDN, with the steps to follow" width="1200" height="630"/></figure>
<h2>Troubleshooting CSDN: where to start</h2>
<p>Before hunting for the exact answer, run through this checklist.</p>
<ol>
<li>Can you still open <code>wp-admin</code>? If so, almost everything can be fixed from the plugin&#8217;s Settings page.</li>
<li>Read the notices at the top. The plugin explains the outcome of its actions in coloured boxes.</li>
<li>Remember the last thing you changed: a hardening rule, a policy, a limit.</li>
<li>If there&#8217;s a <strong>Check now</strong> button, use it before guessing.</li>
<li>If you can no longer get into the site, get your FTP access or the hosting&#8217;s file manager ready.</li>
</ol>
<h2>Logins and blocks</h2>
<h3>I&#8217;ve locked myself out: what do I do?</h3>
<p>If you still have access to WordPress, for example from your phone on mobile data, open the <strong>Blocked IPs</strong> tab. Find your IP and press <strong>Unblock</strong>. If your IP isn&#8217;t listed but you&#8217;re still blocked (which can come from the optional security list), go to the <strong>General</strong> tab, “Local IP overrides” section: enter the IP, choose “Always unblock (unban)” and press <strong>Save override</strong>. Then, in the <strong>General</strong> tab, press <strong>Add to whitelist</strong>.</p>
<p>If you&#8217;re blocked from the site too, and see a 403 error, log in via FTP and open <code>.htaccess</code>. Remove the line with your IP, or the whole block between <code># BEGIN Cisilino Site Defense Network</code> and <code># END Cisilino Site Defense Network</code>.</p>
<p><strong>Warning:</strong> the manual edit is temporary. The same source will rewrite the block at the next event: a failed login, a sync, or the 15-minute round. As soon as you&#8217;re back in, use <strong>Unblock</strong> and the whitelist.</p>
<h3>Why didn&#8217;t the whitelist unblock me?</h3>
<p>The whitelist only stops failed logins from being counted. It doesn&#8217;t remove blocks already in place. To remove a block you need <strong>Unblock</strong>, which creates a permanent unblock override on this site.</p>
<h3>A legitimate user has been blocked</h3>
<p>The attempts counter is cumulative per IP and never resets on its own. Even scattered mistakes over weeks can reach the threshold, which defaults to 10. Unblock the IP and whitelist it, or raise the threshold in <strong>Remote settings</strong>, where the field is called “Local block threshold (failed attempts)”.</p>
<h3>An IP&#8217;s block never ends</h3>
<p>A local block doesn&#8217;t expire. A manual block expires after the chosen duration, from 1 hour to 7 days. If you chose “Permanent (until you remove it)”, it doesn&#8217;t expire. A block received from the panel disappears once the panel removes it from the list. A timed unblock, once it expires, brings the block back if the original source is still there. For a definitive unblock use <strong>Unblock</strong>, which is permanent.</p>
<h3>Blocks look odd behind a proxy or a CDN</h3>
<p>The plugin reads the IP only from <code>REMOTE_ADDR</code> and ignores the <code>X-Forwarded-For</code> header, because it can be forged. Look at the line “Your current IP is …” under the <strong>IP address</strong> field in the <strong>General</strong> tab. If it isn&#8217;t your public IP, the plugin is seeing the proxy&#8217;s address. In that case, avoid blocking or whitelisting that address until you&#8217;ve sorted it out with whoever manages the proxy.</p>
<h2>Errors after the .htaccess rules</h2>
<p>This part of troubleshooting CSDN covers rules written to the server&#8217;s own file.</p>
<h3>The site shows a 500 error after saving the hardening rules</h3>
<p>The plugin makes no copy of <code>.htaccess</code> and doesn&#8217;t check the syntax after writing it. An error, or a rule your server doesn&#8217;t accept, shows up straight away as a 500 error.</p>
<ol>
<li>Log in via FTP or the file manager.</li>
<li>Make a copy of <code>.htaccess</code>.</li>
<li>Delete the block between <code># BEGIN Cisilino Site Defense Network - Hardening</code> and <code># END Cisilino Site Defense Network - Hardening</code>.</li>
<li>Reload the site, then correct the settings in the <strong>Hardening / IDS</strong> tab.</li>
</ol>
<p>The hardening block is only rewritten when you save that tab or reactivate the plugin, not by the 15-minute round. Your manual fix therefore stays in place.</p>
<h3>I wrote a custom path and the whole site gives a 403</h3>
<p>In the custom paths box, every line is literal text, with no wildcards. The rule blocks any address containing that string. Writing <code>/</code> or <code>wp</code> blocks everything, including <code>wp-admin</code>. Remove the hardening block via FTP, as above. Then, in the <strong>Hardening / IDS</strong> tab, fix or empty the “Custom paths to block” box and save. If you don&#8217;t fix it, a new save or a plugin reactivation will rewrite the rule, and the site will go back to giving a 403.</p>
<h3>You see “Settings saved, but writing to .htaccess failed”</h3>
<p>The <code>.htaccess</code> file isn&#8217;t writable: check the permissions. The rules in that block aren&#8217;t active. The two switches that act in PHP, meaning XML-RPC and <code>?author=N</code>, stay active regardless.</p>
<h3>The test says the PHP block in uploads doesn&#8217;t work</h3>
<p>In the <strong>Test</strong> tab, the “Check PHP execution block in uploads” box reports whether the test file was executed. Check that your hosting allows <code>.htaccess</code> in that folder, and that there&#8217;s no more specific <code>&lt;Directory&gt;</code> block. On nginx the rules have no effect. The rule only covers the standard <code>uploads</code> folder.</p>
<h3>A plugin or the theme has stopped working</h3>
<p>Switch off the last rule you turned on and save. The most common cases: blocking PHP in <code>uploads</code> breaks plugins that write PHP files there; disabling XML-RPC stops remote apps and functions; blocking executable uploads also rejects files such as <code>.svg</code>.</p>
<h2>Users, authors and visitors</h2>
<h3>An author can no longer publish: “your account is suspended”</h3>
<p>Rate limiting has seen too much content created too quickly. By default the limit is 150 items in 300 seconds, with a 3600-second suspension. From the <strong>Rate limiting</strong> tab, in the suspended users table, press <strong>Revoke suspension</strong>. Otherwise, wait for it to expire.</p>
<p>Switching off “Rate limit active” doesn&#8217;t remove a suspension already under way. Before a large import, raise the limit N or switch off the cap.</p>
<h3>A visitor sees “Too many submissions”</h3>
<p>A guest has sent too many comments or forms too quickly: more than 2 in 60 seconds by default, with a 3600-second block. The block is by IP, so it can hit several people in the same office. Raise the N value in the visitors section. There&#8217;s no list of exceptions.</p>
<h3>I can&#8217;t create an editor or administrator user</h3>
<p>That&#8217;s intentional. The default <strong>User registration</strong> policy is “Low-privilege roles only”, and it makes no exception, not even for you. Switch temporarily to “No restriction”, create the user, then switch back. With “No registration (exclusive)” nobody can create users. Also check the default role under Settings &gt; General in WordPress: if it&#8217;s a forbidden role, registrations are rejected.</p>
<h2>Connecting to the panel</h2>
<h3>The panel connection doesn&#8217;t show</h3>
<p>The status is in the “Panel connection status:” box at the top of the <strong>Remote settings</strong> tab. If the box is missing, the fields were incomplete: you need the Customer code, the API key and the Panel URL. After “Save and verify connection” no separate banner appears.</p>
<ul>
<li>“Panel URL not secure: https is required …”: the address must start with <code>https</code>. The plugin also refuses to save an http URL.</li>
<li>“Authentication rejected by the panel: customer_code or API key incorrect.”: double-check both values.</li>
<li>“Unable to reach the panel: …”: a network, DNS or certificate problem.</li>
<li>“Invalid response from the panel (not JSON).”: the address doesn&#8217;t point to the right panel.</li>
</ul>
<p>If the panel doesn&#8217;t respond, local protection carries on and the queued data is sent on the next round. The plugin works even without the panel.</p>
<h3>Activity isn&#8217;t reaching the panel</h3>
<p>In the <strong>Activity log</strong> tab, look at the diagnostics table and the “awaiting delivery to the panel” row. Press <strong>Try sending now</strong>: the result appears in the diagnostics. The row cap, 500 by default, deletes the oldest ones even if they haven&#8217;t been delivered.</p>
<h2>Debug log, integrity and headers</h2>
<h3>The debug log won&#8217;t turn on</h3>
<p>There are two possible messages. “the uploads folder is not writable”: fix the permissions on <code>uploads</code>. “the files in its folder appear reachable from the internet”: probably a server with no <code>.htaccess</code>, such as nginx. Block access to the <code>csdn-debug-*</code> folder in the server configuration and try again. If the log stopped because of the 200 MB cap, download or delete the files and turn it back on.</p>
<h3>Integrity says “the plugin&#8217;s files do not match”</h3>
<p>If you&#8217;ve edited a plugin file by hand, that&#8217;s normal. Otherwise, treat the site as potentially compromised: reinstall the plugin from a trusted copy and check the rest. If the message says there&#8217;s no reference at all, reactivate the plugin to take a new snapshot.</p>
<h3>HSTS won&#8217;t turn on, or won&#8217;t turn off</h3>
<p>To turn it on you must open the plugin&#8217;s settings over https, otherwise you&#8217;ll see “HSTS was NOT activated”. Always save from an https page. Unticking the box stops the header being sent, but browsers that already received it will remember it for a long time.</p>
<h2>If you can&#8217;t find the answer</h2>
<p>If this troubleshooting CSDN page isn&#8217;t enough, turn on the debug log, reproduce the problem and read the entry. Then open a discussion on the <a href="https://wordpress.org/support/plugin/cisilino-site-defense-network/" target="_blank" rel="noopener">plugin&#8217;s support forum</a>: it&#8217;s the place to get help and see problems already reported. Don&#8217;t paste server paths or sensitive data.</p>
<p>Previous chapter: <a href="https://www.cisilino.com/en/?p=985">Debug log: PHP errors in their own file</a>. Next chapter: <a href="https://www.cisilino.com/en/?p=987">Deactivation, uninstallation and personal data</a>. For the index: <a href="https://www.cisilino.com/en/?p=972">the CSDN manual</a>.</p><p>The post <a href="https://www.cisilino.com/en/2026/10/30/troubleshooting-csdn-faq/">Troubleshooting CSDN: FAQ</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.cisilino.com/en/2026/10/30/troubleshooting-csdn-faq/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Debug log: PHP errors in their own file</title>
		<link>https://www.cisilino.com/en/2026/10/30/debug-log-php-errors-their-own-file/</link>
					<comments>https://www.cisilino.com/en/2026/10/30/debug-log-php-errors-their-own-file/#respond</comments>
		
		<dc:creator><![CDATA[matteocisilino]]></dc:creator>
		<pubDate>Fri, 30 Oct 2026 16:05:59 +0000</pubDate>
				<category><![CDATA[CSDN manual]]></category>
		<category><![CDATA[Cisilino Site Defense Network]]></category>
		<category><![CDATA[debug]]></category>
		<category><![CDATA[PHP errors]]></category>
		<guid isPermaLink="false">https://www.cisilino.com/?p=1056</guid>

					<description><![CDATA[<p>How to turn on the Debug log tab of the plugin CSDN since version 1.0.15: duration, file size, rotation, downloads and limits.</p>
<p>The post <a href="https://www.cisilino.com/en/2026/10/30/debug-log-php-errors-their-own-file/">Debug log: PHP errors in their own file</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>The WordPress debug log is a new feature in the CSDN plugin since version 1.0.15. It logs the site&#8217;s PHP errors into its own file, without touching <code>wp-config.php</code>. You switch it on from the backend, and it switches itself off.</p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" src="https://www.cisilino.com/wp-content/uploads/2026/10/manuale-csdn-log-di-debug.webp" alt="Diagram of WordPress with the WordPress debug log tab of the plugin CSDN highlighted" width="1200" height="630"/></figure>
<h2>Where it is</h2>
<p>Go to Settings &gt; Cisilino Site Defense Network (point 1 in the image) and open the <strong>Debug log</strong> tab (point 2). There are three sections:</p>
<ul>
<li>point 3: “Site debug log”, with status and activation.</li>
<li>point 4: “Collected files”.</li>
<li>point 5: “Latest entries”.</li>
</ul>
<h2>What the WordPress debug log is for</h2>
<p>It comes in useful when the site shows a blank page or a critical error, when something breaks after an update, or when your hosting won&#8217;t let you edit <code>wp-config.php</code> or read the logs. The <code>WP_DEBUG</code> and <code>WP_DEBUG_LOG</code> constants are defined before the plugins load, so a plugin can&#8217;t turn them on. This log instead uses a PHP error handler hooked onto the plugin&#8217;s own loading.</p>
<p>This log adds to things, it doesn&#8217;t replace anything. Errors keep arriving wherever they arrived before, meaning <code>debug.log</code> and the server log. It sends nothing to the panel.</p>
<h2>How to use it</h2>
<ol>
<li>Open the <strong>Debug log</strong> tab.</li>
<li>Choose <strong>Stay on for</strong>: <strong>1 hour</strong>, <strong>24 hours</strong> (default) or <strong>7 days</strong>.</li>
<li>Choose <strong>Maximum size per file</strong>.</li>
<li>Press <strong>Turn on the debug log</strong>. You&#8217;ll read “Debug log turned on. It switches itself off when the chosen time runs out; the files stay.”.</li>
<li>Reproduce the problem on the site.</li>
<li>Go back to the tab. Read “Latest entries”, or download the file from the “Collected files” section.</li>
<li>When you&#8217;re done, press <strong>Turn off the debug log</strong>, or wait for it to expire. You&#8217;ll see “Debug log turned off. The files collected are still here below.”.</li>
</ol>
<p>The “Status:” line tells you whether the log is “on, switches off on dd/mm/yyyy hh:mm”, “off (expired on …)” or “off”. While the log is on you can change the size with <strong>Save size</strong>.</p>
<h3>Collected files</h3>
<p>The table lists name, size, and the <strong>Download</strong> and <strong>Delete</strong> buttons. Below you&#8217;ll find <strong>Delete all files</strong>. Before deleting, the plugin asks for confirmation: “Delete this file? This cannot be undone.”. For <strong>Delete all files</strong> the text is “Delete all debug log files? This cannot be undone.”. If there&#8217;s nothing you&#8217;ll read “No files: the log has never been switched on, or it hasn&#8217;t logged anything yet.”.</p>
<h3>Latest entries</h3>
<p>The box shows the 200 most recent entries, newest first. The <strong>All levels</strong> menu lets you filter by Fatal error, Parse error, Recoverable error, Warning, Notice or Deprecated. Then press <strong>Filter</strong>. For anything else, download the files. If the filter finds nothing, you&#8217;ll read “No entries match this filter.”.</p>
<p>An entry has this shape:</p>
<p><code>[2026-10-29 10:15:03 UTC] Warning: message in /path/file.php:12 | GET /page</code></p>
<ul>
<li>The time is in UTC, different from the site time shown in the <a href="https://www.cisilino.com/en/?p=984">Activity log</a>.</li>
<li>After the vertical bar you&#8217;ll find the method and path of the request, without the query string. From the command line or cron you&#8217;ll see “cli/cron”.</li>
<li>A multi-line message, such as a stack trace, stays a single entry, with the following lines indented.</li>
<li>The lines “Info: debug log enabled (user N)” and “Info: debug log disabled (user N)” carry no level: a filter hides them.</li>
</ul>
<h2>Default values and limits</h2>
<ul>
<li>Duration of the WordPress debug log: 1 hour, 24 hours or 7 days. Any other value becomes 24 hours.</li>
<li>Size per file: 1, 5, 10, 25 or 50 MB. The default is 5 MB. The chosen size is saved when you press <strong>Turn on the debug log</strong> or <strong>Save size</strong>. Watch out: <strong>Turn off the debug log</strong> resets the size to 5 MB, because that form doesn&#8217;t include the size menu.</li>
<li>Overall cap: 200 MB, adding up the <code>.log</code> and <code>.zip</code> files together.</li>
<li>Every message is truncated to 4000 characters.</li>
<li>It only logs PHP errors: not slow queries, JavaScript errors or HTTP requests.</li>
</ul>
<h2>Examples</h2>
<ul>
<li>A critical error after a plugin update: turn it on for 1 hour, reload the page, filter “Fatal error”. The entry shows the file and line, for example <code>/…/plugins/xyz/file.php:210 | GET /shop/</code>.</li>
<li>Occasional warnings: 24 hours, filter on Warning or Deprecated. If the file has been rotated, download the zip.</li>
<li>A slow site with no clear cause: 7 days with 25 MB files, then look for Notice and Warning entries that keep repeating.</li>
</ul>
<p>Keep it on for only as long as you need: often 1 hour is enough.</p>
<p><strong>Warning:</strong> the debug log files contain server paths and fragments of data. Don&#8217;t share them publicly. They stay on disk even after switching off and after uninstalling the plugin, which deletes the options but not the files. Delete them yourself when you&#8217;re finished. The overall cap is 200 MB.</p>
<p><strong>Warning:</strong> on an nginx server, turning it on can be refused until the server blocks the <code>csdn-debug-*</code> folder. The message is “Debug log not turned on: the files in its folder appear reachable from the internet (probably a server with no .htaccess support, such as nginx). The logs can contain paths and data: block access to the csdn-debug-* folder in the server configuration and try again.”. If you don&#8217;t manage the server yourself, ask whoever does.</p>
<p><strong>Warning:</strong> the log doesn&#8217;t see errors suppressed with <code>@</code>, nor ones generated before the plugin loads. For example, it doesn&#8217;t see errors from <code>wp-config.php</code>. The plugin&#8217;s WordPress debug log doesn&#8217;t replace the server&#8217;s own logs.</p>
<h2>What happens behind the scenes</h2>
<p>The WordPress debug log saves its files in a folder named <code>wp-content/uploads/csdn-debug-</code> followed by 16 random characters. Inside are an <code>index.php</code>, a <code>.htaccess</code> denying access, and the file in use, <code>csdn-debug.log</code>. On activation the plugin writes a test file and tries to read it over HTTP. If it responds, the plugin refuses to turn the log on.</p>
<p>When the file in use exceeds the chosen size, it is closed, compressed into a <code>.zip</code>, and a new one starts. No entry is lost. The original <code>.log</code> is only deleted once the zip has been verified. If the compression fails, the <code>.log</code> stays. “Latest entries” only reads from the file in use, so after a rotation the older entries sit inside the zip files.</p>
<p>Before rotating, the plugin checks the 200 MB cap. If it&#8217;s reached, the log stops so nothing gets overwritten. The yellow notice reads: “The log has stopped because the files reached the space cap (200 MB): to avoid overwriting data, it stops writing. Download or delete the files, then turn it back on.”. To start again, delete the files and turn the log back on.</p>
<p>On expiry the log switches itself off, but the files stay. The plugin never truncates or deletes them: only you do that, with <strong>Delete</strong> or <strong>Delete all files</strong>. For fatal errors, the entry is written at the end of the request.</p>
<h2>If the WordPress debug log doesn&#8217;t work</h2>
<ul>
<li>“Debug log not turned on: the uploads folder is not writable.”: check the permissions on the <code>wp-content/uploads</code> folder.</li>
<li>The log doesn&#8217;t write: if writing fails, the plugin reports it with an entry “Site debug log: …” in the “Last attempts” of the <a href="https://www.cisilino.com/en/?p=984">Activity log</a> tab.</li>
<li>The log has stopped for the cap: download what you need, delete the files, and turn it back on.</li>
</ul>
<p>The <a href="https://www.cisilino.com/en/?p=972">general guide to the manual</a> explains where this tab fits in. To understand the WordPress constants better, look at the <a href="https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/" target="_blank" rel="noopener">official WordPress debugging guide</a>: it explains <code>WP_DEBUG</code> and <code>WP_DEBUG_LOG</code>, which this plugin cannot replace.</p>
<p>Previous chapter: <a href="https://www.cisilino.com/en/?p=984">Activity log</a>. Next chapter: <a href="https://www.cisilino.com/en/?p=986">Troubleshooting and frequently asked questions</a>.</p><p>The post <a href="https://www.cisilino.com/en/2026/10/30/debug-log-php-errors-their-own-file/">Debug log: PHP errors in their own file</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.cisilino.com/en/2026/10/30/debug-log-php-errors-their-own-file/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Activity log WordPress: the CSDN tab</title>
		<link>https://www.cisilino.com/en/2026/10/30/activity-log-wordpress-csdn-tab/</link>
					<comments>https://www.cisilino.com/en/2026/10/30/activity-log-wordpress-csdn-tab/#respond</comments>
		
		<dc:creator><![CDATA[matteocisilino]]></dc:creator>
		<pubDate>Fri, 30 Oct 2026 16:05:53 +0000</pubDate>
				<category><![CDATA[CSDN manual]]></category>
		<category><![CDATA[activity log]]></category>
		<category><![CDATA[audit log]]></category>
		<category><![CDATA[Cisilino Site Defense Network]]></category>
		<guid isPermaLink="false">https://www.cisilino.com/?p=1055</guid>

					<description><![CDATA[<p>How to use the Activity log tab of the plugin CSDN: event groups, filters, retention, the row cap, sending to the panel and clearing it.</p>
<p>The post <a href="https://www.cisilino.com/en/2026/10/30/activity-log-wordpress-csdn-tab/">Activity log WordPress: the CSDN tab</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>The activity log WordPress keeps through the CSDN plugin is a local diary of who did what, and when, on your site. It records logins, users, content, plugins, themes and more. It&#8217;s there to help you reconstruct what happened.</p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" src="https://www.cisilino.com/wp-content/uploads/2026/10/manuale-csdn-registro-attivita.webp" alt="Diagram of WordPress with the Activity log WordPress tab of the plugin CSDN highlighted" width="1200" height="630"/></figure>
<h2>Where it is</h2>
<p>In the backend go to Settings &gt; Cisilino Site Defense Network (point 1 in the image). Open the <strong>Activity log</strong> tab (point 2). From top to bottom you&#8217;ll find these sections:</p>
<ul>
<li>point 3: “Activity log settings”.</li>
<li>point 4: the status row above the form, with the row counters.</li>
<li>point 5: “Panel delivery diagnostics”.</li>
<li>point 6: “Logged activity”, the table with the filters.</li>
<li>point 7: “Clear the local log”.</li>
</ul>
<h2>What the activity log WordPress keeps is for</h2>
<p>It helps you answer questions like “who deactivated that plugin?” or “which IP did that user log in from?”. Every event is a row in the site&#8217;s database table.</p>
<p>Don&#8217;t confuse it with the per-IP failed-login counter, which decides the blocks. They are two separate pieces of data, with different retention rules. A failed login attempt, though, also shows up here, one row per attempt.</p>
<p>For a long history and for serious searches, the panel is better. The local log also works without the panel. The connection is set up in <a href="https://www.cisilino.com/en/?p=974">Remote settings</a>.</p>
<h2>How to use it</h2>
<ol>
<li>Open the tab and look at the row “Rows in the local log: N — awaiting delivery to the panel: M”.</li>
<li>In the form, choose the settings described below.</li>
<li>Press <strong>Save log settings</strong>. You&#8217;ll see “Activity log settings saved.”.</li>
<li>To read the events go to “Logged activity”. Choose a group from the <strong>All groups</strong> menu, or type into the <strong>User, object or IP</strong> field, then press <strong>Filter</strong>.</li>
</ol>
<h3>The form settings</h3>
<ul>
<li>“Log activity on this site”: turn it off and no new rows are written. Old ones stay.</li>
<li>“Local retention (days)”: from 0 to 3650. With 0, nothing is deleted for age.</li>
<li>“Rows kept cap”: from 0 to 1,000,000. With 0 there&#8217;s no cap.</li>
<li>“Send activity to the panel”: requires the connection set up in Remote settings.</li>
<li>“Immediate delivery”: sending starts at the end of the request, without making the visitor wait. Turn it off, and sending happens only with the 15-minute synchronisation.</li>
<li>“What to log”: one box for each of the 18 event groups.</li>
</ul>
<h3>The event groups</h3>
<p>The groups carry these labels, identical in the “What to log” boxes and in the <strong>All groups</strong> menu: Logins (login, logout, failed attempts); Users (creation, profile edits, roles, deletion); Content (posts, pages, custom post types); Categories and tags; Comments; Media (attachments); Plugins (activation, deactivation, installation, update); Themes (theme switch, update, customisation); WordPress updates; WordPress settings; Navigation menus; Widgets; Theme/plugin file editor from wp-admin; Content export; File uploads (including those outside the media library); Plugin file integrity; Plugin settings (including this plugin&#8217;s own); Plugin lifecycle (deactivation, uninstallation, log clearing).</p>
<p>For WordPress settings only a selection of the main options is logged, for example <code>blogname</code>, <code>siteurl</code>, <code>admin_email</code>, <code>default_role</code> and <code>active_plugins</code>. For other plugins, only settings declared with <code>register_setting()</code> or saved through <code>options.php</code> are visible. The file editor logs the attempt, not the outcome.</p>
<h3>How to read the table</h3>
<p>The columns are When, User, IP, Group, Action, Detail and Sent. There are 50 rows per page, most recent first. Use <strong>Previous</strong> and <strong>Next</strong> to move around. If there&#8217;s nothing, you&#8217;ll read “No activity recorded (with these filters).”.</p>
<p>Group and Action appear with their raw name, for example <code>plugins</code> and <code>deactivated</code>. Anyone not logged in shows as “(not authenticated)”. In the Sent column you&#8217;ll find the panel&#8217;s confirmation date, or “—” if the row is still queued. The technical details field isn&#8217;t visible here: it&#8217;s read on the panel.</p>
<p>An example row: 12/10/2026 09:14:02, user mario (administrator), IP <code>203.0.113.5</code>, group <code>plugins</code>, action <code>deactivated</code>.</p>
<h3>Examples of reading it</h3>
<ul>
<li>The “Logins (login, logout, failed attempts)” group and a suspicious IP: a run of <code>failed</code> followed by a <code>success</code> can mean someone has guessed the password.</li>
<li>A <code>users</code> row with action <code>role_changed</code> and an unexpected user: check whether it&#8217;s a privilege escalation.</li>
<li>A row in the Uploads group with a block warning: someone tried to upload a dangerous file.</li>
</ul>
<h2>Default values for the activity log WordPress keeps</h2>
<ul>
<li>Logging on, sending to the panel on, immediate delivery on, every group active.</li>
<li>Retention: 30 days. The age-based deletion runs once a day.</li>
<li>Row cap: 500. The check runs every 100 inserts, so the table can exceed it by about 100 rows.</li>
<li>If you save with no group ticked, the log stays on but writes nothing.</li>
<li>It doesn&#8217;t log normal visits, and it doesn&#8217;t export data.</li>
</ul>
<p><strong>Warning:</strong> a failed login saves the username typed. If someone types their password into the username field, that text stays in the log, which can go to the panel. The plugin doesn&#8217;t filter it out. Keep this in mind when you share or read the log.</p>
<p><strong>Warning:</strong> the row cap (default 500) deletes the oldest rows even if they haven&#8217;t been sent to the panel yet. The cap takes priority over the delivery guarantee. On sites with a lot of unauthenticated traffic (failed logins, comments, file submissions), 500 rows can run out quickly. If you need the full history, raise the cap, but bear in mind that setting it to 0 removes the limit on disk space.</p>
<p><strong>Warning:</strong> “Clear activity log” is irreversible locally. It first asks for confirmation: “Clear the whole local activity log? This cannot be undone.”.</p>
<h2>What isn&#8217;t saved</h2>
<p>Plain-text passwords are never logged. When a profile is edited, only the fact that the password changed is saved. The plugin&#8217;s “API Key” field is shown as <code>***</code>. Options from other plugins whose name contains words like key, secret, token, password, auth, salt, nonce, license or credential have their value replaced with “*** (value not logged)”. Option values are truncated to 200 characters.</p>
<h2>Panel delivery diagnostics</h2>
<p>The section at point 5 is useful when activity isn&#8217;t reaching the panel. A failed send shows no visible error: the rows stay queued and retry. The only symptom is the “awaiting” counter that doesn&#8217;t drop.</p>
<p>The table shows, among other things, “Panel connection”, “Activity log”, “Sending to the panel”, “Immediate delivery”, “Rows queued”, “error_log() destination” and “Last send attempt”. Problem values are in red. If the last attempt shows fewer rows accepted than sent, you&#8217;ll see “Rows rejected by the panel”: those rows aren&#8217;t retried.</p>
<p>There are three buttons:</p>
<ul>
<li><strong>Try sending now</strong>: makes a test send immediately. The result appears in the table.</li>
<li><strong>Enable detailed logging</strong> (then <strong>Disable detailed logging</strong>): also logs successful sends.</li>
<li><strong>Clear diagnostic log</strong>: clears only the “Last attempts” list, which holds at most 25 entries. It only appears if there are entries.</li>
</ul>
<h2>What happens behind the scenes</h2>
<p>At the end of the request the plugin closes the response to the visitor, where the server allows it, and sends the rows to the panel in batches of at most 200, oldest first. A row counts as delivered only once the panel confirms receiving it. A synchronisation every 15 minutes acts as a safety net.</p>
<p>Age-based retention deletes old rows once a day. If sending is on and the panel is configured, it only deletes rows already confirmed. Otherwise it deletes purely by age.</p>
<p>Clearing the log first tries to send the backlog, then deletes everything. It logs the clearing event, which becomes the first row of the new log. It sends no delete command to the panel: the history already sent stays there. After clearing you&#8217;ll read “Local activity log cleared. History already sent to the panel was not touched.”. If there were rows never delivered, a bold warning tells you how many were lost.</p>
<h2>If the activity log WordPress keeps won&#8217;t send</h2>
<ul>
<li>The “awaiting” counter doesn&#8217;t drop: open the diagnostics, check the last attempt and the HTTP code, then press “Try sending now”.</li>
<li>A yellow box on the panel that doesn&#8217;t confirm: the panel may be out of date. The rows stay queued and nothing is lost.</li>
<li>Connection “NOT configured”: without a customer code, API key and URL nothing is sent. Go back to <a href="https://www.cisilino.com/en/?p=974">Remote settings</a>.</li>
</ul>
<p>For a wider guide to good logging practice, read the <a href="https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html" target="_blank" rel="noopener">OWASP logging guide</a>: it explains what&#8217;s worth logging and what to avoid.</p>
<p>Back to <a href="https://www.cisilino.com/en/?p=972">chapter 1, the index of the manual</a>. Previous chapter: <a href="https://www.cisilino.com/en/?p=983">Rate limiting</a>. Next chapter: <a href="https://www.cisilino.com/en/?p=985">Debug log</a>.</p><p>The post <a href="https://www.cisilino.com/en/2026/10/30/activity-log-wordpress-csdn-tab/">Activity log WordPress: the CSDN tab</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.cisilino.com/en/2026/10/30/activity-log-wordpress-csdn-tab/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Rate limiting: limits on authors and visitors</title>
		<link>https://www.cisilino.com/en/2026/10/30/rate-limiting-limits-authors-visitors/</link>
					<comments>https://www.cisilino.com/en/2026/10/30/rate-limiting-limits-authors-visitors/#respond</comments>
		
		<dc:creator><![CDATA[matteocisilino]]></dc:creator>
		<pubDate>Fri, 30 Oct 2026 16:05:51 +0000</pubDate>
				<category><![CDATA[CSDN manual]]></category>
		<category><![CDATA[Cisilino Site Defense Network]]></category>
		<category><![CDATA[rate limiting]]></category>
		<category><![CDATA[user suspension]]></category>
		<guid isPermaLink="false">https://www.cisilino.com/?p=1054</guid>

					<description><![CDATA[<p>How to use the Rate limiting tab of the plugin CSDN: limits on authors and visitors, default values, suspensions and revoking them.</p>
<p>The post <a href="https://www.cisilino.com/en/2026/10/30/rate-limiting-limits-authors-visitors/">Rate limiting: limits on authors and visitors</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>Rate limiting WordPress offered by CSDN puts a cap on write abuse. On one side are authors who publish too much content in too little time, for example through a compromised account. On the other are visitors who send too many comments or contact forms. Each cap switches on and adjusts itself.</p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" src="https://www.cisilino.com/wp-content/uploads/2026/10/manuale-csdn-rate-limiting.webp" alt="Diagram of WordPress with the Rate limiting WordPress tab of the plugin CSDN highlighted" width="1200" height="630"/></figure>
<h2>Where it is</h2>
<p>Go to <strong>Settings</strong> and choose <strong>Cisilino Site Defense Network</strong> (point 1 in the image). Open the “Rate limiting” tab (point 2). Saving requires the <code>manage_options</code> permission; on multisite you need <code>manage_network_options</code>.</p>
<p>There are four sections. Point 3 is “How it works, in practice: what gets counted”. Point 4 is “1. Authors: publishing too often”. Point 5 is “2. Visitors: comments and contact forms”. Point 6 is “Currently suspended users”. All time values are in seconds.</p>
<h2>What it&#8217;s for</h2>
<p>The cap on authors stops an account publishing at full speed before it fills the site with content. The cap on visitors slows anyone flooding comments and forms. The code also knows a third cap, the mandatory email. You&#8217;ll find it in the “User registration” tab, described in the <a href="https://www.cisilino.com/en/?p=982">previous chapter</a>.</p>
<h2>How to use it</h2>
<h3>What gets counted (point 3)</h3>
<p>The info box explains the rules. For authors, the check fires when WordPress saves a post or a page. The plugin counts how many posts and pages by that author have a creation or publication date within the last T seconds. If there are more than N, the author is suspended. The save that crosses the threshold goes through fine: the suspension blocks the ones that follow.</p>
<p>Plugins and themes don&#8217;t count, nor do logins, edits to content older than the window, auto-drafts, revisions, the trash, media, comments or other content types. Temporary environments, like the Plugin Check test one, are ignored.</p>
<p><strong>Warning:</strong> the example written in that info box still quotes N=3. It&#8217;s old text. The real default value is 150 items in 5 minutes, from version 1.0.13.</p>
<h3>Authors (point 4)</h3>
<ol>
<li>Tick “Rate limit active” to limit authors&#8217; publishing.</li>
<li>Decide whether to keep “Email alert”: you get a mail when an author is suspended.</li>
<li>Set “N: allowed items”, from 1 to 1000. Default 150.</li>
<li>Set “T: window (seconds)”, from 10 to 86400. Default 300, meaning 5 minutes.</li>
<li>Set “S: suspension (seconds)”, from 60 to 2592000. Default 3600, meaning 1 hour.</li>
<li>Press <strong>Save rate limiting settings</strong>.</li>
</ol>
<p>The mail goes to the admin address set under Settings &gt; General. It contains the user, the content within the window, the expiry, and a list of up to 20 recent items to check. The suspension doesn&#8217;t change that content.</p>
<h3>Visitors (point 5)</h3>
<ol>
<li>Tick “Rate limit active” to limit guest submissions.</li>
<li>“Email alert” is off by default. On an exposed site it could generate a lot of mail. It goes to the same admin address under Settings &gt; General, once per block.</li>
<li>“N: allowed submissions”, from 1 to 100. Default 2.</li>
<li>“T: window (seconds)”, from 5 to 3600. Default 60.</li>
<li>“S: IP block (seconds)”, from 60 to 2592000. Default 3600.</li>
</ol>
<p>This cap only concerns people who aren&#8217;t logged in. It counts submissions by IP and by type, comments or forms. A block on comments doesn&#8217;t block forms. The contact forms covered are Contact Form 7&#8217;s. A rejected comment shows “Too many submissions” with a 429 error.</p>
<p>If a value is outside the limits, the plugin moves it to the nearest allowed one. Saving shows “Rate limiting settings saved. Values outside the allowed limits have been moved to the nearest one.”</p>
<h2>Rate limiting WordPress: suspensions and blocks</h2>
<p>A suspended author keeps their role and can still use the rest of the admin panel. They lose, though, the permission to create and publish posts and pages. “Add New Post” and the pages menu items disappear, and opening those screens gives “permission denied”. An unclosable notice appears in the dashboard.</p>
<p><strong>Warning:</strong> author suspension affects administrators too. A suspended administrator loses the ability to create and publish, but can still open Settings and revoke their own suspension. There&#8217;s no list of exceptions for users, roles or IPs: the IP whitelist in the General tab doesn&#8217;t exempt anyone from rate limiting.</p>
<p><strong>Warning:</strong> the visitor block is by IP. Several people behind the same IP, such as an office, can be blocked together. In that case raise N. The plugin only reads the connecting address (<code>REMOTE_ADDR</code>) and not proxy or CDN headers: behind a reverse proxy or a CDN every visitor can appear with the same IP and end up blocking each other.</p>
<h3>How to revoke a suspension</h3>
<p>You have two routes.</p>
<ol>
<li>Wait. The suspension ends on its own after S seconds.</li>
<li>In the section at point 6, “Currently suspended users”, press <strong>Revoke suspension</strong> on the user&#8217;s row. You&#8217;ll see “Suspension revoked: the user can create and publish content again.” If the table is empty, you&#8217;ll read “No suspended users.”</li>
</ol>
<p>The table shows at most 100 users. The dashboard notices carry the links “Revoke the suspension” and “Check and revoke”, which lead to the same tab.</p>
<p>Switching off “Rate limit active” doesn&#8217;t remove a suspension already in progress. To remove it you have to revoke it, or wait for it to expire.</p>
<h2>What happens behind the scenes</h2>
<p>The suspension is information saved on the user, with an expiry date. For guests, every submission is logged for 24 hours in a plugin table, then counted within the window. If two requests arrive together, one extra may slip through. Suspensions and blocks land in the Activity log, if it&#8217;s on and if the Users and Comments groups are enabled.</p>
<p><strong>Warning:</strong> a legitimate bulk import can trip the cap on authors. Before a migration, switch off the cap or raise N.</p>
<h2>Examples of rate limiting WordPress</h2>
<ul>
<li>A blog with a single author: you can lower N to 10 or 20 with T=300. You&#8217;ll catch a compromised account sooner. These are trial values, not a rule of the plugin.</li>
<li>A newsroom that duplicates or imports pages: keep 150/300 or higher.</li>
<li>Offices with a shared IP: raise visitors&#8217; allowed submissions to 3 or 5.</li>
</ul>
<p>Useful conversions: 300 seconds is 5 minutes, 3600 is 1 hour, 86400 is 1 day. To learn more about the general topic, read the OWASP guide on <a href="https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks" target="_blank" rel="noopener">Blocking Brute Force Attacks</a>, which explains why limiting repeated attempts matters.</p>
<p>Previous: <a href="https://www.cisilino.com/en/?p=982">User registration: who can create accounts</a>. Next: <a href="https://www.cisilino.com/en/?p=984">Activity log: what happened on the site</a>. For the general index go to <a href="https://www.cisilino.com/en/?p=972">chapter 1 of the manual</a>.</p><p>The post <a href="https://www.cisilino.com/en/2026/10/30/rate-limiting-limits-authors-visitors/">Rate limiting: limits on authors and visitors</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.cisilino.com/en/2026/10/30/rate-limiting-limits-authors-visitors/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>User registration: who can create accounts</title>
		<link>https://www.cisilino.com/en/2026/10/30/user-registration-who-can-create-accounts/</link>
					<comments>https://www.cisilino.com/en/2026/10/30/user-registration-who-can-create-accounts/#respond</comments>
		
		<dc:creator><![CDATA[matteocisilino]]></dc:creator>
		<pubDate>Fri, 30 Oct 2026 16:05:49 +0000</pubDate>
				<category><![CDATA[CSDN manual]]></category>
		<category><![CDATA[Cisilino Site Defense Network]]></category>
		<category><![CDATA[user registration]]></category>
		<category><![CDATA[WordPress roles]]></category>
		<guid isPermaLink="false">https://www.cisilino.com/?p=1053</guid>

					<description><![CDATA[<p>How to use the User registration tab of the plugin CSDN: policy, allowed roles, mandatory email and the limits of this protection.</p>
<p>The post <a href="https://www.cisilino.com/en/2026/10/30/user-registration-who-can-create-accounts/">User registration: who can create accounts</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>The “User registration” tab decides who can create new accounts on your site, and with which role. It&#8217;s the defence against hidden administrators, meaning accounts created secretly to get back onto the site after an attack. User registration WordPress is governed from here. In this chapter you&#8217;ll see the registration policy, the allowed roles and the mandatory email address.</p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" src="https://www.cisilino.com/wp-content/uploads/2026/10/manuale-csdn-registrazione-utenti.webp" alt="Diagram of WordPress with the User registration WordPress tab of the plugin CSDN highlighted" width="1200" height="630"/></figure>
<h2>Where it is</h2>
<p>In the WordPress menu open <strong>Settings</strong> and then <strong>Cisilino Site Defense Network</strong> (point 1 in the image). Choose the “User registration” tab (point 2). Saving requires the <code>manage_options</code> permission; on multisite you need <code>manage_network_options</code>.</p>
<p>There are three sections. Point 3 is “Registration policy”. Point 4 is “Allowed roles (only at the &#8220;low-privilege roles&#8221; level)”. Point 5 is “Mandatory email”.</p>
<h2>What it&#8217;s for</h2>
<p>The policy applies to every route of account creation: the wp-admin panel, the REST API, XML-RPC, WP-CLI, and any plugin or theme using WordPress&#8217;s own functions to create users. The check is done in PHP, without touching the <code>.htaccess</code> file.</p>
<h2>How to use it</h2>
<h3>Registration policy (point 3)</h3>
<p>Choose a single level out of three. They don&#8217;t add up.</p>
<ul>
<li>“No restriction (disabled)”: the module is off and WordPress behaves as usual.</li>
<li>“Low-privilege roles only (never administrator/editor/author)”: this is the default level. The allowed roles at point 4 apply.</li>
<li>“No registration (exclusive)”: no new user can be created at all.</li>
</ul>
<h3>Allowed roles (point 4)</h3>
<p>This only applies at the low-privilege roles level. You can tick <code>subscriber</code> (ticked by default), <code>contributor</code> and <code>customer</code> (useful with WooCommerce). The <code>administrator</code>, <code>editor</code>, <code>author</code> and <code>shop_manager</code> boxes are always disabled, marked “never allowed”.</p>
<h3>Mandatory email (point 5)</h3>
<p>The box “Don&#8217;t create users without a valid email address” is on by default. It stops users being created without a valid email, through any route. It doesn&#8217;t touch users who already exist. This setting is saved together with the rate limiting ones, but is managed here.</p>
<p>At the end, press <strong>Save registration policy</strong>. You&#8217;ll see “User registration policy saved.” The save lands in the Activity log, under the label “User registration”.</p>
<h2>User registration WordPress: default values and limits</h2>
<ul>
<li>The default policy is “Low-privilege roles only”, active even if you&#8217;ve never saved anything.</li>
<li>The starting allowed role is <code>subscriber</code> alone.</li>
<li>Forbidden roles are always discarded, even if someone tries to submit them by hand.</li>
<li>The list of roles is fixed: it doesn&#8217;t show your site&#8217;s custom roles.</li>
<li>There are no email domain lists, captchas or anti-spam checks on registrations.</li>
</ul>
<p><strong>Warning:</strong> with “No registration (exclusive)” nobody can create users, not even the administrator. The “Add New User” item disappears from the menu, and opening <code>user-new.php</code> by hand gives a 403 error. If, at the low-privilege roles level, you untick every role, the list stays empty and no user is allowed at all. Here, though, the menu item and the page stay visible: the 403 error only arrives when you try to create the user.</p>
<p>With the default level you can&#8217;t create an editor or an author, not even as an administrator. The plugin makes no exception for someone already logged in. To create a user with a high role, switch temporarily to “No restriction”, create the user, and then switch back.</p>
<p>Also check the “New user default role” under Settings &gt; General in WordPress. If it&#8217;s a forbidden role, such as Editor, every registration without an explicit role is rejected.</p>
<h2>What happens behind the scenes</h2>
<p>The main check acts on the <code>pre_insert_user_data</code> filter, only when a user is created. Changes to existing users always go through. A rejected attempt shows the title “Registration not allowed” with a 403 error. On the REST API you get a 403 JSON error instead of the page.</p>
<p>With any policy active, the plugin removes the XML-RPC method <code>wp.newUser</code>. With the exclusive policy it also forces WordPress&#8217;s “Anyone can register” option to false. At the low-privilege level, that option stays whatever you chose.</p>
<p>There&#8217;s also a safety net after creation. If an account is somehow created in violation of the policy, the plugin immediately strips its role and writes an event to the Activity log. The account isn&#8217;t deleted, so you can examine it.</p>
<p><strong>Warning:</strong> a compromised plugin or theme writing straight to the users table with a database INSERT doesn&#8217;t pass through any filter. No PHP plugin can stop that. The user registration WordPress protection in this tab is a strong barrier, but it isn&#8217;t absolute.</p>
<h2>Examples</h2>
<ul>
<li>A showcase site with no public users: choose “No registration (exclusive)”.</li>
<li>A site with subscribers or comments: leave the default level with <code>subscriber</code>.</li>
<li>A shop with WooCommerce: add <code>customer</code>.</li>
<li>You need to add a collaborator with a high role: use “No restriction” only for as long as needed.</li>
</ul>
<h2>If something goes wrong</h2>
<p>If a sign-up is rejected with the message about a role not being allowed, check WordPress&#8217;s default role and the roles ticked at point 4. The Activity log tells you if an account has had its role stripped by the safety net. To understand the roles better, read the page on <a href="https://wordpress.org/documentation/article/roles-and-capabilities/" target="_blank" rel="noopener">roles and capabilities in the WordPress documentation</a>. It lists what each role can do.</p>
<p>Previous: <a href="https://www.cisilino.com/en/?p=981">Paranoic Hardening: security headers and the admin session</a>. Next: <a href="https://www.cisilino.com/en/?p=983">Rate limiting: limits on authors and visitors</a>. For the general index go to <a href="https://www.cisilino.com/en/?p=972">chapter 1 of the manual</a>.</p><p>The post <a href="https://www.cisilino.com/en/2026/10/30/user-registration-who-can-create-accounts/">User registration: who can create accounts</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.cisilino.com/en/2026/10/30/user-registration-who-can-create-accounts/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Paranoic Hardening: headers and autologout</title>
		<link>https://www.cisilino.com/en/2026/10/30/paranoic-hardening-headers-autologout/</link>
					<comments>https://www.cisilino.com/en/2026/10/30/paranoic-hardening-headers-autologout/#respond</comments>
		
		<dc:creator><![CDATA[matteocisilino]]></dc:creator>
		<pubDate>Fri, 30 Oct 2026 16:05:46 +0000</pubDate>
				<category><![CDATA[CSDN manual]]></category>
		<category><![CDATA[Cisilino Site Defense Network]]></category>
		<category><![CDATA[HSTS]]></category>
		<category><![CDATA[security headers]]></category>
		<guid isPermaLink="false">https://www.cisilino.com/?p=1052</guid>

					<description><![CDATA[<p>How to use the Paranoic Hardening tab of the plugin CSDN: HTTP headers, HSTS, the check and autologout, with the recommended order and risks.</p>
<p>The post <a href="https://www.cisilino.com/en/2026/10/30/paranoic-hardening-headers-autologout/">Paranoic Hardening: headers and autologout</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></description>
										<content:encoded><![CDATA[<p>The “<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Paranoic Hardening” tab of the CSDN plugin brings together the most delicate options: the HTTP security headers, HSTS and the automatic logout of inactive administrators. Here you change the behaviour of the visitor&#8217;s browser, not just the server&#8217;s. That&#8217;s why it&#8217;s all off by default.</p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" src="https://www.cisilino.com/wp-content/uploads/2026/10/manuale-csdn-paranoic-hardening.webp" alt="Diagram of WordPress with the Paranoic Hardening tab of the plugin CSDN highlighted" width="1200" height="630"/></figure>
<h2>Where it is</h2>
<p>In the WordPress side menu go to <strong>Settings</strong> and choose <strong>Cisilino Site Defense Network</strong> (point 1 in the image). Open the “<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Paranoic Hardening” tab (point 2). Saving requires the <code>manage_options</code> permission; on multisite you need <code>manage_network_options</code>.</p>
<p>The tab has four sections. At point 3 you&#8217;ll find “Paranoic Hardening — HTTP security headers”. At point 4 there&#8217;s “HTTP Strict Transport Security (HSTS)”. Point 5 is “Security header check”. Point 6 is “Autologout of inactive administrators”.</p>
<h2>What it&#8217;s for</h2>
<p>Headers are instructions the site sends the browser along with every page. The plugin sends them through WordPress&#8217;s <code>send_headers</code> hook, without touching the <code>.htaccess</code> file. So you don&#8217;t risk a 500 error, and they work even without <code>mod_headers</code>.</p>
<p>The headers only cover the public site. They are never sent in the admin area. The plugin offers no Content-Security-Policy, and it doesn&#8217;t send X-XSS-Protection.</p>
<h2>How to use Paranoic Hardening</h2>
<h3>HTTP security headers (point 3)</h3>
<ul>
<li><strong>X-Content-Type-Options</strong> sends <code>nosniff</code>. The browser stops “guessing” a file&#8217;s type. The risk here is practically nil.</li>
<li><strong>X-Frame-Options</strong> sends <code>SAMEORIGIN</code>. The site can no longer be embedded in an <code>&lt;iframe&gt;</code> on another domain. If a partner site shows your pages, it will stop doing so.</li>
<li><strong>Referrer-Policy</strong> sends <code>strict-origin-when-cross-origin</code>. Towards other domains only the domain travels, not the path. Third-party statistics tools wanting the full referrer won&#8217;t get it.</li>
</ul>
<p>Tick the boxes you need and press <strong>Save Paranoic Hardening</strong>. You&#8217;ll see the notice “Paranoic Hardening settings saved and applied.” Boxes you don&#8217;t tick are saved as off.</p>
<h3>HSTS (point 4)</h3>
<p>HSTS tells the browser to always use https with your domain. There are three boxes: “Enable HSTS”, “includeSubDomains” and “Preload”. The header sent carries <code>max-age=31536000</code>, meaning one year. The value is fixed and cannot be changed.</p>
<p>The plugin refuses to activate it if the page wasn&#8217;t opened over https. In that case it saves the rest and shows a red warning: “Settings saved, but HSTS was NOT activated: this request did not arrive over https. Open the panel over https and try again.” If the page is over http, the three boxes are also disabled.</p>
<p>If you turn off “Enable HSTS”, on saving “includeSubDomains” and “Preload” are reset too. If you turn HSTS back on, you&#8217;ll need to tick them again.</p>
<h3>Security header check (point 5)</h3>
<p>Press <strong>Check now</strong>. The plugin makes a real request to the site&#8217;s home page and checks which headers genuinely arrive. The result appears in the box, with the date of the last test.</p>
<ul>
<li>Green: “All the expected headers are present in the site&#8217;s real response.”</li>
<li>Red: the active headers that didn&#8217;t arrive. This can be a proxy, a CDN or another plugin removing them. HSTS shows as missing even if the home address is http rather than https, because the plugin only sends it on https requests.</li>
<li>Blue: “No active header to check: enable at least one option above and save.”</li>
<li>Red with “Check request failed”: the request didn&#8217;t succeed.</li>
</ul>
<p>The test checks whether a header is present, not its value. It doesn&#8217;t run on its own: you have to press it.</p>
<h3>Autologout of administrators (point 6)</h3>
<p>This section of Paranoic Hardening has its own button, <strong>Save autologout for administrators</strong>. Tick “Enable” to log out inactive administrators. Then set the “Inactivity timeout (seconds)”. If the browser blocks <code>localStorage</code> (in a private window, for instance), the check never fires and you&#8217;re never logged out.</p>
<p>The default value is 900, meaning 15 minutes. The minimum is 60 and the maximum is 86400. If you write a number outside those limits, the plugin moves it to the nearest allowed value. For example, 30 becomes 60. The notice stays green, so reread the number in the field after saving.</p>
<p>Only users with the <code>manage_options</code> permission are logged out. Editors and authors aren&#8217;t touched. Inactivity is measured in the browser: mouse, keyboard, scrolling and touch all count. The session closes just as with “Log Out”, and unsaved changes in an open form are lost.</p>
<h2>Recommended order of activation</h2>
<ol>
<li>Open the panel over https.</li>
<li>Turn on X-Content-Type-Options, save and press “Check now”.</li>
<li>Turn on Referrer-Policy, save and check.</li>
<li>Check that no site embeds yours, then turn on X-Frame-Options, save and check.</li>
<li>Turn on autologout with a generous timeout, for example 1800. Lower it only after a few days.</li>
<li>Last of all, consider HSTS, without includeSubDomains and without Preload.</li>
</ol>
<p>Turn on one option at a time. If something breaks, you&#8217;ll know straight away which one did it.</p>
<h2>The risk of HSTS, includeSubDomains and Preload</h2>
<p><strong>Warning:</strong> HSTS can&#8217;t be undone from the site. If you untick it, the plugin stops sending the header, but browsers that already received it will remember it until it expires. The plugin never sends <code>max-age=0</code>, so there&#8217;s no “cancel”. The tab&#8217;s own banner says so too: the effects can stay visible for weeks or months.</p>
<p>With HSTS on, the browser refuses any non-https connection to the domain. If the certificate expires or breaks, the browser no longer even shows the “proceed anyway” screen. The site becomes unreachable from that browser.</p>
<ul>
<li><strong>includeSubDomains</strong> extends the rule to every subdomain. A single subdomain without valid https, even a test one or a future one, becomes unreachable for anyone who has already visited the site. Only turn it on if every subdomain is, and will remain, https.</li>
<li><strong>Preload</strong> only adds the <code>preload</code> flag to the header. On its own it doesn&#8217;t register the site: submitting it to the browsers&#8217; list is done by hand on hstspreload.org. The list sits inside the browsers, and getting out of it takes weeks. Treat Preload as a final, one-way decision.</li>
</ul>
<p>Always save from the https version of the panel. Disabled boxes aren&#8217;t sent by the browser: saving from an http page switches off HSTS and its sub-options.</p>
<h2>What happens behind the scenes</h2>
<p>The Paranoic Hardening settings are WordPress options, not server rules. Autologout prints a script only on admin pages. The script records the last activity in the browser&#8217;s <code>localStorage</code> and checks the timeout every 5 seconds. On expiry it asks <code>admin-ajax.php</code> to log you out and takes you to the login page. The save only lands in the Activity log if you actually changed something.</p>
<h2>If something goes wrong</h2>
<ul>
<li>The box turns red after “Check now”: a proxy, a CDN or another plugin is stripping the headers. Check their configuration.</li>
<li>A partner site no longer shows your pages: untick X-Frame-Options and save.</li>
<li>You can&#8217;t turn on HSTS: reopen the panel with the https address.</li>
<li>To check the headers by hand, use your browser&#8217;s developer tools or <code>curl -I</code> on the site&#8217;s https address.</li>
</ul>
<p>To understand HSTS better, read the page on <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security" target="_blank" rel="noopener">Strict-Transport-Security on MDN</a>. It explains max-age, includeSubDomains and preload precisely.</p>
<p>Previous: <a href="https://www.cisilino.com/en/?p=980">Test tab: checking that the protections work</a>. Next: <a href="https://www.cisilino.com/en/?p=982">User registration: who can create accounts</a>. For the general index go to <a href="https://www.cisilino.com/en/?p=972">chapter 1 of the manual</a>.</p><p>The post <a href="https://www.cisilino.com/en/2026/10/30/paranoic-hardening-headers-autologout/">Paranoic Hardening: headers and autologout</a> first appeared on <a href="https://www.cisilino.com/en/">Matteo Cisilino</a>.</p>]]></content:encoded>
					
					<wfw:commentRss>https://www.cisilino.com/en/2026/10/30/paranoic-hardening-headers-autologout/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
