<?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/"
	 xmlns:media="http://search.yahoo.com/mrss/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" >

<channel>
	<title>Kaushal Bhavsar</title>
	<atom:link href="https://kaushalbhavsar.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://kaushalbhavsar.com</link>
	<description></description>
	<lastBuildDate>Thu, 22 Oct 2026 11:17:28 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.2</generator>
	<itunes:subtitle>Kaushal Bhavsar</itunes:subtitle>
	<itunes:summary></itunes:summary>
	<itunes:explicit>clean</itunes:explicit>
	<item>
		<title>What I Check Before Letting an AI Agent Run a Task</title>
		<link>https://kaushalbhavsar.com/knowledgabase/security-checks-before-ai-agent-task/</link>
					<comments>https://kaushalbhavsar.com/knowledgabase/security-checks-before-ai-agent-task/#respond</comments>
		
		<dc:creator><![CDATA[Kaushal Bhavsar]]></dc:creator>
		<pubDate>Thu, 22 Oct 2026 02:53:00 +0000</pubDate>
				<category><![CDATA[Knowledge Base]]></category>
		<guid isPermaLink="false">https://kaushalbhavsar.com/?p=3638</guid>

					<description><![CDATA[Before giving an AI agent a task, I would review its permissions, inputs, action limits and verification process. A convincing answer is not evidence that an external action succeeded.]]></description>
										<content:encoded><![CDATA[<p>An AI assistant that suggests a command and an agent that executes it have different responsibilities. Once a system can edit files, query data or call external services, the task needs controls around those actions.</p>
<p>Before giving an agent access, I would ask what it can reach, what it can change and how I will verify the result.</p>
<p>A capable model does not remove the need for those boundaries. It makes their design more important because the system can perform more work between instructions.</p>
<h2>Define the permitted outcome</h2>
<p>“Fix the application” is too broad to describe an agent’s authority. I would specify the relevant project, the intended change, the checks it may run and the actions that require further approval.</p>
<p>For a fictional maintenance task, the agent might edit a local branch and run tests, while deployment remains a separate step. It would not need access to unrelated repositories, customer exports or production credentials.</p>
<p>The tool interface and credentials should enforce that scope where possible. A prompt asking the model to be careful cannot compensate for an unnecessarily powerful account.</p>
<h2>Treat retrieved material as data</h2>
<p>An agent may read web pages, email, repository files and tool output. Those sources can contain instructions placed by somebody other than the user.</p>
<p>For example, a fictional support ticket could tell an agent to upload a configuration file to an external address “for debugging.” That text is part of the ticket being examined. It does not grant permission to transmit the file.</p>
<p>This is the practical risk behind indirect prompt injection. I would limit what the agent can disclose or execute even if it misinterprets a source. Content filtering can contribute, but it should not be the only protection.</p>



<p>A proposed tool action should pass scope and permission checks before execution, then be verified against the external result.</p>


<figure class="kb-mermaid" data-kb-mermaid-format="svg"><div class="kb-mermaid__frame"><pre class="mermaid">flowchart TD

 A[&quot;Proposed tool action&quot;] --&gt; B{&quot;Scope, permissions and arguments valid?&quot;}

 B --&gt;|No| X[&quot;Block and report&quot;]

 B --&gt;|Yes| C{&quot;Required approval obtained?&quot;}

 C --&gt;|No| X

 C --&gt;|Yes or not required| D[&quot;Execute scoped action&quot;]

 D --&gt; E{&quot;External outcome verified?&quot;}

 E --&gt;|Yes| F[&quot;Report completion&quot;]

 E --&gt;|No| G[&quot;Report unresolved state&quot;]</pre></div></figure>


<h2>Validate actions outside the model</h2>
<p>Before a tool runs, I would validate the arguments against the allowed operation. Is this path inside the project? Is this recipient authorised? Is this database operation read-only? Does the requested network destination belong to the task?</p>
<p>For high-impact actions, the user should be able to inspect a concrete proposed result. Approval is more meaningful when it shows the exact change, destination and effect than when it asks permission to “continue.”</p>
<p>Reversible tasks can use scoped write access and recovery mechanisms. Irreversible actions need stronger controls appropriate to their consequences.</p>
<h2>Set limits on the run</h2>
<p>I would bound iterations, execution time and resource use, and define what happens after repeated failures. An agent that retries indefinitely can increase cost or repeat a damaging action.</p>
<p>The audit record should identify the tools used, decisions made and outcomes without unnecessarily retaining secrets or sensitive source material. Recovery also needs thought: restoring a file cannot unsend an email or undo a disclosure.</p>
<h2>Verify the external result</h2>
<p>A model’s statement that a task is complete is not sufficient evidence. I would inspect the changed files, test the intended behaviour or read the service’s authoritative result.</p>
<p>Submission and completion are different states. A successful API call may only have queued a job. A local test may pass while the deployed application remains unchanged.</p>
<p>My acceptance check would therefore be defined before execution. If the task is to change a configuration, what observation will prove the new configuration is active? If the agent cannot obtain that evidence, its report should say what it changed and what remains unverified.</p>
<h3>References</h3>
<ul>
<li><a href="https://cheatsheetseries.owasp.org/cheatsheets/LLM_Prompt_Injection_Prevention_Cheat_Sheet.html" target="_blank" rel="noopener">OWASP: LLM Prompt Injection Prevention</a></li>
<li><a href="https://genai.owasp.org/glossaries/prompt-injection/" target="_blank" rel="noopener">OWASP GenAI Security Project: Prompt injection</a></li>
</ul>]]></content:encoded>
					
					<wfw:commentRss>https://kaushalbhavsar.com/knowledgabase/security-checks-before-ai-agent-task/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How I Would Test Whether a Cybersecurity Quiz Measures Understanding</title>
		<link>https://kaushalbhavsar.com/knowledgabase/cybersecurity-quiz-understanding-vs-recall/</link>
					<comments>https://kaushalbhavsar.com/knowledgabase/cybersecurity-quiz-understanding-vs-recall/#respond</comments>
		
		<dc:creator><![CDATA[Kaushal Bhavsar]]></dc:creator>
		<pubDate>Thu, 22 Oct 2026 02:52:00 +0000</pubDate>
				<category><![CDATA[Knowledge Base]]></category>
		<guid isPermaLink="false">https://kaushalbhavsar.com/?p=3636</guid>

					<description><![CDATA[A learner can remember terminology without being ready to investigate a problem. I describe how I would evaluate cybersecurity questions for reasoning, clarity and useful feedback.]]></description>
										<content:encoded><![CDATA[<p>While building InfoSecQuiz, I have been thinking about what a correct answer actually demonstrates. Remembering the expansion of an acronym is useful knowledge, but it is different from choosing the next step in an investigation.</p>
<p>My view is that an assessment should be clear about which ability it measures. Recall questions have a place. They should not carry claims about practical readiness that the questions cannot support.</p>
<h2>Define the ability before writing the question</h2>
<p>I would start with a specific objective: recognise a term, interpret evidence, identify a missing control or choose between plausible actions.</p>
<p>Then I would write the question to exercise that ability. Adding a long story to an acronym question does not automatically turn it into a scenario-based assessment. The learner must need the scenario’s facts to answer it.</p>
<p>A useful test is to remove the scenario. If the answer remains obvious from a keyword, the item may still be measuring recall.</p>
<h2>Make the evidence matter</h2>
<p>Consider this illustrative question:</p>
<blockquote><p>An administrator removes a malicious file from a website. The file reappears later. The site is still online, and relevant logs are available. Which next action best helps establish how the attacker is retaining access?</p></blockquote>
<p>The answer options could compare preserving and correlating evidence, repeatedly deleting the file, changing the site’s appearance and assuming a new hosting provider will solve the problem.</p>
<p>That is a starting point, but the distracting options are too weak for an advanced assessment. A stronger version would offer several reasonable investigative steps and supply enough context to justify one priority. Otherwise, learners can answer by eliminating obviously irrelevant choices.</p>
<p>I would also avoid claiming there is one correct operational sequence when the scenario lacks facts about active harm, business impact or available containment options.</p>
<h2>Review the explanation as carefully as the answer</h2>
<p>The explanation should identify which fact makes the preferred answer appropriate and why the other choices are weaker under the stated conditions.</p>
<p>It should also explain what would change the answer. For example, evidence of ongoing data theft may make immediate containment more urgent than the sequence suggested by a less active scenario.</p>
<p>That teaches conditional reasoning. “Option B is correct because it is best practice” gives the learner little they can transfer to another problem.</p>



<p>Question quality improves through review of the reasoning required and the answers learners actually give.</p>


<figure class="kb-mermaid" data-kb-mermaid-format="svg"><div class="kb-mermaid__frame"><pre class="mermaid">flowchart TD

 A[&quot;Define the ability&quot;] --&gt; B[&quot;Write question and explanation&quot;]

 B --&gt; C{&quot;Scenario facts needed?&quot;}

 C --&gt;|No| D[&quot;Revise or label as recall&quot;]

 D --&gt; B

 C --&gt;|Yes| E[&quot;Review and trial the item&quot;]

 E --&gt; F{&quot;Ambiguity or weak distractors?&quot;}

 F --&gt;|Yes| B

 F --&gt;|No| G[&quot;Use for the stated ability&quot;]

 G --&gt; H[&quot;Review response patterns&quot;]

 H --&gt; B</pre></div></figure>


<h2>Examine how people answer</h2>
<p>I would review response patterns after questions are used. Which distractors are selected? Does an item consistently confuse otherwise capable learners? Are there comments pointing to ambiguous wording or more than one defensible answer?</p>
<p>Response time can provide context, but I would not equate speed with understanding. Language, accessibility and reading effort affect it too.</p>
<p>I would keep practice and assessment conditions separate. Repeated exposure can improve a score through familiarity, so that result should not be presented as independent evidence of new competence.</p>
<h2>Keep the claim proportional to the test</h2>
<p>A multiple-choice quiz can examine selected knowledge and decisions. It cannot, on its own, establish that somebody can investigate an unfamiliar live incident, write secure code or communicate under pressure.</p>
<p>For those claims, I would add practical tasks and review the work produced. The quiz can help identify what to practise next. Its value increases when the learner understands exactly what the result does and does not measure.</p>]]></content:encoded>
					
					<wfw:commentRss>https://kaushalbhavsar.com/knowledgabase/cybersecurity-quiz-understanding-vs-recall/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Critical PHP RCE Advisory: Patch CVE-2026-109618 and CVE-2026-109619 Now</title>
		<link>https://kaushalbhavsar.com/vulnerabilities/critical-php-rce-advisory-patch-cve-2026-109618-and-cve-2026-109619-now/</link>
					<comments>https://kaushalbhavsar.com/vulnerabilities/critical-php-rce-advisory-patch-cve-2026-109618-and-cve-2026-109619-now/#respond</comments>
		
		<dc:creator><![CDATA[Kaushal Bhavsar]]></dc:creator>
		<pubDate>Wed, 21 Oct 2026 18:34:06 +0000</pubDate>
				<category><![CDATA[Vulnerabilities]]></category>
		<guid isPermaLink="false">https://kaushalbhavsar.com/?p=3612</guid>

					<description><![CDATA[PHP2Shell exposes PHP web servers to critical remote code execution risks. I explain the affected runtimes, fixed PHP versions, and the checks administrators should complete after patching.]]></description>
										<content:encoded><![CDATA[<p>If your website runs on PHP, I recommend treating this as an emergency update. On 21 October 2026, the PHP project released fixes for two critical vulnerabilities that can let an unauthenticated attacker execute code on an affected server. Both carry a CVSS v4.0 score of 9.2.</p>
<p>The vulnerabilities, also known as PHP2Shell, are tracked as <strong>CVE-2026-109618</strong> and <strong>CVE-2026-109619</strong>. <a href="https://watchtowr.com/intelligence/php-cve-2026-109618-faq/" target="_blank" rel="noopener">watchTowr reports exploitation in the wild</a>, and <a href="https://blog.cloudflare.com/php-vulnerabilities-waf-protection/" target="_blank" rel="noopener">Cloudflare reports attack traffic targeting its customers</a>. I would prioritise internet-facing PHP services immediately.</p>
<h2>Who needs to act?</h2>
<p>The <a href="https://www.php.net/archive/2026.php" target="_blank" rel="noopener">PHP project&#8217;s advisory</a> identifies all PHP installations serving web requests as at risk, including PHP-FPM, Apache with mod_php, php-cgi, FrankenPHP and LiteSpeed. The project considers mod_php the highest-risk configuration: a demonstrated attack can reach the vulnerable path before application code starts running.</p>
<p>For WordPress owners, the important distinction is that <strong>updating WordPress, plugins or themes does not update the PHP runtime</strong>. PHP is part of the hosting environment. If your host manages it, ask the host to confirm that the PHP version serving your site has received the fix. If you manage a VPS or dedicated server yourself, check who is responsible for installing the packages and restarting the services.</p>
<h2>What goes wrong inside PHP?</h2>
<ul>
<li><strong>CVE-2026-109618: out-of-memory corruption.</strong> A memory allocation failure can interrupt PHP while internal request data is only partly initialised. Request cleanup can then use that incomplete data as if it were valid, opening a path to remote code execution.</li>
<li><strong>CVE-2026-109619: stale global state.</strong> A worker can retain references to memory that belonged to an earlier request and has already been freed. A subsequent request handled by that worker can access the stale state before normal initialisation replaces it.</li>
</ul>
<p>The exact attack conditions vary with the PHP build, configuration and request handling. Using PHP-FPM instead of mod_php is not a reason to skip the update.</p>
<h2>Fixed PHP versions</h2>
<p>Install the fixed release for your PHP branch, or a later security release:</p>
<ul><li><strong>PHP 8.5: 8.5.12</strong></li><li><strong>PHP 8.4: 8.4.27</strong></li><li><strong>PHP 8.3: 8.3.36</strong></li><li><strong>PHP 8.2: 8.2.35</strong></li></ul>
<p>PHP 8.2 reaches upstream end of life on 31 December 2026. Patch it now and plan the move to a supported branch.</p>
<p>PHP 8.1 and older no longer receive regular security releases from the PHP project. Upgrade to a supported branch or obtain a confirmed backported fix from your distribution or support vendor. The PHP security team has provided minimal source backports for PHP 7.4, 8.0 and 8.1 for people building from source; these are not ready-to-install packages or a return to normal upstream support.</p>
<p>Some Linux vendors backport security fixes without changing the upstream version shown by PHP. In that case, check the full package revision and the vendor&#8217;s advisory for these CVEs rather than judging the result from the version number alone.</p>



<p>Patch every affected PHP runtime and verify the version serving each website. An interim mitigation does not complete remediation.</p>


<figure class="kb-mermaid" data-kb-mermaid-format="svg"><div class="kb-mermaid__frame"><pre class="mermaid">flowchart TD

 A[&quot;Inventory PHP runtimes&quot;] --&gt; B{&quot;Patched package available?&quot;}

 B --&gt;|Yes| C[&quot;Back up and install fix&quot;]

 B --&gt;|No| D[&quot;Reduce exposure using vendor guidance&quot;]

 D --&gt; E[&quot;Arrange patched package or upgrade&quot;]

 E --&gt; B

 C --&gt; F[&quot;Restart affected workers&quot;]

 F --&gt; G[&quot;Verify web and CLI runtimes&quot;]

 G --&gt; H{&quot;Every runtime patched?&quot;}

 H --&gt;|No| A

 H --&gt;|Yes| I[&quot;Test application and review logs&quot;]</pre></div></figure>


<h2>My recommended update checklist</h2>
<ol>
<li><strong>Identify every PHP runtime.</strong> Check each server, container, site and PHP version selected in your hosting panel. Different sites on one server may use different handlers or versions.</li>
<li><strong>Take a current snapshot or backup.</strong> Confirm that you have a recovery path before making the update. Keep the backup separate from the live web directory.</li>
<li><strong>Install the patched packages.</strong> Use your distribution&#8217;s supported package manager, hosting panel or established deployment process. For containers, rebuild with a patched base image and redeploy.</li>
<li><strong>Restart the affected services.</strong> Restart PHP-FPM pools, Apache or the relevant PHP-serving processes so every worker loads the patched runtime. Replacing files on disk does not replace code already loaded in running workers.</li>
<li><strong>Verify the runtime serving each site.</strong> Check the CLI with <code>php -v</code>, then check the web runtime separately. The CLI binary can differ from the version used by your website. In WordPress, review <strong>Tools → Site Health → Info → Server</strong> and confirm the handler and package details with your host. If you temporarily use <code>phpinfo()</code>, restrict access and delete the page immediately after checking it because it exposes configuration details.</li>
<li><strong>Test the application.</strong> Check important pages, logins, forms and uploads, then review PHP and web-server error logs. Record which package and runtime you verified.</li>
</ol>
<h2>Where to get the update</h2>
<p>For <strong>cPanel/WHM</strong>, check EasyApache 4 package updates and the <a href="https://docs.cpanel.net/" target="_blank" rel="noopener">cPanel documentation</a>. For <strong>Plesk</strong>, use the panel&#8217;s update process and check the <a href="https://support.plesk.com/hc/en-us/articles/44397729587351-Vulnerability-CVE-2026-109618-and-CVE-2026-109619-Remote-code-execution-in-PHP-shipped-with-Plesk" target="_blank" rel="noopener">Plesk advisory</a>. For <strong>CloudLinux Alt-PHP</strong>, check the <a href="https://blog.cloudlinux.com/php-cve-2026-109618-and-cve-2026-109619" target="_blank" rel="noopener">CloudLinux update guidance</a> and confirm coverage for every installed branch.</p>
<p>On Debian, Ubuntu, AlmaLinux, Rocky Linux, RHEL or another distribution, follow that vendor&#8217;s security advisory and package instructions. If you use a third-party repository, confirm that its packages include both fixes. I would avoid switching repositories on a production server without checking package compatibility and the rollback plan.</p>
<h2>If you cannot patch immediately</h2>
<p>The PHP project states that its interim measures only reduce exposure to specific attack paths. <strong>They do not make an unpatched installation safe.</strong> Follow the current <a href="https://www.php.net/archive/2026.php" target="_blank" rel="noopener">official PHP guidance</a> for your configuration while arranging the update.</p>
<p>I would avoid copying isolated PHP settings from social media. The advisory&#8217;s memory-limit changes have operational implications, and some settings must apply before request parsing to have any effect. Ask your administrator to apply the full guidance and restart all affected workers. If an exposed service cannot be patched or adequately restricted, consider temporarily taking it offline.</p>
<p>A web application firewall can provide an additional layer of protection against known attack patterns. It does not replace the PHP patch, and any route that reaches the origin directly also needs attention.</p>
<h2>Check for compromise as well as patching</h2>
<p>Review unexpected files in web directories, new scheduled tasks, unfamiliar processes, PHP worker crashes, unusual outbound connections and unexplained load spikes. These are investigation leads, not proof that either vulnerability was exploited.</p>
<p>If you find evidence of compromise, preserve relevant logs and isolate the affected workload while you investigate. Patching closes the vulnerability; it does not remove an existing web shell, undo data access or invalidate credentials an attacker may already have obtained.</p>
<p>After the immediate response, remove unused PHP versions and applications, review automatic security-update settings, and restrict administrative access. Keep your CMS, plugins and themes maintained alongside the underlying runtime.</p>
<h2>Technical references</h2>
<ul><li><a href="https://www.php.net/archive/2026.php" target="_blank" rel="noopener">PHP security announcement and fixed releases, 21 October 2026</a></li><li><a href="https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w" target="_blank" rel="noopener">CVE-2026-109618: PHP&#8217;s out-of-memory corruption advisory</a></li><li><a href="https://github.com/php/php-src/security/advisories/GHSA-6wmf-4rv5-p3rp" target="_blank" rel="noopener">CVE-2026-109619: PHP&#8217;s stale global state advisory</a></li></ul>]]></content:encoded>
					
					<wfw:commentRss>https://kaushalbhavsar.com/vulnerabilities/critical-php-rce-advisory-patch-cve-2026-109618-and-cve-2026-109619-now/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>What a PII Redactor Can Miss</title>
		<link>https://kaushalbhavsar.com/knowledgabase/what-pii-redactors-can-miss/</link>
					<comments>https://kaushalbhavsar.com/knowledgabase/what-pii-redactors-can-miss/#respond</comments>
		
		<dc:creator><![CDATA[Kaushal Bhavsar]]></dc:creator>
		<pubDate>Wed, 21 Oct 2026 02:48:00 +0000</pubDate>
				<category><![CDATA[Knowledge Base]]></category>
		<guid isPermaLink="false">https://kaushalbhavsar.com/?p=3628</guid>

					<description><![CDATA[Detecting an email address is easier than detecting every clue to a person’s identity. I explain how to evaluate redaction tools and review what survives.]]></description>
										<content:encoded><![CDATA[<p><em>Updated: 22 October 2026.</em></p>
<p>A redaction tool removes names, telephone numbers and email addresses from a document. Is the remaining text safe to share?</p>
<p>I would read what survives before answering. A person may still be identifiable through their role, location, dates or a distinctive event, even when their name has disappeared.</p>
<p>That is the central difficulty with PII redaction: some identifiers have a recognisable format, while others become identifying only in context.</p>
<h2>Start with the information and its audience</h2>
<p>Imagine this fictional sentence: “The only database administrator at the east office requested leave after the incident on Monday.” Removing a name would not necessarily conceal the person from colleagues.</p>
<p>The audience matters. A description that reveals little to a stranger may be obvious to somebody who knows the organisation. I would therefore define the sharing purpose and intended recipients before deciding what needs removal or generalisation.</p>
<p>I would also distinguish redaction from pseudonymisation and anonymisation. Replacing a name with a stable label can preserve links between records. It may be useful, but it does not by itself establish that re-identification is no longer possible.</p>
<h2>Know what the detector supports</h2>
<p>Pattern matching can work well for some structured identifiers. Names, free-form addresses, mixed languages and organisation-specific codes need different treatment.</p>
<p>A detector’s supported entity list is a starting point. I would test the formats and languages present in the actual material, including spacing variations, abbreviations and transcription errors. A general model may not recognise a local identifier or an internal reference number.</p>
<p>The input format also matters. If a tool analyses pasted text, it has not necessarily inspected an attachment’s metadata, comments, images or hidden document layers. An OCR step introduces another opportunity to miss or misread an identifier.</p>



<p>Redaction needs checks for missed identifiers, indirect clues and the final exported file.</p>


<figure class="kb-mermaid" data-kb-mermaid-format="svg"><div class="kb-mermaid__frame"><pre class="mermaid">flowchart TD

 A[&quot;Define audience and sharing purpose&quot;] --&gt; B[&quot;Detect supported identifiers&quot;]

 B --&gt; C[&quot;Redact or generalise&quot;]

 C --&gt; D{&quot;Identifiers or context still reveal a person?&quot;}

 D --&gt;|Yes| C

 D --&gt;|Uncertain| E[&quot;Escalate for review&quot;]

 E --&gt; C

 D --&gt;|No identified issue| F[&quot;Inspect actual export&quot;]

 F --&gt; G{&quot;Hidden content or metadata remains?&quot;}

 G --&gt;|Yes| C

 G --&gt;|No identified issue| H[&quot;Authorised sharing decision&quot;]</pre></div></figure>


<h2>Measure misses and unnecessary removals</h2>
<p>I would create a synthetic test set with known examples and mark the expected spans. Include ordinary sentences without personal data as well as difficult positive examples.</p>
<p>Then review false negatives and false positives separately. A missed account number may create a privacy problem. Excessive redaction can make a report useless or remove the context an investigator needs.</p>
<p>I would compare results across entity types rather than accept one overall accuracy number. A tool can perform well on email addresses and poorly on names while still producing an attractive average.</p>
<h2>Review the output and the processing path</h2>
<p>Before sharing sensitive material, I would inspect the final output for indirect identifiers and check the actual exported file. A coloured rectangle over visible text does not prove that the text was removed from the document underneath it.</p>
<p>I would also examine where the original input goes. A redaction service that sends source documents to logs, analytics or an external model creates a separate data-handling decision. Browser-based processing can reduce transmission, but that behaviour needs verification rather than a label.</p>
<p>For high-impact sharing, I would combine automated detection with a human review appropriate to the material. The tool’s useful contribution is finding likely sensitive spans consistently and showing what it changed. The decision to disclose the remaining information still depends on its content and context.</p>
<h3>References</h3>
<ul>
<li><a href="https://presidio.dataprivacystack.org/supported_entities/" target="_blank" rel="noopener">Presidio: Supported PII entities</a></li>
<li><a href="https://presidio.dataprivacystack.org/" target="_blank" rel="noopener">Presidio project documentation</a></li>
</ul>]]></content:encoded>
					
					<wfw:commentRss>https://kaushalbhavsar.com/knowledgabase/what-pii-redactors-can-miss/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>A Security Headers Score Is Only Part of the Story</title>
		<link>https://kaushalbhavsar.com/knowledgabase/security-headers-score-limitations/</link>
					<comments>https://kaushalbhavsar.com/knowledgabase/security-headers-score-limitations/#respond</comments>
		
		<dc:creator><![CDATA[Kaushal Bhavsar]]></dc:creator>
		<pubDate>Wed, 21 Oct 2026 02:47:00 +0000</pubDate>
				<category><![CDATA[Knowledge Base]]></category>
		<guid isPermaLink="false">https://kaushalbhavsar.com/?p=3626</guid>

					<description><![CDATA[Security headers provide useful browser protections, but a high score cannot establish that an application is secure. I explain what to check behind the grade.]]></description>
										<content:encoded><![CDATA[<p><em>Updated: 22 October 2026.</em></p>
<p>A website receives a high security-headers score. What can I safely infer from that result?</p>
<p>I can infer that the checker observed certain response headers and evaluated them against its rules. I cannot infer that the website’s access controls, password recovery or business logic are secure.</p>
<p>Headers are worth configuring. Their value becomes clearer when each one is connected to a specific browser behaviour instead of treated as a point on a scoreboard.</p>
<h2>Presence does not establish an effective policy</h2>
<p>Content Security Policy can restrict which resources a page loads and how some content executes. Its usefulness depends on the directives and exceptions in the actual policy.</p>
<p>A permissive policy may preserve every existing script while offering less protection than its presence suggests. Conversely, a strict policy copied without testing can break a payment flow, embedded application or essential script.</p>
<p>I would distinguish an enforced policy from <code>Content-Security-Policy-Report-Only</code>. Report-only mode is useful for observing violations before enforcement, but it does not block them. A checker should make that distinction visible.</p>
<h2>Match the configuration to the site</h2>
<p>HSTS tells supporting browsers to use HTTPS for future connections under its rules. I would review the HTTPS readiness of relevant hosts before extending the policy across subdomains or considering preload submission.</p>
<p>Other controls address different risks. For example, content-type handling and framing restrictions serve different purposes from transport security. Their settings should reflect the application’s needs, including any legitimate embedding requirements.</p>
<p>My approach would be to identify the intended protection, inspect the current behaviour, test the change and document any exception. “The scanner asked for this header” is not enough explanation for a production configuration change.</p>
<h2>Check more than the homepage</h2>
<p>A public checker usually observes a limited set of responses. The login page, an error response, a download and a page reached after authentication may behave differently.</p>
<p>Redirects matter too. I would record the requested URL, the final URL and where a header was observed. A policy on one response does not prove that every other response uses it.</p>
<p>For a checker I was designing, I would want results to show the raw header value, the interpreted effect and the limits of the request. That gives an administrator something they can reproduce and investigate.</p>



<p>A header result feeds into configuration testing and the wider application review; the score alone cannot certify the application.</p>


<figure class="kb-mermaid" data-kb-mermaid-format="svg"><div class="kb-mermaid__frame"><pre class="mermaid">flowchart TD

 A[&quot;Observe response headers&quot;] --&gt; B{&quot;Policy matches intended protection?&quot;}

 B --&gt;|No| C[&quot;Review directives and exceptions&quot;]

 C --&gt; D[&quot;Test important user journeys&quot;]

 B --&gt;|Yes| D

 D --&gt; E{&quot;Protection works without breaking the site?&quot;}

 E --&gt;|No| C

 E --&gt;|Yes| F[&quot;Record policy and evidence&quot;]

 F --&gt; G[&quot;Combine with access and application tests&quot;]</pre></div></figure>


<h2>Use the score to start a review</h2>
<p>Suppose an illustrative customer portal has an excellent header configuration but lets an ordinary user retrieve another customer’s document. The headers do not correct that authorisation failure.</p>
<p>That is why I would use a header report alongside application testing, dependency maintenance, access reviews and recovery checks. It covers one useful part of the system.</p>
<p>After changing a policy, I would test important user journeys and review violation reports carefully. Those reports can contain URLs and other details, so their collection and retention also need thought.</p>
<p>The result I want is a configuration whose purpose and behaviour the team understands. A grade can help track changes, but the policy, test evidence and exceptions are what another engineer needs to maintain it.</p>
<h3>References</h3>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CSP" target="_blank" rel="noopener">MDN: Content Security Policy</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security" target="_blank" rel="noopener">MDN: Strict-Transport-Security</a></li>
<li><a href="https://wstg.owasp.org/v4.2/4-Web_Application_Security_Testing/" target="_blank" rel="noopener">OWASP Web Security Testing Guide</a></li>
</ul>]]></content:encoded>
					
					<wfw:commentRss>https://kaushalbhavsar.com/knowledgabase/security-headers-score-limitations/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How I Read a Suspicious Email’s Headers</title>
		<link>https://kaushalbhavsar.com/knowledgabase/how-i-read-suspicious-email-headers/</link>
					<comments>https://kaushalbhavsar.com/knowledgabase/how-i-read-suspicious-email-headers/#respond</comments>
		
		<dc:creator><![CDATA[Kaushal Bhavsar]]></dc:creator>
		<pubDate>Wed, 21 Oct 2026 02:46:00 +0000</pubDate>
				<category><![CDATA[Knowledge Base]]></category>
		<guid isPermaLink="false">https://kaushalbhavsar.com/?p=3624</guid>

					<description><![CDATA[Email headers can help explain delivery and authentication, but some fields can be forged. I describe how I separate trusted receiving evidence from a sender’s claims.]]></description>
										<content:encoded><![CDATA[<p><em>Updated: 22 October 2026.</em></p>
<p>An email claims to come from a familiar organisation. The sender’s name looks right, the logo is convincing and the message asks for an urgent payment or login.</p>
<p>I would look at the headers, but I would not expect a single “pass” result to decide whether the message is safe.</p>
<p>Headers help answer questions about delivery and authentication. They do not establish that the sender’s request is legitimate or that the account has not been compromised.</p>
<h2>Preserve the original message</h2>
<p>I would start with the original message or its full source. A screenshot leaves out the routing and authentication details. An ordinary inline forward can also lose important evidence.</p>
<p>Before sharing headers, remember that they may contain addresses, internal hostnames, identifiers and other information. For a public discussion, I would use a carefully sanitised copy. For an investigation, preserve the original separately.</p>
<h2>Establish which system is reporting the result</h2>
<p>The <code>Authentication-Results</code> field can record checks performed by a receiving system. Its value depends on whether that system is trusted. An attacker can add a convincing-looking header to a message before sending it.</p>
<p>I would therefore begin at the trusted receiving side and identify the authentication results that belong to that environment. I would not accept every line saying <code>spf=pass</code> as evidence from my mail provider.</p>
<p>Routing headers need similar care. <code>Received</code> entries can help reconstruct the path, but entries outside the trusted boundary may have been supplied by an untrusted sender. Reading a list from bottom to top is not enough unless that boundary has been established.</p>



<p>Authentication results become useful evidence only after their trusted receiving source is established.</p>


<figure class="kb-mermaid" data-kb-mermaid-format="svg"><div class="kb-mermaid__frame"><pre class="mermaid">flowchart TD

 A[&quot;Original email and full headers&quot;] --&gt; B{&quot;Result from trusted receiving system?&quot;}

 B --&gt;|No or unknown| C[&quot;Treat header claims as untrusted&quot;]

 B --&gt;|Yes| D[&quot;Interpret SPF, DKIM and DMARC&quot;]

 C --&gt; E[&quot;Seek trusted delivery evidence&quot;]

 E --&gt; B

 D --&gt; F[&quot;Review actual domains and requested action&quot;]

 F --&gt; G{&quot;Credentials, money or sensitive data?&quot;}

 G --&gt;|Yes| H[&quot;Verify through a known independent channel&quot;]

 G --&gt;|No| I[&quot;Assess content and context&quot;]

 H --&gt; I</pre></div></figure>


<h2>Interpret authentication precisely</h2>
<p>SPF evaluates whether the sending server is authorised for the relevant envelope-sender or HELO domain. It does not directly authenticate the display name shown in the inbox.</p>
<p>DKIM checks a domain’s signature over selected parts of the message. A successful check does not mean the content is honest or harmless.</p>
<p>DMARC connects authentication to the visible From domain through alignment. A pass can be useful evidence against certain forms of domain impersonation, but an attacker can use a domain they control or send from a compromised legitimate account.</p>
<p>I would compare the actual domains rather than rely on a familiar word in an address. A reply address that differs from the sender can be legitimate, but it should make sense for the business process.</p>
<h2>Use the message context to decide the next step</h2>
<p>Consider a fictional invoice email that passes authentication for a supplier’s real domain but asks for payment to a new bank account. Authentication does not verify the bank-account change. I would confirm it through a previously known contact method, rather than a telephone number introduced by that email.</p>
<p>Likewise, an authentication failure needs interpretation. Forwarding and message modification can affect results. Failure is a reason to investigate, not an automatic explanation of who sent the message.</p>
<p>A useful analysis states what the trusted headers support, what the message asks the recipient to do and which verification step remains. If the request involves credentials, money or sensitive information, I would pause that action until it has been independently confirmed.</p>
<h3>References</h3>
<ul>
<li><a href="https://www.rfc-editor.org/rfc/rfc8601.html" target="_blank" rel="noopener">RFC 8601: Authentication-Results and trust boundaries</a></li>
<li><a href="https://www.rfc-editor.org/rfc/rfc7489.html" target="_blank" rel="noopener">RFC 7489: DMARC</a></li>
</ul>]]></content:encoded>
					
					<wfw:commentRss>https://kaushalbhavsar.com/knowledgabase/how-i-read-suspicious-email-headers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Decoding a JWT Does Not Verify It</title>
		<link>https://kaushalbhavsar.com/knowledgabase/jwt-decoding-is-not-verification/</link>
					<comments>https://kaushalbhavsar.com/knowledgabase/jwt-decoding-is-not-verification/#respond</comments>
		
		<dc:creator><![CDATA[Kaushal Bhavsar]]></dc:creator>
		<pubDate>Wed, 21 Oct 2026 02:45:00 +0000</pubDate>
				<category><![CDATA[Knowledge Base]]></category>
		<guid isPermaLink="false">https://kaushalbhavsar.com/?p=3622</guid>

					<description><![CDATA[Reading a token’s claims does not make them trustworthy. I explain the separate jobs of decoding, signature verification, claim validation and authorisation.]]></description>
										<content:encoded><![CDATA[<p><em>Updated: 22 October 2026.</em></p>
<p>A JWT decoder displays a user identifier, an expiry time and a role called <code>admin</code>. It is easy to read that output as a statement about the current user.</p>
<p>At that point, it is only a statement about what the token contains. I would not use it to grant access.</p>
<p>A decoder is useful for inspection and debugging. The confusion begins when readable output is presented as verified identity.</p>
<h2>Understand what the decoder did</h2>
<p>A common signed JWT has three parts separated by dots: a header, a payload and a signature. Its header and payload use Base64url encoding, which makes them straightforward to read. Encoding does not hide the claims or establish who created them. Encrypted JWTs use a different structure and cannot be inspected in the same way without decryption.</p>
<p>For an illustrative payload:</p>
<pre><code>{
  &quot;sub&quot;: &quot;demo-user&quot;,
  &quot;role&quot;: &quot;admin&quot;,
  &quot;aud&quot;: &quot;sample-api&quot;,
  &quot;exp&quot;: 1900000000
}</code></pre>
<p>A decoder can show those fields and convert the timestamp into a date. Somebody can also construct those fields themselves. Their presence is not evidence that the application should accept them.</p>



<p>Decoded claims remain untrusted until the application completes its verification, validation and authorisation checks.</p>


<figure class="kb-mermaid" data-kb-mermaid-format="svg"><div class="kb-mermaid__frame"><pre class="mermaid">flowchart TD

 A[&quot;Received token&quot;] --&gt; B[&quot;Parse structure and claims&quot;]

 B --&gt; C{&quot;Trusted key and allowed algorithm verify?&quot;}

 C --&gt;|No| R[&quot;Reject token&quot;]

 C --&gt;|Yes| D{&quot;Issuer, audience and time claims valid?&quot;}

 D --&gt;|No| R

 D --&gt;|Yes| E{&quot;Correct token purpose?&quot;}

 E --&gt;|No| R

 E --&gt;|Yes| F{&quot;Operation and resource permitted?&quot;}

 F --&gt;|No| G[&quot;Deny operation&quot;]

 F --&gt;|Yes| H[&quot;Allow scoped operation&quot;]</pre></div></figure>


<h2>Verification and acceptance are separate decisions</h2>
<p>Signature verification checks cryptographic integrity using a trusted key and an allowed algorithm. The application must control which algorithms and keys it accepts; it should not simply follow whatever the untrusted header requests.</p>
<p>Even a valid signature does not settle whether this token belongs in this request. I would also validate the expected issuer, intended audience, relevant time limits and the token type required by the application. Different token purposes need distinct acceptance rules.</p>
<p>Authorisation follows those checks. An accepted identity still needs permission for the particular operation and resource. A token issued for one service should not become a general access pass for another.</p>
<h2>A useful decoder should explain its limits</h2>
<p>When designing a decoder, I would label its result “decoded” and reserve “verified” for an actual verification operation with an identified trust configuration.</p>
<p>Expiry deserves careful wording too. “The <code>exp</code> claim is in the future” describes a parsed value. “This token is valid” claims much more. A token may be revoked, intended for another audience or signed by an untrusted issuer.</p>
<p>I would show malformed input clearly and avoid silently repairing a broken token into something that looks legitimate. Debugging tools should preserve the distinction between the supplied bytes and their interpretation.</p>
<h2>Keep real credentials out of public debugging workflows</h2>
<p>A live bearer token may grant access to an account or API. I would use a synthetic token when trying an unfamiliar decoder. I would never paste a signing secret or private key into a public website for convenience.</p>
<p>For a browser-based tool, “processed locally” is a behaviour to verify. Check whether scripts, analytics, error reports, URLs or browser storage receive the token. A page can decode in the browser and still leak input through another component.</p>
<p>For an application, I would use a maintained JWT library and test rejection cases as carefully as successful logins: an incorrect audience, an expired token, an unexpected algorithm and a token signed with the wrong key. A readable token is the beginning of inspection, not the end of the trust decision.</p>
<h3>References</h3>
<ul>
<li><a href="https://www.rfc-editor.org/rfc/rfc7519.html" target="_blank" rel="noopener">RFC 7519: JSON Web Token</a></li>
<li><a href="https://www.rfc-editor.org/rfc/rfc8725.html" target="_blank" rel="noopener">RFC 8725: JSON Web Token Best Current Practices</a></li>
</ul>]]></content:encoded>
					
					<wfw:commentRss>https://kaushalbhavsar.com/knowledgabase/jwt-decoding-is-not-verification/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>What “Zero Tribal Knowledge” Would Require from a Software Team</title>
		<link>https://kaushalbhavsar.com/knowledgabase/zero-tribal-knowledge-software-teams/</link>
					<comments>https://kaushalbhavsar.com/knowledgabase/zero-tribal-knowledge-software-teams/#respond</comments>
		
		<dc:creator><![CDATA[Kaushal Bhavsar]]></dc:creator>
		<pubDate>Fri, 16 Oct 2026 02:51:00 +0000</pubDate>
				<category><![CDATA[Knowledge Base]]></category>
		<guid isPermaLink="false">https://kaushalbhavsar.com/?p=3634</guid>

					<description><![CDATA[Documentation becomes useful when another engineer can make a change or recover a service with it. I explain how I would reduce reliance on knowledge held by one person.]]></description>
										<content:encoded><![CDATA[<p><em>Updated: 22 October 2026.</em></p>
<p>A system can have a long README and still depend on one person who knows which warning to ignore, which job must run first and which account actually owns the deployment.</p>
<p>My view is that “zero tribal knowledge” is a useful direction rather than a literal promise. There will always be experience that has not been written down. The priority is to stop important operations depending on information that only one person can supply.</p>
<p>I would measure that through tasks, not document length.</p>
<h2>Begin with the moments that require an interruption</h2>
<p>List the questions that repeatedly bring work back to a particular person. How do I deploy this? Why did this job fail? Which dataset does the dashboard use? What is safe to restart?</p>
<p>Those interruptions reveal the gaps more clearly than asking everybody to “improve documentation.” Each question should lead to an answer stored where the next operator will look.</p>
<p>For a fictional ingestion service, the missing information might be a dependency on a source export that finishes after midnight. A setup guide can be technically accurate while omitting that operating constraint.</p>
<h2>Capture decisions as well as commands</h2>
<p>A command tells me what to run. A decision record tells me why the system works that way and when I should reconsider it.</p>
<p>I would record the problem, the chosen approach, the important alternatives and the consequence of changing it. This can be short. The useful detail is often a constraint, such as an upstream system that cannot support a certain query pattern.</p>
<p>Without that explanation, a future engineer may “simplify” a workaround and reintroduce the original failure.</p>
<h2>Write the failure path</h2>
<p>A happy-path deployment guide is only part of a handover. I would also want the symptoms of common failures, the evidence to collect, safe containment steps and the point at which to escalate.</p>
<p>“Restart the worker” needs conditions. What state can be lost? Could work run twice? How will the operator verify recovery? What should they avoid doing while an incident is being investigated?</p>
<p>Secrets should be referenced through the approved access process, not copied into the runbook. The document should identify the role required and where access is managed.</p>



<p>An independent operator reveals missing knowledge by trying a routine task and a recovery scenario.</p>


<figure class="kb-mermaid" data-kb-mermaid-format="svg"><div class="kb-mermaid__frame"><pre class="mermaid">flowchart TD

 A[&quot;Record recurring questions&quot;] --&gt; B[&quot;Document decisions and failure paths&quot;]

 B --&gt; C[&quot;Independent operator tries the task&quot;]

 C --&gt; D{&quot;Private help or special access required?&quot;}

 D --&gt;|Yes| E[&quot;Fix process, access or instructions&quot;]

 E --&gt; B

 D --&gt;|No| F[&quot;Verify outcome and recovery&quot;]

 F --&gt; G[&quot;Assign owner and review triggers&quot;]

 G --&gt;|System changes| B</pre></div></figure>


<h2>Test the handover with an independent operator</h2>
<p>My preferred check is to let another engineer perform a representative task in a safe environment using the documentation. The original author can observe, but every necessary verbal intervention should become an improvement to the process or its instructions.</p>
<p>I would test a routine change and a failure scenario. An independent operator should be able to establish the current state, take an appropriate action and verify the result.</p>
<p>This also reveals problems that documentation alone cannot fix. If the only deployment credential belongs to one individual, writing its existence down does not remove the dependency.</p>
<h2>Keep ownership visible</h2>
<p>Each important document needs an owner and a reason to be reviewed. A change to a dependency, permission or recovery process should trigger an update alongside the code.</p>
<p>I would track practical outcomes: successful independent deployments, fewer unresolved handover questions and recovery exercises completed without private help. The aim is to make knowledge usable at the moment somebody needs it, including when its original author is unavailable.</p>]]></content:encoded>
					
					<wfw:commentRss>https://kaushalbhavsar.com/knowledgabase/zero-tribal-knowledge-software-teams/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Automating Database Administration Without Losing Control</title>
		<link>https://kaushalbhavsar.com/knowledgabase/automating-warehouse-administration-safely/</link>
					<comments>https://kaushalbhavsar.com/knowledgabase/automating-warehouse-administration-safely/#respond</comments>
		
		<dc:creator><![CDATA[Kaushal Bhavsar]]></dc:creator>
		<pubDate>Fri, 16 Oct 2026 02:50:00 +0000</pubDate>
				<category><![CDATA[Knowledge Base]]></category>
		<guid isPermaLink="false">https://kaushalbhavsar.com/?p=3632</guid>

					<description><![CDATA[Repeated requests for tables and views should become a controlled delivery process. I describe how I would automate warehouse changes while keeping access and recovery reviewable.]]></description>
										<content:encoded><![CDATA[<p><em>Updated: 22 October 2026.</em></p>
<p>When every dashboard request requires somebody to create another table, view or permission manually, the warehouse becomes dependent on that person’s availability.</p>
<p>I would approach this as a delivery-process problem. The useful goal is to make an approved change repeatable, inspectable and recoverable, so another engineer can operate it.</p>
<p>Serverless infrastructure does not remove responsibility for schema design, access control or the meaning of the data.</p>
<h2>Decide where the logic belongs</h2>
<p>QuickSight supports custom SQL for suitable data sources and configurations. A database view is therefore a design choice, not a universal workaround for an absence of SQL support.</p>
<p>I would use a managed warehouse relation when several consumers need the same definition, when its permissions need central review or when it forms a stable reporting contract. A narrow experiment may belong closer to the analysis, provided its access is appropriate.</p>
<p>The decision should explain who owns the calculation and how a future change reaches its consumers.</p>
<h2>Turn recurring requests into a small contract</h2>
<p>For a fictional monthly headcount dataset, I would first define the fields, reporting period, inclusion rules, expected level of detail and permitted audience. Without that contract, automation can reproduce an ambiguous number very efficiently.</p>
<p>The proposed SQL, grants and accompanying explanation would live in version control. A reviewer should be able to see that a change adds a column, alters a calculation or expands access.</p>
<p>I would avoid an open-ended form that lets anybody submit arbitrary SQL under a powerful service identity. A controlled request can select an approved pattern and supply validated parameters instead.</p>



<p>A warehouse change needs execution checks, data checks and access checks before consumers rely on it.</p>


<figure class="kb-mermaid" data-kb-mermaid-format="svg"><div class="kb-mermaid__frame"><pre class="mermaid">flowchart TD

 A[&quot;Dataset contract and SQL change&quot;] --&gt; B[&quot;Review SQL and grants&quot;]

 B --&gt; C[&quot;Deploy in test environment&quot;]

 C --&gt; D{&quot;Statement completed successfully?&quot;}

 D --&gt;|No| E[&quot;Investigate and correct&quot;]

 E --&gt; B

 D --&gt;|Yes| F[&quot;Test data meaning and denied access&quot;]

 F --&gt; G{&quot;Checks pass?&quot;}

 G --&gt;|No| E

 G --&gt;|Yes| H[&quot;Approved staged production deployment&quot;]

 H --&gt; I[&quot;Verify result and record change&quot;]</pre></div></figure>


<h2>Give deployment its own workflow</h2>
<p>My implementation would start in a test environment with synthetic or appropriately controlled data. The pipeline would validate the change, apply it with a restricted deployment identity and run checks before making the output available to consumers.</p>
<p>Redshift’s Data API can submit SQL, and its statement-status interface provides a way to check the result. A successful submission is not the same as successful execution. The workflow needs to wait for a terminal status and handle failure explicitly.</p>
<p>Retries also need design. I would use supported idempotency mechanisms where applicable and keep a deployment record, rather than assume that every SQL operation is safe to run twice.</p>
<h2>Test meaning and permissions</h2>
<p>For that headcount example, useful tests would cover the expected population, duplicate records, missing reporting periods and changes around a period boundary. The exact cases depend on the agreed definition.</p>
<p>Access tests belong in the same process. Can the reporting identity query the approved relation? Can it reach raw personal records it does not need? What happens to grants after an object is replaced?</p>
<p>For breaking changes, I would prefer a staged migration where existing consumers continue working while the new contract is tested. Some data changes cannot be undone by simply restoring the previous SQL file, so the recovery plan must fit the operation.</p>
<h2>Make the process operable by somebody else</h2>
<p>The deployment output should identify what changed, who approved it, the execution result and the checks performed. Failures need an owner and a documented response.</p>
<p>I would begin by automating one frequent, well-understood request. Once another engineer can deploy, verify and recover that change without private instructions, the pattern is ready to expand.</p>
<h3>References</h3>
<ul>
<li><a href="https://docs.aws.amazon.com/quicksight/latest/APIReference/API_CustomSql.html" target="_blank" rel="noopener">AWS: QuickSight custom SQL</a></li>
<li><a href="https://docs.aws.amazon.com/redshift-data/latest/APIReference/API_ExecuteStatement.html" target="_blank" rel="noopener">AWS: Redshift Data API — ExecuteStatement</a></li>
<li><a href="https://docs.aws.amazon.com/redshift-data/latest/APIReference/API_DescribeStatement.html" target="_blank" rel="noopener">AWS: Redshift Data API — DescribeStatement</a></li>
</ul>]]></content:encoded>
					
					<wfw:commentRss>https://kaushalbhavsar.com/knowledgabase/automating-warehouse-administration-safely/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Your Dashboard Shows Totals. Who Can Read the Underlying Records?</title>
		<link>https://kaushalbhavsar.com/knowledgabase/dashboard-totals-underlying-record-access/</link>
					<comments>https://kaushalbhavsar.com/knowledgabase/dashboard-totals-underlying-record-access/#respond</comments>
		
		<dc:creator><![CDATA[Kaushal Bhavsar]]></dc:creator>
		<pubDate>Fri, 16 Oct 2026 02:38:00 +0000</pubDate>
				<category><![CDATA[Knowledge Base]]></category>
		<guid isPermaLink="false">https://kaushalbhavsar.com/?p=3616</guid>

					<description><![CDATA[An aggregate dashboard can hide personal records on screen while its underlying connections still have broad access. I explain how to review that boundary.]]></description>
										<content:encoded><![CDATA[<p><em>Updated: 22 October 2026.</em></p>
<p>A dashboard can show only headcount, totals and trends while the account behind it can still read individual records. I would check both before describing the data as protected.</p>
<p>The visual tells me what a particular screen displays. It does not tell me everything a user, dataset author or service account can retrieve.</p>
<p>This matters when a reporting system combines useful business information with names, employee identifiers, compensation or other personal data. Removing those fields from a chart does not automatically remove access elsewhere.</p>
<h2>Trace the identity that reaches the database</h2>
<p>Imagine a fictional reporting system where managers see monthly headcount by department. The warehouse also contains individual employment records.</p>
<p>I would trace a request from the dashboard to the dataset and then to the database connection. Does the database receive the viewer’s identity, or does it see a shared service account? Who can edit the dataset? Can an author add fields, create a new analysis or export a different result?</p>
<p>These questions determine where access restrictions must be enforced. A database policy cannot distinguish two dashboard viewers if both arrive as the same identity and no trusted user context reaches it.</p>
<p>Redshift supports row-level security, and supported QuickSight configurations can propagate user identity. Those capabilities need deliberate configuration; I would verify which identity actually executes the query rather than infer it from the sign-in screen.</p>



<p>Illustrative access paths: the dashboard connection reaches approved aggregates, while individual records require a separately authorised route.</p>


<figure class="kb-mermaid" data-kb-mermaid-format="svg"><div class="kb-mermaid__frame"><pre class="mermaid">flowchart TD

 V[&quot;Dashboard viewer&quot;] --&gt; Q[&quot;Reporting connection&quot;]

 Q --&gt; A[&quot;Approved aggregate relation&quot;]

 A --&gt; T[&quot;Totals and trends&quot;]

 Q --&gt; X[&quot;Direct raw-record access denied&quot;]

 U[&quot;Authorised detail user&quot;] --&gt; P[&quot;Identity and permission checks&quot;]

 P --&gt; R[&quot;Permitted individual records&quot;]

 T --&gt; S[&quot;Review small groups and exports&quot;]</pre></div></figure>


<h2>Give aggregate reporting an appropriate data source</h2>
<p>Where a dashboard needs only approved totals, I would consider giving its connection access to a dedicated aggregate relation instead of the underlying personal records. The owner, grants and query behaviour of that relation still need review.</p>
<p>For an illustrative headcount dataset, the approved output might contain reporting month, business unit and count. It would not include a hidden employee identifier merely because the source table contains one.</p>
<p>This approach also makes the intended contract easier to inspect: these are the fields and level of detail this reporting use case needs. A separate, controlled workflow can serve authorised users who genuinely require individual records.</p>
<h2>Aggregation needs a privacy review too</h2>
<p>An aggregate is not automatically anonymous. Suppose a filter reduces a department to one person. A total can then reveal information about that person. Comparing overlapping groups can also disclose more than either chart appears to show on its own.</p>
<p>I would review small groups, combinations of filters, drill-downs and exports. Depending on the data and audience, the design may need broader groupings, suppression or limits on available breakdowns. There is no universal group-size threshold that makes every dataset safe.</p>
<h2>Test with accounts that should be refused</h2>
<p>My review would include a viewer from another department, an ordinary author and the service identity itself. I would test permitted actions and denied actions, including access through alternative datasets or direct database tools where those routes exist.</p>
<p>I would also record whether data is queried live or copied into another storage layer. A copy creates another place where permissions, retention and exports matter.</p>
<p>The evidence I want is concrete: the identity used, the objects it can access, the records it can retrieve and the results of the negative tests. A screenshot of a tidy dashboard cannot answer those questions.</p>
<h3>References</h3>
<ul>
<li><a href="https://docs.aws.amazon.com/redshift/latest/dg/t_rls.html" target="_blank" rel="noopener">AWS: Row-level security in Amazon Redshift</a></li>
<li><a href="https://aws.amazon.com/blogs/business-intelligence/centrally-manage-permissions-for-tables-and-views-accessed-from-amazon-quicksight-with-trusted-identity-propagation/" target="_blank" rel="noopener">AWS: QuickSight and Redshift trusted identity propagation</a></li>
</ul>]]></content:encoded>
					
					<wfw:commentRss>https://kaushalbhavsar.com/knowledgabase/dashboard-totals-underlying-record-access/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
