<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>security on Saurabh Kumar</title><link>https://saurabh-kumar.com/tags/security/</link><description>Recent content in security on Saurabh Kumar</description><generator>Hugo</generator><language>en-US</language><copyright>Copyright © 2025, Saurabh Kumar.</copyright><lastBuildDate>Sun, 11 Oct 2026 12:00:00 +0000</lastBuildDate><atom:link href="https://saurabh-kumar.com/tags/security/index.xml" rel="self" type="application/rss+xml"/><item><title>Rampart</title><link>https://saurabh-kumar.com/til/1791720000/</link><pubDate>Sun, 11 Oct 2026 12:00:00 +0000</pubDate><guid>https://saurabh-kumar.com/til/1791720000/</guid><description>&lt;p&gt;Small on-device models are getting good enough to sit in front of the big ones. &lt;a href="https://ndstudio.gov/posts/say-hello-to-rampart" rel="noopener external"&gt;Rampart&lt;/a&gt; from the National Design Studio redacts PII in the browser before a prompt reaches any LLM: regexes with checksum or structural checks for cards (Luhn), SSNs, emails, URLs and IPs, plus a fine-tuned MiniLM for names, phones, account numbers, government IDs and street addresses.&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;14.7 MB Q4 ONNX (~15 MB with tokenizer), 98.4% private-term recall across seven Latin-script languages. p50 is 3.9 ms on WebGPU but 12.6 ms on the default WASM backend. OpenAI&amp;rsquo;s Privacy Filter is ~2.8 GB; Presidio scores 65% on the same test set.&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;guard.protect()&lt;/code&gt; swaps PII for placeholders like &lt;code&gt;[GIVEN_NAME_1]&lt;/code&gt;, and &lt;code&gt;guard.reveal()&lt;/code&gt; fills them back into the reply. The LLM never sees the name; the user still does.&lt;/li&gt;&#10;&lt;li&gt;Default-deny: every detected label is redacted except city, state and ZIP, so the assistant keeps coarse location without the street line.&lt;/li&gt;&#10;&lt;li&gt;Know the gaps: names in non-Latin scripts recall ~14% (Hindi 6%, Arabic 5%), and it scores 86.4% on a hostile-input suite. The repo calls it harm reduction, not perfect protection.&lt;/li&gt;&#10;&lt;li&gt;Same size class, different job: &lt;a href="https://cactuscompute.com/blog/whistle" rel="noopener external"&gt;Cactus Whistle&lt;/a&gt; is 16.9 MB speech-to-text in seven languages, 11 ms to first token on an M4 Pro CPU (Whisper base: 145 MB, 73 ms). It loads into the same engine as &lt;a href="https://huggingface.co/Cactus-Compute/needle3" rel="noopener external"&gt;Needle 3&lt;/a&gt;, their tool-calling model, so one call takes audio in and returns &lt;code&gt;set_lights(room=&amp;quot;kitchen&amp;quot;, on=false)&lt;/code&gt;. Voice commands for home automation with no cloud round trip.&lt;/li&gt;&#10;&lt;li&gt;The pattern: a tiny specialist at the edge does one narrow job (redact, transcribe, route), and the big model only sees what it needs. Both sets of benchmarks are vendor-reported.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>Microsoft eXecution Container (MXC)</title><link>https://saurabh-kumar.com/til/1791633600/</link><pubDate>Sat, 10 Oct 2026 12:00:00 +0000</pubDate><guid>https://saurabh-kumar.com/til/1791633600/</guid><description>&lt;p&gt;&lt;a href="https://github.com/microsoft/mxc" rel="noopener external"&gt;Microsoft eXecution Container (MXC)&lt;/a&gt; is an embeddable SDK for running untrusted commands under OS-enforced policies, not a hosted sandbox service.&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Defaults: Seatbelt on macOS, Bubblewrap on Linux, ProcessContainer on Windows. SDKs for Node, Rust, and .NET.&lt;/li&gt;&#10;&lt;li&gt;Restricts filesystem and network access. macOS hostname allowlists need a caller-managed proxy; not every backend is a VM.&lt;/li&gt;&#10;&lt;li&gt;Useful boundary: sandbox the command where it executes, not just the agent&amp;rsquo;s tool-composition script. Isolation limits damage; it does not make generated output trustworthy.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>SecretSpec</title><link>https://saurabh-kumar.com/til/1784116800/</link><pubDate>Wed, 15 Jul 2026 12:00:00 +0000</pubDate><guid>https://saurabh-kumar.com/til/1784116800/</guid><description>&lt;p&gt;&lt;a href="https://secretspec.dev/" rel="noopener external"&gt;SecretSpec&lt;/a&gt; declares secrets once in &lt;code&gt;secretspec.toml&lt;/code&gt; (names + descriptions, never values) and resolves them from any of 11 backends: keyring, 1Password, Vault, AWS, GCP, .env. Same command everywhere: &lt;code&gt;secretspec run --profile production -- npm start&lt;/code&gt;. Per-secret fallback chains (&lt;code&gt;providers = [&amp;quot;vault&amp;quot;, &amp;quot;keyring&amp;quot;, &amp;quot;env&amp;quot;]&lt;/code&gt;) and a &lt;code&gt;ref = { item, field }&lt;/code&gt; form points at a secret you already have elsewhere, no renaming. Sharpest bit: agents get held to a stricter bar by default. &lt;code&gt;require_reason = &amp;quot;agents&amp;quot;&lt;/code&gt; forces &lt;code&gt;secretspec run --reason &amp;quot;...&amp;quot;&lt;/code&gt; before an AI agent can read a secret, appended to a local audit log; humans running interactively are unaffected. Rust core, SDKs for Python/Go/Node/Ruby/PHP/Haskell. Worth piloting on a project drowning in &lt;code&gt;.env&lt;/code&gt; sprawl.&lt;/p&gt;&#10;</description></item><item><title>Opus 4.6 launch</title><link>https://saurabh-kumar.com/til/1770379200/</link><pubDate>Fri, 06 Feb 2026 12:00:00 +0000</pubDate><guid>https://saurabh-kumar.com/til/1770379200/</guid><description>&lt;p&gt;Opus 4.6 launch.&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;context compaction (beta) and 1M context window, enables longer agentic tasks without loosing context.&lt;/li&gt;&#10;&lt;li&gt;they claim it has found 500 Zero-Day Flaws in open-source projects (yet to see the proofs though)&lt;/li&gt;&#10;&lt;li&gt;agent teams, multiple agent coordinates with a leader agent. &lt;a href="https://code.claude.com/docs/en/agent-teams" rel="noopener external"&gt;https://code.claude.com/docs/en/agent-teams&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>UIPC and SIPC on blockchain</title><link>https://saurabh-kumar.com/til/1770292802/</link><pubDate>Thu, 05 Feb 2026 12:00:02 +0000</pubDate><guid>https://saurabh-kumar.com/til/1770292802/</guid><description>&lt;p&gt;On blockchain, UIPC (Universal IPC) and SIPC (Secure IPC) are frameworks that allows different network to talk to each other using a standard protocol. While UIPC acts as the universal courier, SIPC acts as the security guard. Together, they create &amp;ldquo;Internet of Blockchains&amp;rdquo;. &lt;a href="https://gemini.google.com/app/b8339d20bf7f33cf" rel="noopener external"&gt;Gemini&lt;/a&gt;&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href="https://docs.cosmos.network/ibc/v10.1.x/intro" rel="noopener external"&gt;Cosmos IBC&lt;/a&gt; &amp;amp; &lt;a href="https://wiki.polkadot.network/docs/learn-xcm" rel="noopener external"&gt;Polkadot - XCM&lt;/a&gt; are two industry leading protocols for UIPC&lt;/li&gt;&#10;&lt;li&gt;For the SIPC, &lt;strong&gt;Zero-Knowledge Proofs&lt;/strong&gt; and &lt;strong&gt;Rollup architecture&lt;/strong&gt; also &amp;ldquo;Trustless bridges&amp;rdquo; or &amp;ldquo;Cross-rollup communication&amp;rdquo; are often more frequently used terms in blockchain literatures.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item><item><title>Handling Django Authentication Redirects in HTMX Applications</title><link>https://saurabh-kumar.com/articles/2025/05/handling-django-authentication-redirects-in-htmx-applications/</link><pubDate>Fri, 02 May 2025 00:00:00 +0000</pubDate><guid>https://saurabh-kumar.com/articles/2025/05/handling-django-authentication-redirects-in-htmx-applications/</guid><description>&lt;p&gt;When a user’s session expires, an HTMX request can follow Django’s login redirect and swap the login page into the target element. I ran into this recently and used middleware to redirect the whole browser instead.&lt;/p&gt;&#10;&lt;h2 id="whats-going-wrong"&gt;What&amp;rsquo;s Going Wrong?&lt;/h2&gt;&#10;&lt;p&gt;HTMX updates part of a page, but an expired session can cause Django to redirect a request to the login page. The returned login HTML can then appear inside a div or table cell rather than replacing the page.&lt;/p&gt;&#10;&lt;p&gt;What we really want is to redirect the whole browser to the login page, and then&#10;bring users right back to where they were after they log in again. Simple idea,&#10;slightly tricky execution.&lt;/p&gt;&#10;&lt;h2 id="redirect-with-middleware"&gt;Redirect with middleware&lt;/h2&gt;&#10;&lt;p&gt;This middleware converts HTMX 302 responses into a full-page redirect using &lt;code&gt;HX-Redirect&lt;/code&gt;. It sets a &lt;code&gt;next&lt;/code&gt; parameter from the referring page or request path.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlparse&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HtmxAuthRedirectMiddleware&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; Middleware to handle HTMX authentication redirects properly.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; When an HTMX request results in a 302 redirect (typically for authentication),&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; this middleware:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; 1. Changes the response status code to 204 (No Content)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; 2. Adds an HX-Redirect header with the redirect URL&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; 3. Preserves the original request path in the &amp;#39;next&amp;#39; query parameter&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; This ensures that after authentication, the user is returned to the page&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; they were attempting to access, maintaining a seamless UX with HTMX.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; Credits: https://www.caktusgroup.com/blog/2022/11/11/how-handle-django-login-redirects-htmx/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt; &amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_response&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# HTMX request returning 302 likely is login required.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Take the redirect location and send it as the HX-Redirect header value,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# with &amp;#39;next&amp;#39; query param set to where the request originated. Also change&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# response status code to 204 (no content) so that htmx will obey the&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# HX-Redirect header value.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;HX-Request&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;true&amp;#34;&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;302&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Determine the next path from referer or current request path&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ref_header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Referer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ref_header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;referer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urlparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ref_header&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;next_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;referer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;next_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Parse the redirect URL&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;redirect_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urlparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;location&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Set response status code to 204 for HTMX to process the redirect&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;204&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Update the &amp;#34;?next&amp;#34; query parameter&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;query_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse_qs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redirect_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;next&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;next_path&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;new_query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urlencode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doseq&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Set the new HX-Redirect header&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;HX-Redirect&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;redirect_url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;?&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;new_query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;em&gt;This middleware is inspired by &lt;a href="https://www.caktusgroup.com/blog/2022/11/11/how-handle-django-login-redirects-htmx/" rel="noopener external"&gt;this&#10;post&lt;/a&gt;&#10;by the caktus group.&lt;/em&gt;&lt;/p&gt;&#10;&lt;h2 id="how-it-works"&gt;How It Works&lt;/h2&gt;&#10;&lt;p&gt;The middleware changes a 302 response to 204 so HTMX can process the &lt;code&gt;HX-Redirect&lt;/code&gt; header. That header redirects the whole browser. The &lt;code&gt;next&lt;/code&gt; parameter records the path to return to after login.&lt;/p&gt;&#10;&lt;p&gt;This applies to all HTMX 302 responses, not just authentication redirects. Add checks if other redirects in your application need different handling.&lt;/p&gt;&#10;&lt;h2 id="adding-this-to-your-project"&gt;Adding This to Your Project&lt;/h2&gt;&#10;&lt;p&gt;Add the middleware to your Django project and its &lt;code&gt;MIDDLEWARE&lt;/code&gt; list in &lt;code&gt;settings.py&lt;/code&gt;:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;MIDDLEWARE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# Your other middleware stuff...&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;yourapp.middleware.HtmxAuthRedirectMiddleware&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just make sure it comes after Django&amp;rsquo;s authentication middleware in the list - order matters here!&lt;/p&gt;&#10;&lt;p&gt;Edits:&lt;/p&gt;&#10;&lt;p&gt;2025-05-04: Use &lt;code&gt;urlparse&lt;/code&gt; and &lt;code&gt;parse_qs&lt;/code&gt; to securely handle urls. Thanks &lt;a href="https://fosstodon.org/@adamchainz/114448835195505930" rel="noopener external"&gt;Adam Johnson&lt;/a&gt;&lt;/p&gt;&#10;</description></item><item><title>actions/checkout</title><link>https://saurabh-kumar.com/til/1733832000/</link><pubDate>Tue, 10 Dec 2024 12:00:00 +0000</pubDate><guid>https://saurabh-kumar.com/til/1733832000/</guid><description>&lt;p&gt;&lt;a href="https://github.com/actions/checkout" rel="noopener external"&gt;&lt;code&gt;actions/checkout&lt;/code&gt;&lt;/a&gt; saves the workflow token (&lt;code&gt;GITHUB_TOKEN&lt;/code&gt; or a custom one) in the checked-out repo&amp;rsquo;s &lt;code&gt;.git/config&lt;/code&gt; by default. Workflows that upload the repo as an artifact leak it, and &lt;a href="https://unit42.paloaltonetworks.com/github-repo-artifacts-leak-tokens/" rel="noopener external"&gt;Unit 42 found many projects doing this&lt;/a&gt;. GitHub calls it intended behaviour. Turn it off, and scan workflows with &lt;a href="https://github.com/woodruffw/zizmor" rel="noopener external"&gt;zizmor&lt;/a&gt;, which &lt;a href="https://blog.yossarian.net/2024/12/06/zizmor-ultralytics-injection" rel="noopener external"&gt;would have caught the Ultralytics injection&lt;/a&gt;.&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yml" data-lang="yml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;- &lt;span class="nt"&gt;uses&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;actions/checkout@v4&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;persist-credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item></channel></rss>