<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Haven Messenger</title>
    <description>The latest articles on DEV Community by Haven Messenger (@havenmessenger).</description>
    <link>https://dev.to/havenmessenger</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3891528%2F1736c7dd-a6a7-443a-863c-0abb7d56e358.png</url>
      <title>DEV Community: Haven Messenger</title>
      <link>https://dev.to/havenmessenger</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/havenmessenger"/>
    <language>en</language>
    <item>
      <title>Business Email Compromise: The Fraud That Doesn't Break Any Encryption</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Wed, 12 Aug 2026 12:18:18 +0000</pubDate>
      <link>https://dev.to/havenmessenger/business-email-compromise-the-fraud-that-doesnt-break-any-encryption-4h56</link>
      <guid>https://dev.to/havenmessenger/business-email-compromise-the-fraud-that-doesnt-break-any-encryption-4h56</guid>
      <description>&lt;p&gt;Business email compromise, usually shortened to BEC, has been the largest reported category of cybercrime loss tracked by the FBI's Internet Crime Complaint Center for years running, ahead of ransomware and ahead of credential theft. It's also one of the least technically sophisticated attacks in active use. There's often no malware, no zero-day, no cracked cipher. The entire attack lives in the gap between "this email looks legitimate" and "this email is legitimate," and that gap is wider than most encryption marketing wants to admit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two different attacks that look identical to the victim
&lt;/h2&gt;

&lt;p&gt;BEC comes in two forms, and the distinction matters for defense. The first is &lt;strong&gt;account takeover&lt;/strong&gt;: an attacker phishes credentials or steals a session token, logs into the real mailbox, and sends from it directly. Every authentication signal a recipient could check passes, because it genuinely is that account sending that mail. SPF passes. DKIM passes. DMARC alignment passes. The message is, by every protocol-level measure, authentic.&lt;/p&gt;

&lt;p&gt;The second is &lt;strong&gt;domain impersonation&lt;/strong&gt;: the attacker registers a lookalike domain (rn instead of m, a swapped TLD, an extra hyphen) and sends from there, often after quietly monitoring a real email thread for weeks to learn the tone, the vendor names, and the amounts already in flight. No account is compromised. The forgery is in the domain, not the mailbox.&lt;/p&gt;

&lt;p&gt;Both produce the same result in an inbox: a message that reads as coming from someone the recipient already trusts, asking for something time-sensitive and financial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why DMARC enforcement helps with only one of the two
&lt;/h2&gt;

&lt;p&gt;SPF, DKIM, and DMARC exist to answer one question: did this message actually originate from a server the domain owner authorized? When DMARC is enforced at &lt;code&gt;p=reject&lt;/code&gt;, and not left at the far more common &lt;code&gt;p=none&lt;/code&gt; monitoring mode, it closes the domain impersonation vector almost completely. A lookalike domain sending unauthenticated mail gets rejected outright, or at minimum flagged before it lands.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key distinction.&lt;/strong&gt; DKIM and DMARC prove which mail server sent a message and that its headers weren't altered in transit. They say nothing about who was sitting at the keyboard, or whose credentials that keyboard belonged to. Account takeover BEC passes every one of these checks, because the check was never designed to answer that question.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the ceiling on authentication-layer defenses. A message from a genuinely compromised mailbox is, cryptographically, indistinguishable from a message the legitimate owner typed. Some of the same weaknesses that make forwarded and mailing-list mail hard to authenticate cleanly apply here too: the signature travels with the message regardless of who currently controls the account attached to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four patterns that account for most losses
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Mechanism&lt;/th&gt;
&lt;th&gt;Typical ask&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Executive fraud&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compromised or spoofed executive mailbox, often timed to travel or a known meeting&lt;/td&gt;
&lt;td&gt;Urgent wire transfer, gift cards, secrecy requested&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vendor invoice redirect&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compromised vendor mailbox monitoring a real, ongoing invoice thread&lt;/td&gt;
&lt;td&gt;"Our bank changed, use this account for the next payment"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Attorney impersonation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Spoofed or compromised law firm domain, timed around a real closing&lt;/td&gt;
&lt;td&gt;Wire the closing or escrow funds to a new account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Payroll diversion&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Compromised employee or HR mailbox&lt;/td&gt;
&lt;td&gt;Change direct-deposit routing details before the next pay cycle&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice the common thread across all four: none of them require the attacker to break anything cryptographic. They require patience, plausible timing, and a payment process with no independent verification step.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually stops it
&lt;/h2&gt;

&lt;p&gt;The controls that work aren't primarily cryptographic. They're process controls that assume any single email, however authentic it looks, can be wrong.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Out-of-band verification for any payment-detail change.&lt;/strong&gt; Call a phone number pulled from an existing record, never one supplied in the email itself, before honoring a new account number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual control on wire transfers above a threshold.&lt;/strong&gt; No single approver, regardless of seniority or urgency framing, should be able to release funds alone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DMARC enforcement at &lt;code&gt;p=reject&lt;/code&gt;, with SPF and DKIM properly aligned.&lt;/strong&gt; This closes the impersonation half of the problem outright and is table stakes even though it doesn't touch account takeover.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message signing for finance-sensitive internal communication.&lt;/strong&gt; A PGP or S/MIME signature tied to a specific private key gives a recipient something to check beyond "does this look right": did this message verify against the key I already have for this person.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Training staff to recognize the pattern, not the sender.&lt;/strong&gt; Urgency, secrecy, and a payment-detail change are the three-signal cluster that matters, independent of whose name is on the message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point is the one most training programs get backwards. Teaching people to scrutinize sender names and domains helps with impersonation, but account takeover BEC comes from an address that is, in every visible respect, correct. The signal that actually generalizes across both attack types is the shape of the request itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The session-token wrinkle that makes MFA less of a backstop than it used to be
&lt;/h2&gt;

&lt;p&gt;A common assumption is that multi-factor authentication closes the account-takeover half of this problem outright. It closes the credential-phishing version of it. It does much less against the adversary-in-the-middle phishing kits now common in BEC campaigns, which proxy a real login flow in real time and capture the session token issued after MFA succeeds, rather than trying to capture a reusable password. The victim completes a normal-looking login, MFA prompt included, and the attacker walks away with a live session cookie that bypasses the need to re-authenticate at all. A stolen session token is functionally indistinguishable, to the mail server, from the account owner simply staying logged in.&lt;/p&gt;

&lt;p&gt;This is part of why the process controls matter more than any single authentication upgrade. Phishing-resistant hardware keys (FIDO2/WebAuthn) close the adversary-in-the-middle gap in a way that OTP-based MFA doesn't, and they're worth adopting for exactly that reason. But a determined BEC operation only needs one compromised mailbox to run the executive-fraud or vendor-redirect pattern, and the defense that actually catches it is a human process that treats every payment-detail change as unverified until confirmed through a separate channel, regardless of how the request arrived or how authentic the account looked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a signed, encrypted channel helps and where it doesn't
&lt;/h2&gt;

&lt;p&gt;End-to-end encryption was never built to solve BEC, and it's worth being direct about that rather than implying otherwise. Encryption protects a message's contents from anyone who doesn't hold a key. It does nothing to verify who's sitting at the sender's keyboard, and a compromised account can send an encrypted message just as convincingly as a plaintext one.&lt;/p&gt;

&lt;p&gt;What a PGP-signed message adds is narrower and more specific: cryptographic proof that a message was signed with a particular private key, which is a stronger claim than "this domain's DKIM record checked out." If that private key lives somewhere an attacker who merely phished a web login can't reach, a forged executive request stops verifying, even from a compromised mail account, unless the attacker also has the signing key. That's a real, if partial, improvement over authentication headers alone. It's not a replacement for callback verification and dual control on money movement, and no vendor, us included, should suggest otherwise.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/business-email-compromise-fraud/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Thunderbolt and DMA Attacks: What a Port Can Do to a Locked Laptop</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Tue, 11 Aug 2026 12:22:19 +0000</pubDate>
      <link>https://dev.to/havenmessenger/thunderbolt-and-dma-attacks-what-a-port-can-do-to-a-locked-laptop-4an7</link>
      <guid>https://dev.to/havenmessenger/thunderbolt-and-dma-attacks-what-a-port-can-do-to-a-locked-laptop-4an7</guid>
      <description>&lt;p&gt;A locked laptop feels like a closed door. Full-disk encryption and a login screen are usually enough to stop a casual thief. Neither one, on its own, stops a device plugged into the right port from reading memory directly off the running system, because Thunderbolt was built to give external hardware a level of access that ordinary USB peripherals never get.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thunderbolt Is PCIe, Extended Out Through a Port
&lt;/h2&gt;

&lt;p&gt;Most external ports, a standard USB-A jack, for example, connect a peripheral to the system through a controller that mediates what the device can access. Thunderbolt works differently. It tunnels PCI Express, the same high-speed internal bus that graphics cards and NVMe drives use, out through an external connector. That's what makes Thunderbolt fast enough to drive an external GPU or a multi-monitor dock over a single cable. It's also what makes it a much more privileged interface than USB: a PCIe device isn't just handing data to the operating system through a driver, it can be granted direct memory access, DMA, which means reading and writing system RAM without going through the CPU or the OS at all.&lt;/p&gt;

&lt;p&gt;Direct memory access exists because it's useful. It's how a graphics card moves frame data efficiently, and how a fast storage controller avoids CPU overhead on every read and write. The security problem is that a malicious PCIe device, connected through a Thunderbolt port, can ask for the same kind of access and use it to read encryption keys, session tokens, or anything else sitting in memory while the machine is running, whether or not the screen is locked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Thunderspy Actually Demonstrated
&lt;/h2&gt;

&lt;p&gt;In 2020, researcher Bjorn Ruytenberg at Eindhoven University of Technology published Thunderspy, a set of attacks against Thunderbolt's security model. The research showed that with a few minutes of physical access to a Thunderbolt port, an attacker could reprogram the controller's firmware to clone the identity of an already-trusted device, or in some cases disable Thunderbolt security checks entirely, even on systems where the more restrictive security levels were enabled and even when the machine was locked or in sleep. Some of the described attacks required opening the laptop case briefly to attach hardware directly to the Thunderbolt controller; others worked through the port alone.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The finding wasn't that Thunderbolt has a bug. It's that the security model assumed a level of attacker effort that turned out to be lower than expected, and that firmware-level trust decisions made once at pairing time weren't being re-verified strongly enough afterward.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This class of attack sits in the same family as &lt;a href="https://havenmessenger.com/blog/posts/cold-boot-attacks-ram-forensics/" rel="noopener noreferrer"&gt;cold boot attacks&lt;/a&gt; in that both target data sitting in memory rather than data at rest, but the mechanism is different. Cold boot attacks exploit the physical property that RAM contents fade rather than vanish instantly after power loss. DMA attacks over Thunderbolt exploit a live, powered, running system through a legitimate hardware interface designed to grant broad access.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mitigations That Followed
&lt;/h2&gt;

&lt;p&gt;Intel's response was Kernel DMA Protection, which uses the system's IOMMU (the same VT-d or AMD-Vi hardware used for virtualization memory isolation) to restrict what a Thunderbolt-connected PCIe device can access before the operating system has explicitly authorized it. On supporting hardware and operating systems, this closes most of the pre-boot and pre-authorization window that Thunderspy relied on. The protection isn't universal retroactively: it depends on firmware and OS support that older systems, including many machines from before Kernel DMA Protection existed, simply don't have.&lt;/p&gt;

&lt;p&gt;Thunderbolt 4 made this stronger by requiring Kernel DMA Protection as part of the certification specification itself, rather than leaving it as an optional implementation detail the way Thunderbolt 3 did. That's a meaningful difference: a Thunderbolt 3 machine's actual exposure depends on whether its specific vendor implemented the protection, while a certified Thunderbolt 4 machine is required to have it.&lt;/p&gt;

&lt;p&gt;Apple's implementation on Mac hardware has followed a somewhat different path, layered on top of the T2 security chip on Intel-based Macs and, since the shift to Apple Silicon, on the tighter hardware and firmware integration of the M-series systems. The practical effect has been a narrower attack surface than a typical Windows laptop of the same era, though "narrower" isn't the same as "immune," and researchers have continued to probe Thunderbolt and USB4 implementations across vendors as the specification itself evolves. The lesson generalizes past any one platform: DMA protection is a property of the specific firmware and OS combination running on a given machine, not a property of the word "Thunderbolt" printed next to the port.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;DMA exposure&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Thunderbolt 3, Kernel DMA Protection not implemented&lt;/td&gt;
&lt;td&gt;Full pre-Thunderspy-mitigation exposure while unlocked or briefly accessible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thunderbolt 3, Kernel DMA Protection implemented&lt;/td&gt;
&lt;td&gt;Significantly reduced, but depends on OS and firmware support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thunderbolt 4 (certification requires the protection)&lt;/td&gt;
&lt;td&gt;Kernel DMA Protection mandatory by specification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thunderbolt disabled entirely in firmware&lt;/td&gt;
&lt;td&gt;No PCIe tunneling exposure through the port at all&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Sleep, Not Just Lock, Is the Exposure Window That Matters
&lt;/h2&gt;

&lt;p&gt;A locked screen with the system still fully powered and running is meaningfully different from a system that's been shut down or hibernated with the disk fully unmounted. Full-disk encryption protects data at rest, when the machine is off, but a locked or sleeping machine still has decryption keys and unlocked data sitting in RAM, which is exactly what a DMA attack targets. This is the same underlying exposure that &lt;a href="https://havenmessenger.com/blog/posts/evil-maid-attacks/" rel="noopener noreferrer"&gt;evil maid attacks&lt;/a&gt; exploit more broadly, brief unsupervised physical access to a device that's locked but still running, though DMA over Thunderbolt is a specific technical path into that broader category rather than a synonym for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Actually Reduces the Risk
&lt;/h2&gt;

&lt;p&gt;For most people, the practical exposure is low: this requires physical access and specialized hardware, not something a remote attacker can do. It matters most for anyone who leaves a laptop briefly unattended in a context where a skilled adversary might have physical access, a hotel room, a border crossing, a shared workspace. Where it matters, the concrete steps are disabling Thunderbolt entirely in firmware settings when it's not in active use, keeping firmware and OS updated so Kernel DMA Protection stays current, and fully shutting down rather than sleeping when leaving a device unattended for any length of time, since a powered-off machine with &lt;a href="https://havenmessenger.com/blog/posts/secure-boot-explained/" rel="noopener noreferrer"&gt;secure boot&lt;/a&gt; and full-disk encryption removes the live-memory attack surface entirely.&lt;/p&gt;

&lt;p&gt;None of this argues against Thunderbolt as a technology. The speed it enables is real and useful. It argues for treating an external port that can request direct memory access the way you'd treat any other high-privilege interface: something to be deliberate about, not something to assume is safe by default because it looks like an ordinary cable.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/thunderbolt-dma-attacks-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>hardware</category>
    </item>
    <item>
      <title>CRLite: Fitting Every Revoked Certificate in Your Browser</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Mon, 10 Aug 2026 12:19:25 +0000</pubDate>
      <link>https://dev.to/havenmessenger/crlite-fitting-every-revoked-certificate-in-your-browser-45m2</link>
      <guid>https://dev.to/havenmessenger/crlite-fitting-every-revoked-certificate-in-your-browser-45m2</guid>
      <description>&lt;p&gt;Certificate revocation on the web has been quietly broken for years. Browsers ask a certificate authority whether a certificate is still valid, and that question leaks your browsing, adds latency, and often fails open when the answer never arrives. CRLite is a different bet: ship the entire list of revocations to the browser, compressed small enough to fit, and never ask anyone anything.&lt;/p&gt;

&lt;p&gt;When your browser connects to a site over HTTPS, it receives a certificate that proves the site controls its domain. Sometimes a certificate needs to be pulled before it expires, because the private key leaked, the certificate was issued in error, or the domain changed hands. That is revocation. The hard part was never deciding to revoke. It was getting the news to every browser, in time, without creating new problems along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the Old Ways Failed
&lt;/h2&gt;

&lt;p&gt;The two traditional mechanisms both have structural flaws. Certificate revocation lists (CRLs) are files a CA publishes listing every revoked serial number. They grew large and were fetched rarely, so a browser's copy was often stale. The Online Certificate Status Protocol (OCSP) replaced the big file with a live query: before trusting a certificate, the browser asks the CA about that specific certificate.&lt;/p&gt;

&lt;p&gt;OCSP fixed staleness and introduced three new problems. It is slow, adding a network round trip to the CA on the critical path of every new connection. It is a privacy leak, because the CA learns which sites you visit and when. And it usually fails open: if the OCSP responder is unreachable, browsers proceed rather than break the web, which means an attacker who can block the query defeats the check entirely. OCSP stapling helps with the speed and privacy issues by having the server attach a fresh proof, but it depends on server operators enabling it, and adoption was never universal.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The privacy problem in one line:&lt;/strong&gt; Every OCSP request tells a certificate authority that a particular user is about to visit a particular website. A revocation check should not double as a browsing-history feed to a third party.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The CRLite Bet: Push Everything
&lt;/h2&gt;

&lt;p&gt;CRLite, a system that came out of research published in 2017 and was later built into Firefox, takes the position that the browser should just hold the answer for every certificate locally. No live query, no leak, no failing open. To do that it needs two things: a complete list of all publicly trusted certificates, and knowledge of which of them are revoked.&lt;/p&gt;

&lt;p&gt;The complete list comes from Certificate Transparency logs, which record essentially every certificate issued by a publicly trusted CA. The revocation status comes from aggregating the CAs' own CRLs. Combine them and you can partition the entire universe of known certificates into two sets: the ones that are still valid, and the ones that are revoked. The trouble is size. That universe is hundreds of millions of certificates. You cannot ship that to every browser several times a day.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bloom Filter Cascade
&lt;/h2&gt;

&lt;p&gt;Here is the elegant part. A &lt;strong&gt;Bloom filter&lt;/strong&gt; is a compact structure that answers set-membership questions with a useful asymmetry: if it says an item is not in the set, that is always true, but if it says an item is in the set, it might be wrong. Those wrong answers are false positives, and their rate depends on how much space you spend.&lt;/p&gt;

&lt;p&gt;CRLite builds a cascade of these filters. Because it knows the full universe in advance, it can do something a normal Bloom filter cannot.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Layer 1.&lt;/strong&gt; Build a Bloom filter over the set of revoked certificates. Query it for every valid certificate too. Most valid certificates correctly come back as not revoked, but a small number are false positives that the filter wrongly flags as revoked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layer 2.&lt;/strong&gt; Take exactly those false positives, the valid certificates that layer 1 got wrong, and build a second Bloom filter over them. Now a few revoked certificates will be false positives in this layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layer 3.&lt;/strong&gt; Build a filter over that set of mistakes. Each layer only has to correct the errors of the layer above, so each layer is far smaller than the last.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The layers alternate, correcting each other, and the error shrinks geometrically until it reaches zero over the known universe. To check a certificate, the browser walks the layers in order. The first layer that says not present gives a definitive answer, and the level at which the item drops out tells you whether it was revoked or valid. Because the whole set was known when the cascade was built, there are no false positives and no false negatives for any certificate in that universe.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A single Bloom filter trades accuracy for space. A cascade uses a second filter to catch the first one's mistakes, a third to catch the second's, and so on, until the structure is exact over the exact set it was built from.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The result compresses the revocation status of the entire web into a few megabytes, small enough to distribute to browsers regularly, with much smaller delta updates in between full builds. The check then happens entirely on your device, offline, in microseconds, with no CA learning anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  What CRLite Does and Does Not Cover
&lt;/h2&gt;

&lt;p&gt;CRLite is not magic, and its guarantees have edges worth stating plainly.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;How CRLite handles it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Privacy&lt;/td&gt;
&lt;td&gt;Fully addressed. Checks are local, so no revocation query reveals your browsing to a CA.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed&lt;/td&gt;
&lt;td&gt;Fully addressed. No network round trip on the connection path.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Freshness window&lt;/td&gt;
&lt;td&gt;A revocation is only known after the next dataset is built and pushed. Very recent revocations may not yet be reflected, though delta updates keep the gap short.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coverage&lt;/td&gt;
&lt;td&gt;Bounded by what Certificate Transparency and the aggregated CRLs contain. A certificate outside those sources is outside the dataset.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In other words, CRLite decisively fixes the privacy and performance failures of live checking, and it turns fail-open into a locally held, hard answer. What it cannot do is know about a revocation faster than the pipeline that feeds it. That is a far better failure mode than the one it replaces, where a blocked query meant no check at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Matters Beyond the Browser
&lt;/h2&gt;

&lt;p&gt;CRLite is a case study in a pattern that shows up throughout privacy engineering. The obvious approach, asking a server in real time, leaks information and creates a dependency on availability. The better approach is often to move the data to the user and let the check happen locally, so no query ever has to be made. The same instinct drives k-anonymity in breach checking and local-first designs generally.&lt;/p&gt;

&lt;p&gt;The takeaway for anyone evaluating a system that promises to check something on your behalf is to ask where the check happens and what it reveals. A check that phones home is a check that watches you. CRLite shows that with the right data structure, you can often keep the check and drop the surveillance, and that trade is almost always worth making.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/crlite-certificate-revocation/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Identity-Based Encryption, Explained</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Sat, 08 Aug 2026 12:19:58 +0000</pubDate>
      <link>https://dev.to/havenmessenger/identity-based-encryption-explained-l5b</link>
      <guid>https://dev.to/havenmessenger/identity-based-encryption-explained-l5b</guid>
      <description>&lt;p&gt;In ordinary public-key cryptography, before you can encrypt a message to someone you have to find and verify their public key. Identity-based encryption removes that step: the recipient's identity, their email address, is the public key. It is an elegant idea with a sharp edge, because someone has to be able to hand out the matching private keys, and that someone can read everything.&lt;/p&gt;

&lt;p&gt;Adi Shamir posed the question in 1984. Could you build a system where a person's public key is simply their name or email address, so a sender needs nothing but the recipient's identity to encrypt to them? The appeal was obvious. The whole apparatus of certificates, key servers, and web-of-trust exists to answer one question: is this public key really theirs? If the key were just the address itself, that question would disappear. Shamir showed how to do it for signatures but left encryption open. It stayed open for seventeen years.&lt;/p&gt;

&lt;p&gt;In 2001, Dan Boneh and Matthew Franklin published a practical construction using a piece of mathematics that had mostly been a tool for attacking cryptosystems: bilinear pairings on elliptic curves. Around the same time, Clifford Cocks published a different construction based on quadratic residues. Boneh and Franklin's pairing-based scheme became the one everyone built on, and identity-based encryption, usually shortened to IBE, went from a twenty-year-old open problem to deployable software.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Setup: One Authority, Many Identities
&lt;/h2&gt;

&lt;p&gt;IBE revolves around a central party called the Private Key Generator, or PKG. When the system starts, the PKG generates a master secret and a set of public system parameters that it publishes to everyone. Those parameters, plus a recipient's identity string, are all a sender needs.&lt;/p&gt;

&lt;p&gt;The flow works like this. Alice wants to encrypt a message to &lt;code&gt;bob@example.com&lt;/code&gt;. She takes the public system parameters and the literal string &lt;code&gt;bob@example.com&lt;/code&gt;, runs the encryption algorithm, and produces ciphertext. She never contacted Bob, never looked up a key, never checked a certificate. Bob, to read it, goes to the PKG, authenticates himself as the owner of that address, and receives the private key that corresponds to it. The PKG derives that private key from its master secret and the identity string. Bob decrypts.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The asymmetry.&lt;/strong&gt; Encryption needs only public information plus the recipient's identity, so anyone can do it at any time, even before the recipient has ever contacted the system. Decryption needs a private key that only the PKG can produce. The public key exists the moment the identity does; the private key is issued on demand.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Pairings Make It Work
&lt;/h2&gt;

&lt;p&gt;The mechanism rests on a bilinear pairing, a function that takes two points on an elliptic curve and maps them to a value in another group, with a special property: you can move a scalar multiplier from one input to the output and back. Written loosely, pairing of (a times P, b times Q) equals pairing of (P, Q) raised to the product a times b. This lets the scheme link two secrets that were never combined directly.&lt;/p&gt;

&lt;p&gt;In Boneh-Franklin, the recipient's identity is hashed to a curve point. The PKG's master secret is a scalar. The recipient's private key is the master secret applied to the identity point. When Alice encrypts, she uses a fresh random value and the identity point to build the ciphertext so that only someone holding the identity's private key can invert it, and the pairing is what makes the two halves cancel out correctly during decryption.&lt;/p&gt;

&lt;p&gt;The security rests on a hardness assumption in the pairing setting, a bilinear variant of the Diffie-Hellman problem. As long as that problem is intractable, an attacker who sees the ciphertext and the public parameters cannot recover the message without the identity's private key.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Escrow Problem Is the Whole Story
&lt;/h2&gt;

&lt;p&gt;Here is the part the elegance tends to obscure. The PKG derives every user's private key from its own master secret. That means the PKG can derive every user's private key, whenever it wants, without telling anyone. It does not need to break anything, it does not need a court order to compel a third party, it simply computes the key it was always able to compute. This is &lt;strong&gt;key escrow by design&lt;/strong&gt;, and it is not a bug you can patch. It is the mechanism.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In a certificate-based system, your private key is yours and no one else generates it. In identity-based encryption, the authority that issues your key can regenerate it forever. The trust you place in a certificate authority is that it will not lie about whose key is whose. The trust you place in a PKG is that it will not read your mail.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a fundamentally different and larger amount of trust. A compromised certificate authority can impersonate you going forward, which is serious, but it cannot retroactively decrypt traffic that was encrypted to your real key. A compromised PKG can decrypt everything, past and present, that was ever encrypted under its parameters. The PKG is a single point that holds the keys to the entire deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What People Do About It
&lt;/h2&gt;

&lt;p&gt;IBE research spent years trying to soften the escrow problem, and the mitigations are instructive because none of them fully removes it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Threshold PKGs.&lt;/strong&gt; Split the master secret across several authorities using secret sharing, so no single one can derive a key alone. This helps only if the authorities are genuinely independent and do not collude. It raises the bar; it does not eliminate the capability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Certificateless encryption.&lt;/strong&gt; A 2003 variant by Al-Riyami and Paterson combines an authority-derived partial key with a user-chosen secret, so the authority alone cannot decrypt. This trades away some of IBE's original convenience, because the sender now needs a user-specific value again.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accountable IBE.&lt;/strong&gt; Schemes that make unauthorized key generation detectable after the fact, so a cheating PKG leaves evidence. Deterrence, not prevention.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pattern across all of them is the same. You can distribute the trust, make it accountable, or add a user secret, but the closer you get to removing the authority's power, the more you give back the very property that made IBE attractive in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where IBE Actually Fits
&lt;/h2&gt;

&lt;p&gt;The escrow property is fatal for private consumer messaging and a feature for certain enterprise settings. A company that wants to encrypt internal email but must retain the ability to read it under compliance rules, or recover a departed employee's mailbox, sees escrow as exactly the recovery mechanism it needs. Voltage Security commercialized IBE-based email encryption in the 2000s on this basis, and the approach found a home in regulated environments. The IEEE and IETF have published IBE specifications for these use cases.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;Certificate-based (PGP, S/MIME)&lt;/th&gt;
&lt;th&gt;Identity-based (IBE)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Get recipient's public key&lt;/td&gt;
&lt;td&gt;Look up and verify a certificate&lt;/td&gt;
&lt;td&gt;Use their identity string directly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who generates the private key&lt;/td&gt;
&lt;td&gt;The user, locally&lt;/td&gt;
&lt;td&gt;The central authority&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can a third party decrypt&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;The PKG always can&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;Private communication between individuals&lt;/td&gt;
&lt;td&gt;Compliance and recovery in a controlled org&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It is worth putting IBE next to attribute-based encryption, a later generalization where you encrypt to a policy over attributes rather than a single identity. It shares the same authority-issues-keys structure and inherits the same escrow question, which is a good reminder that the tradeoff is not unique to IBE but baked into the family of schemes where a central party mints decryption keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Haven Fits
&lt;/h2&gt;

&lt;p&gt;Haven deliberately does not use an escrow model. Your identity keys are generated on your device and protected by a passphrase that never leaves it, so there is no central party that can regenerate them and no master secret whose compromise would unlock everyone. Encrypted email uses PGP for interoperability, and group chat uses MLS, both of which keep the decryption capability with the endpoints rather than an issuer. IBE is a genuinely clever answer to the key-distribution problem, and studying it clarifies the choice we made: the convenience of encrypting to a bare identity is real, but the price is a party who can read everything, and for a private messenger that price is the wrong one to pay.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/identity-based-encryption-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Ed25519 vs ECDSA: Why the Nonce Decides Everything</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Fri, 07 Aug 2026 12:18:56 +0000</pubDate>
      <link>https://dev.to/havenmessenger/ed25519-vs-ecdsa-why-the-nonce-decides-everything-4260</link>
      <guid>https://dev.to/havenmessenger/ed25519-vs-ecdsa-why-the-nonce-decides-everything-4260</guid>
      <description>&lt;p&gt;ECDSA and Ed25519 both sign data with elliptic curves, and both produce a 64-byte signature that verifies in a fraction of a millisecond. The difference between them is almost invisible on paper: ECDSA needs a fresh secret random number for every signature, and Ed25519 computes that number instead. That one design choice is the reason real people have lost real private keys.&lt;/p&gt;

&lt;p&gt;A digital signature answers a narrow question: did the holder of a specific private key approve this exact message? It is what proves a software update came from its author, what binds a TLS certificate to a domain, and what authorizes a Git commit or an SSH login. Get the math wrong and the signature still verifies, so the failure is silent until someone extracts the key from the signatures themselves.&lt;/p&gt;

&lt;p&gt;ECDSA (the Elliptic Curve Digital Signature Algorithm) and Ed25519 are the two schemes you meet most often. Understanding where they differ is less about the curves they run on and more about a single value that ECDSA calls &lt;em&gt;k&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The value that must never repeat
&lt;/h2&gt;

&lt;p&gt;To make an ECDSA signature you pick a per-signature secret number, usually written &lt;em&gt;k&lt;/em&gt; and often called the nonce. You multiply it by the curve's base point, take a coordinate of the result, and combine it with a hash of the message and your private key to produce the two halves of the signature, &lt;em&gt;r&lt;/em&gt; and &lt;em&gt;s&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The rule is absolute: &lt;em&gt;k&lt;/em&gt; must be unique and unpredictable for every signature you ever make with a given key. Break that rule and the algebra unravels. If two signatures reuse the same &lt;em&gt;k&lt;/em&gt;, an observer who sees both can solve two equations for the one unknown and recover your private key with arithmetic a pocket calculator could handle. The signatures do not have to be on the same message. They just have to share a nonce.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The core failure.&lt;/strong&gt; An ECDSA nonce is not a public parameter you can be sloppy with. It is as sensitive as the private key itself. Reuse it once, or generate it predictably, and the key is exposed to anyone holding the signatures.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  When the rule was broken in public
&lt;/h2&gt;

&lt;p&gt;This is not a theoretical footgun. Two of the most cited key-recovery incidents in modern security both trace back to a bad &lt;em&gt;k&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In 2010, at the 27th Chaos Communication Congress, the group fail0verflow demonstrated that Sony had signed PlayStation 3 firmware using ECDSA with a &lt;strong&gt;constant&lt;/strong&gt; nonce. The same &lt;em&gt;k&lt;/em&gt; appeared on every signature. From two signed messages, the private key that authorized code for the entire console was recoverable. Sony could not fix it by rotating the key on shipped hardware, because the value was baked into the trust chain.&lt;/p&gt;

&lt;p&gt;In August 2013, developers discovered that a flaw in Android's &lt;code&gt;SecureRandom&lt;/code&gt; implementation could produce repeated output. Bitcoin wallets on affected devices signed transactions with ECDSA, and when two transactions reused a nonce, the signing key was exposed. Coins were stolen directly from the affected addresses. The Bitcoin project issued a security advisory and wallets were patched, but the underlying lesson was old: your signature scheme is only as strong as your random number generator on its worst day.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A cryptosystem that fails when the random number generator hiccups is a cryptosystem that will eventually fail, because random number generators hiccup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Two ways to make the nonce safe
&lt;/h2&gt;

&lt;p&gt;There are two answers to the nonce problem, and they define the split between modern ECDSA and Ed25519.&lt;/p&gt;

&lt;p&gt;The first answer keeps ECDSA but stops trusting the RNG. &lt;strong&gt;RFC 6979&lt;/strong&gt; specifies deterministic ECDSA: instead of drawing &lt;em&gt;k&lt;/em&gt; from a random source, you derive it by running an HMAC construction over the message and the private key. The output is unpredictable to anyone without the key, unique per message, and completely reproducible. No entropy is consumed at signing time, so a broken RNG can no longer leak the key. Well-maintained ECDSA libraries default to this today.&lt;/p&gt;

&lt;p&gt;The second answer is to design the scheme so the nonce is deterministic from the start. &lt;strong&gt;Ed25519&lt;/strong&gt;, standardized in RFC 8032, is EdDSA over a twisted Edwards form of Curve25519. Its nonce is derived by hashing the private key material together with the message using SHA-512. There is no random &lt;em&gt;k&lt;/em&gt; to reuse and no RNG in the signing path at all. The property that ECDSA had to bolt on with RFC 6979 is native to Ed25519.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Ed25519 pulls ahead
&lt;/h2&gt;

&lt;p&gt;Deterministic nonces are the headline, but Ed25519 was engineered to remove several other classes of mistake at once.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property&lt;/th&gt;
&lt;th&gt;ECDSA (NIST P-256)&lt;/th&gt;
&lt;th&gt;Ed25519&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Per-signature nonce&lt;/td&gt;
&lt;td&gt;Random, unless RFC 6979 is used&lt;/td&gt;
&lt;td&gt;Deterministic by design&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Side-channel resistance&lt;/td&gt;
&lt;td&gt;Needs careful constant-time coding&lt;/td&gt;
&lt;td&gt;Complete addition formulas, no secret-dependent branches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signature malleability&lt;/td&gt;
&lt;td&gt;Malleable (both s and its negation verify)&lt;/td&gt;
&lt;td&gt;Canonical encoding, non-malleable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Key and signature size&lt;/td&gt;
&lt;td&gt;32-byte key, 64-70 byte signature (DER)&lt;/td&gt;
&lt;td&gt;32-byte key, fixed 64-byte signature&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Curve provenance&lt;/td&gt;
&lt;td&gt;NIST seed with unexplained origin&lt;/td&gt;
&lt;td&gt;Rigid, publicly justified parameters&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The side-channel point is easy to underrate. ECDSA on the NIST curves can be implemented safely, but the safe path requires constant-time scalar multiplication and careful handling of the modular inverse. Ed25519's curve arithmetic uses complete addition formulas that work for every input, so there are no special cases and no secret-dependent branches for a timing attack to read. The scheme makes the safe implementation the natural one.&lt;/p&gt;

&lt;p&gt;Malleability matters for systems that hash the signature itself. ECDSA's &lt;em&gt;s&lt;/em&gt; and its negation both verify, so an attacker can flip a valid signature into a different valid signature for the same message. This is what drove early Bitcoin transaction-malleability problems. Ed25519 pins a single canonical form, closing that door.&lt;/p&gt;

&lt;h2&gt;
  
  
  So why does anyone still use ECDSA?
&lt;/h2&gt;

&lt;p&gt;Because the ecosystem moves slowly and ECDSA got there first. NIST standardized the P-256, P-384, and P-521 curves years before Ed25519 existed, and those curves are written into a long list of compliance regimes, hardware security modules, smartcards, and government procurement rules. If you need a FIPS-validated module or you are issuing certificates into an old public key infrastructure, ECDSA is often the only option on the menu.&lt;/p&gt;

&lt;p&gt;There is also a lingering distrust of the NIST curves themselves. Their parameters were generated from a seed whose origin was never fully explained, which sits uncomfortably next to the Dual EC DRBG episode, where a NIST-blessed random generator turned out to have a plausible backdoor. Curve25519 was designed in the open with every parameter choice justified against published safety criteria, which is a large part of why it spread through the tools that got to choose freely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing in practice
&lt;/h2&gt;

&lt;p&gt;For anything new where you control both ends, Ed25519 is the straightforward pick. It is fast, small, hard to misuse, and supported by OpenSSH, TLS 1.3, modern signing tools, and most current language libraries. When you must interoperate with a system that only speaks ECDSA, use a library that implements RFC 6979 deterministic nonces and constant-time arithmetic, and verify that it does rather than assuming.&lt;/p&gt;

&lt;p&gt;The deeper takeaway generalizes past these two schemes. A good cryptographic design does not merely permit correct use. It removes the ways to be wrong. ECDSA trusted the caller to supply a perfect nonce every time, and that trust was misplaced often enough to fill conference talks. Ed25519 took the decision away. When you evaluate any primitive, the question worth asking is not only whether it can be used securely, but whether it can be used insecurely, and how easily.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/ed25519-vs-ecdsa-signatures/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>cryptography</category>
      <category>webdev</category>
    </item>
    <item>
      <title>HTTP Message Signatures (RFC 9421): Integrity That Survives Proxies</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Thu, 06 Aug 2026 12:19:14 +0000</pubDate>
      <link>https://dev.to/havenmessenger/http-message-signatures-rfc-9421-integrity-that-survives-proxies-5d1i</link>
      <guid>https://dev.to/havenmessenger/http-message-signatures-rfc-9421-integrity-that-survives-proxies-5d1i</guid>
      <description>&lt;p&gt;TLS is very good at one thing: keeping a connection private and intact between two endpoints. But a modern API request rarely travels over a single connection. It passes through load balancers, API gateways, and reverse proxies, each of which terminates TLS and opens a fresh one. At every hop, the cryptographic protection resets. RFC 9421 signs the message itself, so its authenticity travels with it.&lt;/p&gt;

&lt;p&gt;HTTP Message Signatures became an IETF standard in February 2024 as RFC 9421. It defines a way to produce a cryptographic signature over selected parts of an HTTP request or response, and to carry that signature in two headers so the recipient can verify it. The concept is not new. For years, projects used the earlier Cavage draft, and services like Amazon's request signing and Mastodon's federation solved the same problem with bespoke schemes. RFC 9421 is the standardized, carefully specified version of that idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap TLS leaves open
&lt;/h2&gt;

&lt;p&gt;Consider a payment request that flows from a client through a CDN, then an API gateway, then to the backend service that actually moves money. TLS protects each of those three legs separately. The CDN and the gateway both decrypt the request, look at it, and re-encrypt it for the next hop. This is by design; a gateway that could not read the request could not route it.&lt;/p&gt;

&lt;p&gt;The consequence is that the backend has no cryptographic assurance about who originally sent the request or whether an intermediary altered it. It has to trust every hop in the chain. For most traffic that is fine. For a request that authorizes a transaction, that is a lot of trust spread across infrastructure the backend does not control.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Transport security versus message security: TLS secures the pipe. A message signature secures the letter. If the letter is signed, it does not matter how many post offices it passes through: the recipient can verify it came from the stated sender and was not edited in transit. RFC 9421 makes the HTTP request the letter.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How a signature is built
&lt;/h2&gt;

&lt;p&gt;The signer does not sign the raw bytes of the request. Raw HTTP is too malleable, since proxies legitimately reorder headers, change capitalization, and rewrite whitespace. Instead, RFC 9421 defines a canonical form. The signer picks which components to cover, assembles them into a well-defined string called the signature base, and signs that.&lt;/p&gt;

&lt;p&gt;Components come in two kinds. Ordinary header fields are referenced by name. Special values about the request itself are called derived components and are written with a leading @ symbol:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;@method&lt;/strong&gt;: the request method, such as POST&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/authority"&gt;@authority&lt;/a&gt;&lt;/strong&gt;: the host and port&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a class="mentioned-user" href="https://dev.to/path"&gt;@path&lt;/a&gt;&lt;/strong&gt;: the request path&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;@target-uri&lt;/strong&gt;: the full request URI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;content-digest&lt;/strong&gt;: a hash of the body, so the payload is covered too&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By covering the method, path, authority, and a digest of the body, the signature binds the request's meaning. An attacker cannot change POST to DELETE, redirect the path, or swap the body without invalidating the signature. Signing a hash of the body rather than the body itself, using the Content-Digest header from RFC 9530, keeps the signing input small while still protecting the payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two headers
&lt;/h2&gt;

&lt;p&gt;A signed request carries two related header fields. &lt;strong&gt;Signature-Input&lt;/strong&gt; declares what was signed and the signature's parameters. &lt;strong&gt;Signature&lt;/strong&gt; carries the actual signature bytes, keyed to the same label. A single request can carry more than one signature, each with its own label, which is how a gateway can add its own signature without disturbing the client's.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Signature-Input names the ingredients and the recipe. Signature is the result. A verifier reads Signature-Input to reconstruct the exact signature base from the request it received, then checks that the bytes in Signature validate against it with the identified key.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The parameters inside Signature-Input are where much of the security lives:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;keyid&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Identifies which key the verifier should use&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;alg&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The signature algorithm, such as ed25519 or ecdsa-p256-sha256&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;created&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A timestamp for when the signature was made&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;expires&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;When the signature should stop being accepted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;nonce&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A unique value to detect and reject replays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;tag&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;An application-specific label describing the signature's purpose&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Replay protection, which TLS does not give you either
&lt;/h2&gt;

&lt;p&gt;A captured, validly signed request could otherwise be replayed. Signing "transfer 100 dollars" once and then sending it ten times would be a serious flaw. RFC 9421 addresses this with the created, expires, and nonce parameters. A verifier can reject signatures that are too old, refuse ones past their expiry, and remember recently seen nonces to reject duplicates. Because those parameters are inside the signed base, an attacker cannot alter them to sidestep the check. The signature covers its own freshness guarantees.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choosing an algorithm
&lt;/h2&gt;

&lt;p&gt;RFC 9421 supports several signature algorithms, and the choice is a real decision. Asymmetric algorithms such as Ed25519, ECDSA over P-256, and RSA-PSS let the verifier hold only a public key, which is the right model when many parties verify signatures from a signer they do not share a secret with. HMAC, a symmetric option, is faster and simpler but requires the two parties to share a secret key, which suits closed service-to-service links. The elliptic curve options are generally preferred for new designs on size and speed grounds.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A footgun to avoid: Never let the verifier blindly trust the alg parameter from the request to decide how to check the signature. A verifier that accepts whatever algorithm the message claims can be tricked into downgrading to a weaker one, or into treating a public key as an HMAC secret. Pin the expected algorithm to the key, identified by keyid, on the verifier side. This is the same class of mistake that produced the well-known JWT algorithm-confusion vulnerabilities.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Where it is actually used
&lt;/h2&gt;

&lt;p&gt;HTTP Message Signatures show up wherever integrity has to outlast the connection. Open banking and payment APIs use request signing so a transaction authorization is provably intact end to end. The GNAP authorization protocol uses it to bind requests to a key. Federated social systems sign server-to-server requests so one instance can verify another. Any design where a request crosses trust boundaries, and the endpoint needs to know the request was not tampered with along the way, is a candidate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does not replace
&lt;/h2&gt;

&lt;p&gt;Message signatures are an integrity and authenticity tool, not a confidentiality one. A signed request is not a secret; anyone who sees it can read it. You still want TLS for confidentiality on every hop. The two compose cleanly: TLS keeps intermediaries from reading the traffic they should not, and the signature keeps them from tampering with the parts they can read. Signing also does not manage keys for you. It assumes a key distribution and rotation story already exists, which for many teams is the harder half of the work.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/http-message-signatures-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Channel Binding: Tying Your Login to the Right TLS Connection</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Wed, 05 Aug 2026 12:22:08 +0000</pubDate>
      <link>https://dev.to/havenmessenger/channel-binding-tying-your-login-to-the-right-tls-connection-49id</link>
      <guid>https://dev.to/havenmessenger/channel-binding-tying-your-login-to-the-right-tls-connection-49id</guid>
      <description>&lt;p&gt;TLS proves you are talking to a server with a valid certificate. It does not prove that the login you perform inside that connection cannot be lifted out and replayed against a different connection. Channel binding closes that gap by stitching your authentication to the exact encrypted pipe it travels through, so a relay in the middle produces the wrong answer and gets rejected.&lt;/p&gt;

&lt;p&gt;Picture a machine sitting between you and a server: a corporate proxy, a captive portal, or a malicious endpoint you reached through a poisoned link. It terminates your TLS connection, so it can read everything you send, and it opens its own separate TLS connection onward to the real server. To you it looks like the server. To the server it looks like you. This is the classic authentication-relay setup, and plain password login walks straight into it: you send your credential, the machine forwards it, and now the attacker is authenticated as you.&lt;/p&gt;

&lt;p&gt;Certificate validation helps only if the attacker cannot present a certificate your client accepts. Sometimes it can, through a mis-issued cert, a proxy your device already trusts, or a user who clicks past a warning. Channel binding assumes that layer might fail and adds a second, independent check that does not depend on the attacker lacking a certificate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Idea
&lt;/h2&gt;

&lt;p&gt;Every TLS connection has values that are unique to that specific connection and known to both legitimate endpoints. Channel binding takes one of those values and folds it into the authentication computation. The client proves knowledge of its credential &lt;em&gt;and&lt;/em&gt; of the current channel's fingerprint, in a single bound step.&lt;/p&gt;

&lt;p&gt;Now walk the relay through it. You compute your authentication against the fingerprint of the channel between you and the attacker. The attacker cannot reuse that proof on its onward channel to the server, because that second channel has a different fingerprint. The relayed authentication no longer matches, and the server rejects it. The credential was never the weak point; the missing link was proof that the credential was presented over the same pipe the server is answering on.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Channel binding makes an authentication valid only over the exact TLS connection it was computed for, so credentials captured and relayed over a second connection fail to verify.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Three Binding Types, Three Fingerprints
&lt;/h2&gt;

&lt;p&gt;The interesting differences are in &lt;em&gt;which&lt;/em&gt; connection value gets used as the fingerprint. Three named types show up in practice.&lt;/p&gt;

&lt;h3&gt;
  
  
  tls-server-end-point
&lt;/h3&gt;

&lt;p&gt;The simplest binding, defined in RFC 5929, uses a hash of the server's TLS certificate as the fingerprint. It is easy to implement because both sides already have the certificate, and it survives session resumption. Its limit is conceptual: it binds to the certificate identity rather than to the live cryptographic session, so it protects you as long as the attacker cannot present the same certificate. That makes it a meaningful improvement over no binding and the most widely deployed option, used for example by SCRAM-SHA-256-PLUS in several databases.&lt;/p&gt;

&lt;h3&gt;
  
  
  tls-unique
&lt;/h3&gt;

&lt;p&gt;Also from RFC 5929, tls-unique uses the first TLS &lt;em&gt;Finished&lt;/em&gt; message as the fingerprint, a value derived from the full handshake and therefore tied to the actual session keys rather than just the certificate. It is a stronger binding in principle. In practice it carried a sharp edge: the 2014 Triple Handshake attack showed that under TLS 1.2 an attacker could arrange for two different connections to share the same Finished value unless the Extended Master Secret extension (RFC 7627) was in use. tls-unique is also not defined for TLS 1.3, whose handshake changed. It works, but only with care, and it is not the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  tls-exporter
&lt;/h3&gt;

&lt;p&gt;RFC 9266 defines tls-exporter, the modern binding built for TLS 1.3. Instead of reusing a handshake message, it asks TLS for a dedicated per-connection secret through the keying-material exporter interface (RFC 8446), using a label reserved for channel binding. The exporter produces a value unique to the connection and unavailable to a relay that holds a different session. It gives tls-unique's session-level strength without the Triple Handshake footgun, and it is the binding to reach for on TLS 1.3.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Binding type&lt;/th&gt;
&lt;th&gt;Fingerprint used&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;tls-server-end-point&lt;/td&gt;
&lt;td&gt;Hash of server certificate&lt;/td&gt;
&lt;td&gt;Simple, widely deployed, binds to cert identity rather than live session.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tls-unique&lt;/td&gt;
&lt;td&gt;First TLS Finished message&lt;/td&gt;
&lt;td&gt;Session-level, but needs Extended Master Secret under TLS 1.2 and is undefined for TLS 1.3.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tls-exporter&lt;/td&gt;
&lt;td&gt;TLS keying-material exporter (RFC 9266)&lt;/td&gt;
&lt;td&gt;The TLS 1.3 answer: per-connection secret, no Triple Handshake exposure.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Where Channel Binding Lives
&lt;/h2&gt;

&lt;p&gt;Channel binding is not a protocol on its own. It is a feature that authentication mechanisms opt into, and a few use it directly. SCRAM is the clearest example: its "-PLUS" variants require channel binding, and the mechanism carries a flag announcing whether binding is in use. That flag is itself protected inside the exchange, so an attacker who strips the binding to downgrade the client is detected rather than ignored. Kerberos and other GSS-API mechanisms support channel binding too, and it appears in enterprise database and directory authentication where relay through a proxy is a realistic worry.&lt;/p&gt;

&lt;p&gt;A related effort, Token Binding (RFC 8471 and its companions), tried to bind HTTP cookies and OAuth tokens to the underlying TLS connection so a stolen token could not be replayed elsewhere. It was cryptographically sound but saw little adoption, and major browsers dropped support. The idea lives on in the goal, if not that particular specification: tie the secret to the connection so theft of the secret alone is not enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Relates to Other MITM Defenses
&lt;/h2&gt;

&lt;p&gt;Channel binding is one of several answers to the man-in-the-middle problem, and it pairs with the others rather than replacing them.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Certificate pinning&lt;/strong&gt; narrows which certificates a client will accept, cutting off attackers who rely on a mis-issued or proxy certificate. Channel binding assumes that check might still be bypassed and adds an orthogonal one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mutual TLS&lt;/strong&gt; authenticates the client to the server at the TLS layer itself, which is a strong defense where you can deploy client certificates. Channel binding secures application-layer credentials like passwords that mTLS does not cover.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phishing-resistant login&lt;/strong&gt; such as WebAuthn ties the credential to the origin in the browser. Channel binding is the equivalent instinct one layer down, at the transport rather than the origin.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these defends against a user who hands over a one-time code to a convincing fake, which is why adversary-in-the-middle phishing remains a human problem as much as a protocol one. Channel binding raises the cost of the automated relay; it does not remove the need for phishing-resistant credentials and alert users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Encrypted Communication
&lt;/h2&gt;

&lt;p&gt;The lesson underneath channel binding is the one that shapes serious secure-messaging design: authenticating an endpoint and authenticating the channel to that endpoint are different guarantees, and assuming the first gives you the second is where real systems get broken. Binding a credential to its connection, binding a message key to its group state, binding identity to a verifiable key: each is a case of refusing to let a proof float free of the context that makes it meaningful.&lt;/p&gt;

&lt;p&gt;That instinct, tie the secret to the exact context it is meant for, is one that modern protocols like MLS apply throughout. When we build, we treat a proof that could be lifted and reused somewhere else as a bug, not a detail.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/channel-binding-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Secrets in Git History: Why Deleting the File Does Not Help</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Mon, 03 Aug 2026 12:28:49 +0000</pubDate>
      <link>https://dev.to/havenmessenger/secrets-in-git-history-why-deleting-the-file-does-not-help-1ke7</link>
      <guid>https://dev.to/havenmessenger/secrets-in-git-history-why-deleting-the-file-does-not-help-1ke7</guid>
      <description>&lt;p&gt;A config file with a live API key goes in at 11pm. Someone notices at 9am, deletes the file, commits the deletion, and the diff looks clean. The key is still there. Anyone who clones the repository can read it with one command, and that will remain true after every fix that feels like a fix.&lt;/p&gt;

&lt;p&gt;This is the most common credential-exposure route in software, and it is almost entirely a misunderstanding of one design decision. Git is not a file editor with undo. It is a content-addressed object store with an append-only log on top, and once content enters that store, removing it takes a deliberate operation that most people never run.&lt;/p&gt;

&lt;h2&gt;
  
  
  What git actually stores
&lt;/h2&gt;

&lt;p&gt;When you commit a file, git hashes its contents and writes a &lt;em&gt;blob&lt;/em&gt; object named by that hash. A &lt;em&gt;tree&lt;/em&gt; object records which filenames point at which blobs. A &lt;em&gt;commit&lt;/em&gt; object points at one tree, plus its parent commits. Every object is immutable, because its name is derived from its contents.&lt;/p&gt;

&lt;p&gt;Deleting the file writes a new tree that no longer mentions it, inside a new commit. The old commit still exists, still points at the old tree, which still points at the blob holding your key. Nothing was overwritten because nothing in git can be overwritten. Recovering it takes no forensics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;git log --all --full-history -- path/to/config&lt;/code&gt; lists every commit that touched the file, including the one that removed it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git show &amp;lt;commit&amp;gt;:path/to/config&lt;/code&gt; prints the contents as of that commit.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git log -p -S 'AKIA'&lt;/code&gt; searches history for commits where a given string was added or removed, which is how automated scanners work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Git is useful as an audit record because you can prove what a file contained at a given commit. A committed secret is durable for the same reason. It is a hash-linked history, and it is doing exactly what it was designed to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The measured scale of this
&lt;/h2&gt;

&lt;p&gt;A 2019 measurement study of public GitHub by researchers at North Carolina State University, presented at the Network and Distributed System Security Symposium, scanned a large sample of public repositories for high-confidence credential patterns. It found hundreds of thousands of API keys and private keys, and it found that they kept arriving daily rather than tapering off. A substantial share of what it found was still valid when the researchers re-checked later, meaning these were live credentials sitting in public.&lt;/p&gt;

&lt;p&gt;Attackers automate against the same public event stream, and cloud providers have reported credential abuse beginning within minutes of a public push. The window between "committed by accident" and "used by someone else" is not measured in days.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Once a credential has been pushed to a remote, the question that matters is what it can still do, and how fast you can make it do nothing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The order of operations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Rotate the credential first.&lt;/strong&gt; Issue a new one, deploy it, then revoke the old one at the provider. This is the only step that actually ends the exposure, because it makes the leaked bytes worthless regardless of who holds them. Everything else is cleanup of a copy you can no longer account for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then check what it did.&lt;/strong&gt; Pull the provider's access logs for the credential over its whole exposed lifetime, not just since you found it. The relevant period starts at the push, and the push may have been years ago.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then purge, if the value itself is sensitive.&lt;/strong&gt; A rotated API key is a dead string and purging it is tidiness. A customer database dump, a private key that also protects something else, or personal data committed by mistake are different, because the value stays sensitive after the credential is revoked.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a history rewrite reaches, and what it misses
&lt;/h2&gt;

&lt;p&gt;The current tool for this is &lt;code&gt;git filter-repo&lt;/code&gt;. Git's own documentation now steers people away from &lt;code&gt;filter-branch&lt;/code&gt;, which is slow and easy to get subtly wrong. The &lt;code&gt;BFG Repo-Cleaner&lt;/code&gt; is a well-established alternative that trades flexibility for speed on the common case.&lt;/p&gt;

&lt;p&gt;Rewriting produces new commit hashes for everything downstream of the change, which is why it requires a force push and coordination with everyone working on the repository. That is the visible cost. The invisible cost is the set of places the rewrite does not reach.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Where the old object survives&lt;/th&gt;
&lt;th&gt;What clears it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Your own local repository, via reflog and existing packfiles&lt;/td&gt;
&lt;td&gt;Expiring the reflog and running garbage collection with pruning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Every clone anyone already made&lt;/td&gt;
&lt;td&gt;Nothing you control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forks on the hosting platform, which often share an object store with the source&lt;/td&gt;
&lt;td&gt;Platform support, per their documented process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cached web views of the old commit, reachable by its hash&lt;/td&gt;
&lt;td&gt;Platform support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Continuous integration logs and build artifacts&lt;/td&gt;
&lt;td&gt;Log retention settings, deleted per run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mirrors, backups, package caches, local developer machines&lt;/td&gt;
&lt;td&gt;Whatever process created them&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On the major hosting platforms, a commit that is no longer referenced by any branch can still be fetched by its full hash until it is garbage collected, and the platforms document a support process for removing cached views. Plan for that step rather than discovering it, and note that it is a request to a third party rather than something you execute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The practical test:&lt;/strong&gt; after a purge, clone the repository fresh into a new directory and search it. If your scanner is clean on a fresh clone but you never rotated the credential, the exposure is unresolved and now harder to see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where secrets hide besides config files
&lt;/h2&gt;

&lt;p&gt;Most tooling scans file contents at the current commit, which is the narrowest possible view. The recurring surprises are elsewhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Commit messages and pull request descriptions.&lt;/strong&gt; A pasted token in a commit message is not in any blob, so file-content scanners miss it entirely, and it is fully public.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test fixtures and example files.&lt;/strong&gt; A "sample" credential is very often a real one that was working when the test was written.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notebooks.&lt;/strong&gt; Output cells store whatever was printed, including an environment dump.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI configuration.&lt;/strong&gt; A workflow file that echoes a variable for debugging writes it into a public build log.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container image layers.&lt;/strong&gt; A secret copied in and deleted in a later layer stays in the earlier layer, which is the same failure with a different object store.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lockfiles and generated config.&lt;/strong&gt; Tokens embedded in registry URLs are easy to generate and easy to overlook.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Preventing the next one
&lt;/h2&gt;

&lt;p&gt;Detection tools are worth running, and it is worth being clear about what they are. &lt;code&gt;gitleaks&lt;/code&gt; and &lt;code&gt;trufflehog&lt;/code&gt; match known credential formats and entropy patterns, and hosted secret scanning does the same at push time, with some providers automatically notifying the credential's issuer so it can be revoked. All of these catch the shapes they know. A password in a YAML field named &lt;code&gt;db_pass&lt;/code&gt; matches nothing in particular.&lt;/p&gt;

&lt;p&gt;The structural changes do more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep plaintext secrets out of the working tree at all.&lt;/strong&gt; Read them from the environment or a secrets manager at runtime, so there is nothing to accidentally stage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If configuration must live in the repository, commit it encrypted.&lt;/strong&gt; Tools that encrypt values in place, leaving the structure readable, mean a leaked file is ciphertext and the exposure is the key rather than the repository.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make the check a gate rather than a habit.&lt;/strong&gt; A pre-commit hook that refuses the commit is the only version of this that survives a busy week, and a server-side check backs it up when a hook was never installed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope credentials tightly and rotate them on a schedule.&lt;/strong&gt; A key that can only read one bucket and expires in a month is a smaller incident than one that can do anything indefinitely.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One more habit is worth calling out. When a leak is found, people frequently rewrite history quietly and say nothing, because the diff looks clean afterwards and nothing appears to have happened. The credential was public for the whole window regardless, and the provider's access logs are the only thing that can say whether anyone used it. The same point applies to deleting a file from a disk: removing your copy says nothing about whose hands it passed through first.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/git-history-secret-leaks/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>git</category>
      <category>devops</category>
      <category>programming</category>
    </item>
    <item>
      <title>Perceptual Hashing: Matching Images That Are Not Identical</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Sun, 02 Aug 2026 12:22:05 +0000</pubDate>
      <link>https://dev.to/havenmessenger/perceptual-hashing-matching-images-that-are-not-identical-524e</link>
      <guid>https://dev.to/havenmessenger/perceptual-hashing-matching-images-that-are-not-identical-524e</guid>
      <description>&lt;p&gt;Every property that makes SHA-256 useful comes from one behaviour: flip a single bit of input and the entire output changes. Perceptual hashing is built to do the reverse. Change the input a little and the output should barely move, so that two versions of the same photograph land in the same place. That inversion is the whole idea, and it is also where every attack comes from.&lt;/p&gt;

&lt;p&gt;A platform that wants to detect a known image cannot compare files. Re-saving a JPEG at a different quality setting changes millions of bytes and produces a completely different &lt;a href="https://havenmessenger.com/blog/posts/blake3-hash-function/" rel="noopener noreferrer"&gt;cryptographic hash&lt;/a&gt;, and a user who crops fifteen pixels off the bottom defeats byte comparison entirely. Storing the images themselves to compare against is worse: it means keeping a library of exactly the material that must not be kept.&lt;/p&gt;

&lt;p&gt;Perceptual hashing is the answer the industry arrived at. Reduce an image to a short fingerprint that captures its visual structure and discards everything else, then compare fingerprints. Two images that look the same to a person produce fingerprints a small distance apart, even when no two bytes of the files agree.&lt;/p&gt;

&lt;h2&gt;
  
  
  How a basic perceptual hash is computed
&lt;/h2&gt;

&lt;p&gt;The classic constructions are simple enough to implement in an afternoon, which is a good way to build intuition for the whole family.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Average hash&lt;/strong&gt; is the simplest. Convert to greyscale, resize to 8 by 8 pixels, compute the mean brightness of those 64 values, then emit one bit per pixel: 1 if the pixel is above the mean, 0 if below. The result is a 64-bit fingerprint. Resizing throws away resolution, detail, and compression artefacts. What survives is the coarse light and dark structure of the picture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Difference hash&lt;/strong&gt; is a variation with better behaviour. Resize to 9 by 8, then emit a bit for each adjacent horizontal pair: 1 if the left pixel is brighter than the right. It encodes gradients rather than absolute levels, so it is unbothered by a global brightness or contrast change.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;pHash&lt;/strong&gt; applies a discrete cosine transform to a larger greyscale version and keeps only the low-frequency coefficients, discarding the top-left DC term. Low frequencies carry overall composition; high frequencies carry noise, sharpening and compression artefacts. Keeping the former and dropping the latter is exactly the robustness property wanted.&lt;/p&gt;

&lt;p&gt;Comparison is Hamming distance, the count of differing bits. Identical images give 0. Re-encoded and slightly resized versions of the same image typically land within a handful of bits. Unrelated images cluster near 32 out of 64, which is what you expect from two roughly random bit strings.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The threshold is the entire policy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Everything a matching system will ever do right or wrong is decided by one number: the Hamming distance below which two fingerprints are declared the same image. Set it low and edited copies escape. Set it high and unrelated pictures start colliding. There is no setting that avoids both, only a choice about which error you would rather have.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What gets deployed in practice
&lt;/h2&gt;

&lt;p&gt;Production systems are considerably more sophisticated than a DCT over an 8 by 8 thumbnail, and they diverge in one important way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PhotoDNA&lt;/strong&gt;, developed at Microsoft with Dartmouth researcher Hany Farid around 2009, is the long-standing tool for detecting known child sexual abuse material. It converts an image to greyscale, divides it into a grid, and derives a signature from intensity gradients in each cell. It is robust to resizing, re-encoding and moderate alteration. It is licensed rather than published, and the algorithm is not public, which is a deliberate choice: an attacker who knows the transform can design around it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NeuralHash&lt;/strong&gt; was Apple's 2021 proposal, and it took the opposite structural approach. A convolutional neural network mapped an image to a descriptor, which was then quantised via a hashing step into a short code. The intent was greater robustness to transformations than a hand-designed transform could achieve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Video and audio&lt;/strong&gt; use the same idea on different signals. Video systems typically hash sampled frames and match on sequences; audio fingerprinting extracts time and frequency peaks, which is how a phone identifies a song from ten seconds of a noisy recording.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two attacks, and why both are inherent
&lt;/h2&gt;

&lt;p&gt;A perceptual hash is a lossy, continuous-ish function whose whole purpose is to be smooth. Smooth functions can be optimised against. That gives an adversary two directions, and they are opposites.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attack&lt;/th&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Who benefits&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Evasion&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Alter a known image so its hash moves past the threshold, while it still looks the same to a human.&lt;/td&gt;
&lt;td&gt;Whoever is distributing the material the system exists to catch.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Collision&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Alter an innocuous image so its hash matches a known-bad entry, while it still looks innocuous.&lt;/td&gt;
&lt;td&gt;Whoever wants a target flagged, investigated, or their account frozen.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Within days of NeuralHash being found in shipping iOS builds in August 2021, researchers extracted the model, published it, and demonstrated both. Collisions were generated between visually unrelated images, and near-imperceptible perturbations moved a matching image out of range. None of this was surprising to anyone who works on adversarial examples. It is the standard result for any differentiable function with a public model: gradients point at the answer.&lt;/p&gt;

&lt;p&gt;That is the case against publishing the algorithm. The case for publishing is that a system nobody can test is a system whose error rate is whatever its operator says it is. Apple &lt;a href="https://havenmessenger.com/blog/posts/client-side-scanning-explained/" rel="noopener noreferrer"&gt;shelved the client-side scanning plan&lt;/a&gt; in December 2022, and the demonstrations were part of why.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keeping the transform secret does not remove the vulnerability. It removes the ability of anyone outside the operator to measure it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The false positive problem is arithmetic
&lt;/h2&gt;

&lt;p&gt;Suppose a matcher is genuinely accurate: a one in ten million chance that an unrelated image is flagged. That sounds close enough to zero to ignore.&lt;/p&gt;

&lt;p&gt;A large platform processes several billion image uploads per day. At one in ten million, that is hundreds of false matches every day, each of which is a real person whose private photograph has been routed to a human reviewer, and possibly to a report. The rate is excellent. The absolute number is a queue with people in it.&lt;/p&gt;

&lt;p&gt;This is base-rate arithmetic and it is not a criticism of any particular algorithm. It is the reason well-designed deployments require multiple independent matches before escalating, and the reason human review sits between a match and any consequence. It is also the reason "the false positive rate is negligible" is an incomplete sentence. Negligible against what denominator, and what happens to the person on the wrong side of it?&lt;/p&gt;

&lt;h2&gt;
  
  
  The privacy question the primitive raises
&lt;/h2&gt;

&lt;p&gt;Perceptual hashing is often introduced as privacy-preserving, on the grounds that a hash is not an image. Two things complicate that.&lt;/p&gt;

&lt;p&gt;First, a perceptual hash is a lossy but real description of the picture. It is a low-resolution structural summary, and research has shown that approximate images can be reconstructed from some perceptual hash schemes. A cryptographic hash reveals nothing about its input by design; a perceptual hash reveals visual structure by design. Treating the two as equivalent for disclosure purposes is a category error.&lt;/p&gt;

&lt;p&gt;Second, and more consequentially, the matching database is a list of hashes and nothing more. Whether an entry corresponds to abuse material, a leaked document, a protest banner, or a meme critical of a government is not visible from the entry, and not visible to the client doing the matching. The technical mechanism is indifferent to what is on the list. Every property that makes it good at one task makes it equally good at the others, and the only thing standing between the two is governance.&lt;/p&gt;

&lt;p&gt;That is the argument that has driven a decade of debate about scanning on the device rather than on the server, and it is not a technical dispute. Everyone involved agrees about how the matching works.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to take from this
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A perceptual hash is not a cryptographic hash&lt;/strong&gt; and the two have opposite design goals. Do not reason about one using intuitions from the other, particularly around &lt;a href="https://havenmessenger.com/blog/posts/hash-collision-attacks-explained/" rel="noopener noreferrer"&gt;collisions&lt;/a&gt;, which are a defect in one and an unavoidable feature of the other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The threshold is a policy decision wearing a technical costume.&lt;/strong&gt; Ask what it is set to and who chose it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Both attack directions are inherent to the primitive.&lt;/strong&gt; Secrecy about the algorithm changes who can find them first, not whether they exist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A tiny error rate at planetary scale is a large number of people.&lt;/strong&gt; Ask about the denominator and about what a match triggers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The list is the system.&lt;/strong&gt; The matcher enforces whatever it is given, and cannot tell you what that is.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Haven does not perform content matching on messages, which is a consequence of the architecture rather than a policy we could revise: end-to-end encrypted content is not available to the server to match against. That places the whole class of questions above outside what we can do, which is the point of the design and also a real cost of it. A system that cannot scan for the worst material also cannot be quietly repurposed to scan for anything else, and both halves of that sentence are true at once.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/perceptual-hashing-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Hash Collisions in Practice: Identical Prefix, Chosen Prefix, and What Broke</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Sat, 01 Aug 2026 12:21:27 +0000</pubDate>
      <link>https://dev.to/havenmessenger/hash-collisions-in-practice-identical-prefix-chosen-prefix-and-what-broke-3fc0</link>
      <guid>https://dev.to/havenmessenger/hash-collisions-in-practice-identical-prefix-chosen-prefix-and-what-broke-3fc0</guid>
      <description>&lt;p&gt;MD5 was publicly broken in 2004. Certificate authorities were still signing with it in 2008, and a piece of state-linked malware used it to forge a Microsoft code-signing certificate in 2012. The gap between "broken" and "exploited" was not inertia. It was a specific technical requirement that took four more years to satisfy.&lt;/p&gt;

&lt;p&gt;A cryptographic hash function takes input of any length and produces a fixed-length digest. Three properties are usually asked of it. &lt;strong&gt;Preimage resistance&lt;/strong&gt;: given a digest, you cannot find an input that produces it. &lt;strong&gt;Second preimage resistance&lt;/strong&gt;: given one input, you cannot find a different input with the same digest. &lt;strong&gt;Collision resistance&lt;/strong&gt;: you cannot find &lt;em&gt;any&lt;/em&gt; two inputs that produce the same digest.&lt;/p&gt;

&lt;p&gt;The third is the weakest requirement, and it is the one that falls first. It is also the one people misread, because a collision is not an attack on a document that already exists. The attacker produces both halves.&lt;/p&gt;

&lt;h2&gt;
  
  
  The birthday bound sets the ceiling
&lt;/h2&gt;

&lt;p&gt;For an &lt;em&gt;n&lt;/em&gt;-bit digest, finding a collision by brute force takes about 2^n/2 attempts rather than 2^n, because you are looking for any matching pair rather than a match to a specific target. The reasoning is the same as the party-of-23 birthday problem. Twenty-three people is enough for a coincidence between any two of them, while matching &lt;em&gt;your&lt;/em&gt; birthday specifically needs a much larger room.&lt;/p&gt;

&lt;p&gt;That halving is why digest length is quoted at twice the security level anyone wants. A 128-bit digest gives 64 bits of collision resistance, which was already uncomfortable by the late 1990s and is trivially reachable now. This is the generic bound, achievable against any hash function whatsoever. A break means finding collisions faster than that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identical prefix and why it stayed academic
&lt;/h2&gt;

&lt;p&gt;Wang and Yu published practical MD5 collisions in 2004. The output was two blocks of essentially random-looking bytes with the same digest. That form of result is an &lt;strong&gt;identical-prefix collision&lt;/strong&gt;: both documents share whatever came before the colliding blocks, then differ, and the attacker controls very little about what the differing parts say.&lt;/p&gt;

&lt;p&gt;To weaponise that, you need a file format that tolerates a chunk of unreadable bytes and lets its visible content depend on them. It can be done. It is fiddly, it constrains the attacker to formats with the right structure, and it always begins with the same shared prefix, which means the attacker has to author both documents from a common starting point.&lt;/p&gt;

&lt;p&gt;Nobody is forging a signature on a contract that already exists with an identical-prefix collision. That is why MD5 remained in production for years after 2004. Practitioners could read the papers and correctly conclude that the demonstrated attack did not reach their deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chosen prefix is the one that matters
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;chosen-prefix collision&lt;/strong&gt; removes the shared-beginning constraint. The attacker starts with two arbitrary, different prefixes, then computes a pair of suffixes such that the two complete files hash to the same value. Now one document can be a legitimate certificate request for a domain you own, and the other can be a certificate authority certificate for a name you do not.&lt;/p&gt;

&lt;p&gt;Stevens, Lenstra and de Weger published chosen-prefix MD5 collisions in 2007. In December 2008, a team including Stevens, Sotirov, Appelbaum, Lenstra, Molnar, Osvik and de Weger demonstrated the consequence: they obtained a legitimate certificate from a CA still signing with MD5, and produced a colliding intermediate CA certificate carrying the same signature. The computation ran on a cluster of roughly 200 PlayStation 3 consoles. The result was a certificate authority whose signature browsers would accept, created by someone who was not a certificate authority.&lt;/p&gt;

&lt;p&gt;Four years later the same primitive turned up in the wild. The Flame malware, found in 2012, carried a forged Microsoft code-signing certificate produced with a chosen-prefix MD5 collision against a Terminal Server licensing certificate. That let it present itself as a Windows Update package. Whoever built it had done cryptanalytic work that had not appeared in public.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The distinction to keep&lt;/strong&gt; Identical prefix: the attacker writes two documents from a common start and can produce a pair that collide. Chosen prefix: the attacker starts from two documents that are already different and makes them collide. The first is a curiosity in most deployments. The second forges credentials.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  SHA-1 followed the same arc, ten years later
&lt;/h2&gt;

&lt;p&gt;Theoretical attacks on SHA-1 appeared in 2005, well below the 2^80 generic bound. Migration advice followed, and NIST deprecated SHA-1 for digital signature generation after 2013. Deployment moved slowly, as it does.&lt;/p&gt;

&lt;p&gt;In February 2017, CWI Amsterdam and Google published SHAttered, the first practical identical-prefix SHA-1 collision: two PDF files with different visible content and the same digest. The published cost was roughly 2^63.1 SHA-1 computations, which the authors described as around 6,500 CPU-years and 110 GPU-years of work.&lt;/p&gt;

&lt;p&gt;In January 2020, Leurent and Peyrin published the chosen-prefix version, under the name SHAmbles, at an estimated rental cost in the region of 45,000 US dollars. They demonstrated it against the &lt;a href="https://havenmessenger.com/blog/posts/pgp-web-of-trust-explained/" rel="noopener noreferrer"&gt;PGP web of trust&lt;/a&gt;, constructing a case where a certification signature made over one identity appeared valid over another. That is the same shape as the 2008 certificate result, in a different trust system, at a price any moderately funded adversary can pay.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Digest&lt;/th&gt;
&lt;th&gt;Collision status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;MD5&lt;/td&gt;
&lt;td&gt;128-bit&lt;/td&gt;
&lt;td&gt;Chosen-prefix collisions in seconds on a laptop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHA-1&lt;/td&gt;
&lt;td&gt;160-bit&lt;/td&gt;
&lt;td&gt;Chosen-prefix collisions at rentable cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SHA-256&lt;/td&gt;
&lt;td&gt;256-bit&lt;/td&gt;
&lt;td&gt;No practical attack; length-extension applies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://havenmessenger.com/blog/posts/sha3-keccak-sponge-explained/" rel="noopener noreferrer"&gt;SHA-3&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;256-bit and up&lt;/td&gt;
&lt;td&gt;No practical attack; sponge construction, no length extension&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://havenmessenger.com/blog/posts/blake3-hash-function/" rel="noopener noreferrer"&gt;BLAKE3&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;256-bit default&lt;/td&gt;
&lt;td&gt;No practical attack; tree mode, no length extension&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Where SHA-1 still lives, and why some of it is fine
&lt;/h2&gt;

&lt;p&gt;Git identifies every object by SHA-1. Two colliding objects would be indistinguishable to the repository, which is a real integrity concern for &lt;a href="https://havenmessenger.com/blog/posts/git-commit-signing-explained/" rel="noopener noreferrer"&gt;signed commits&lt;/a&gt; and for supply-chain provenance generally. The response after SHAttered was to adopt a hardened variant, developed by Stevens and Shumow, which detects the structural signature of a collision attempt during hashing and refuses. A SHA-256 object format exists and adoption has been slow, for the compatibility reasons that make any identifier change slow.&lt;/p&gt;

&lt;p&gt;Elsewhere, SHA-1 appears in constructions where collision resistance is not the property being relied on. HMAC-SHA-1 is the clearest case: HMAC's security argument does not require the underlying hash to be collision resistant, which is why HMAC-SHA-1 has not fallen alongside SHA-1 signatures, and why the default algorithm in &lt;a href="https://havenmessenger.com/blog/posts/totp-authenticator-apps-explained/" rel="noopener noreferrer"&gt;TOTP authenticator apps&lt;/a&gt; remains sound. The same reasoning applies to several key-derivation uses.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This hash is broken" and "this use of the hash is broken" are different claims. Which property the construction depends on decides which one applies.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That nuance is not a licence to keep it. New designs should not reach for SHA-1 anywhere, if only because auditors, scanners and procurement teams cannot evaluate the distinction at scale, and because NIST has set an end date: SHA-1 is to be phased out of federal use by the end of 2030.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this history suggests about the next migration
&lt;/h2&gt;

&lt;p&gt;The pattern is consistent across both functions. Theory arrives first and is correctly judged non-urgent. The identical-prefix demonstration arrives and is correctly judged to be a narrow threat. The chosen-prefix demonstration arrives and everything is suddenly urgent, at which point the migration takes years because identifiers are embedded in formats, protocols and databases that were never designed to change them.&lt;/p&gt;

&lt;p&gt;The functions we now depend on will follow some version of that curve. This is the argument for &lt;a href="https://havenmessenger.com/blog/posts/cryptographic-agility-explained/" rel="noopener noreferrer"&gt;cryptographic agility&lt;/a&gt;: a system that names its algorithms explicitly, versions its formats, and can accept a second algorithm alongside the first is one that migrates in a release cycle rather than a decade. Systems that hardcode digest lengths into wire formats and storage schemas are the ones still running SHA-1 in 2030.&lt;/p&gt;

&lt;p&gt;The same reasoning drives the current &lt;a href="https://havenmessenger.com/blog/posts/post-quantum-cryptography/" rel="noopener noreferrer"&gt;post-quantum migration&lt;/a&gt;, where the warning arrived well before the capability. Whether an organisation uses that lead time is a design decision made long before the attack is announced.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/hash-collision-attacks-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>IKEv2 and IPsec: The VPN Already Built Into Your Phone</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Fri, 31 Jul 2026 12:22:25 +0000</pubDate>
      <link>https://dev.to/havenmessenger/ikev2-and-ipsec-the-vpn-already-built-into-your-phone-5mo</link>
      <guid>https://dev.to/havenmessenger/ikev2-and-ipsec-the-vpn-already-built-into-your-phone-5mo</guid>
      <description>&lt;p&gt;Open the VPN settings on an iPhone or an Android handset with no VPN app installed and there is already a protocol option waiting for you: IKEv2. It is the tunnel your employer's laptop probably uses, the one your carrier uses to carry Wi-Fi calls, and the one almost nobody writes about because it does not have a marketing department.&lt;/p&gt;

&lt;p&gt;The name is confusing before you start, because two protocols share the job and people use the words interchangeably. IPsec is the part that carries data. IKEv2 is the part that agrees on keys. They are specified separately, implemented in different places, and fail in different ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data plane: ESP
&lt;/h2&gt;

&lt;p&gt;IPsec offers two packet formats. AH, the Authentication Header (RFC 4302), authenticates a packet without encrypting it. ESP, Encapsulating Security Payload (RFC 4303), authenticates and encrypts. In practice essentially every deployment uses ESP alone, because a tunnel that proves authenticity while publishing the contents is a narrow product.&lt;/p&gt;

&lt;p&gt;ESP runs in one of two modes. In &lt;strong&gt;transport mode&lt;/strong&gt; the original IP header stays visible and only the payload is protected, which suits two hosts talking directly. In &lt;strong&gt;tunnel mode&lt;/strong&gt; the entire original packet, header included, is encrypted and wrapped in a new one addressed to the gateway. Tunnel mode is what people mean by a VPN: the outer header says "traffic between my phone and the gateway" and the inner one, which nobody on the path can read, says where the traffic is really going.&lt;/p&gt;

&lt;p&gt;A crucial detail for anyone reasoning about metadata: the outer header is not protected and cannot be. Routers need it. So an observer on the café Wi-Fi learns that your device is speaking IPsec to a particular gateway address, plus packet sizes and timing, which is the same residual exposure every tunnel leaves. This is worth keeping in view when reading &lt;a href="https://havenmessenger.com/blog/posts/vpn-limitations/" rel="noopener noreferrer"&gt;what a VPN does and does not do&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The control plane: two round trips
&lt;/h2&gt;

&lt;p&gt;IKEv2 (RFC 7296) is the negotiation that produces the keys ESP uses. It is deliberately compact. A working tunnel takes two exchanges.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IKE_SA_INIT&lt;/strong&gt; is the first. Both sides send a Diffie-Hellman public value, a nonce, and their supported algorithms. At the end of this exchange they share a secret and can encrypt, but neither knows who the other is. Everything in this exchange travels in the clear, which is why the identities are not in it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IKE_AUTH&lt;/strong&gt; is the second, and it is encrypted under the keys just derived. Each side sends its identity and proves it, then negotiates the first Child SA, which is the actual ESP tunnel that will carry traffic. Authentication can be a certificate signature, a pre-shared key, or EAP, which is how enterprise deployments hand off to an existing directory or a token, and how a phone can authenticate with a username and a certificate at the same time.&lt;/p&gt;

&lt;p&gt;That ordering is a real design property and not an accident. Because identities move only after the unauthenticated key exchange completes, a passive observer does not learn who is connecting. It gives IKEv2 identity protection that early IPsec key exchange lacked.&lt;/p&gt;

&lt;p&gt;Later, &lt;strong&gt;CREATE_CHILD_SA&lt;/strong&gt; handles rekeying and additional tunnels. If the configuration enables it, a rekey performs a fresh &lt;a href="https://havenmessenger.com/blog/posts/diffie-hellman-key-exchange-explained/" rel="noopener noreferrer"&gt;Diffie-Hellman exchange&lt;/a&gt; rather than deriving new keys from the old secret, which is what gives the tunnel &lt;a href="https://havenmessenger.com/blog/posts/forward-secrecy-explained/" rel="noopener noreferrer"&gt;forward secrecy&lt;/a&gt; across its own lifetime. Compromising today's key material does not retroactively open last week's captured traffic.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Worth checking in your config&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Forward secrecy on rekey is an option, not a default in every implementation. Look for the PFS or "DH group" setting in the child SA proposal. If it is absent, rekeys derive from the existing secret and a single key compromise reaches back over the whole session.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why it holds up on a phone
&lt;/h2&gt;

&lt;p&gt;Two extensions explain why mobile operating systems settled on IKEv2 rather than something newer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NAT traversal.&lt;/strong&gt; ESP is its own IP protocol number, and home routers and carrier NATs frequently mishandle anything that is not TCP or UDP. IKEv2 detects a NAT on the path during IKE_SA_INIT and moves the whole conversation to UDP port 4500, encapsulating ESP inside UDP (RFC 3948). Without this, IPsec would be unusable on most consumer networks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MOBIKE&lt;/strong&gt; (RFC 4555) lets an established tunnel change its outer addresses without renegotiating. When your phone walks out of the building and drops from Wi-Fi to cellular, the IP address changes but the security association survives: the client tells the gateway the new address over the existing encrypted channel, and traffic continues. Your SSH session does not die. This is the same machinery that keeps &lt;a href="https://havenmessenger.com/blog/posts/wifi-calling-privacy/" rel="noopener noreferrer"&gt;Wi-Fi Calling&lt;/a&gt; attached to a carrier gateway as you move.&lt;/p&gt;

&lt;h2&gt;
  
  
  Against WireGuard
&lt;/h2&gt;

&lt;p&gt;The obvious comparison is &lt;a href="https://havenmessenger.com/blog/posts/wireguard-vs-openvpn/" rel="noopener noreferrer"&gt;WireGuard&lt;/a&gt;, which is the protocol most privacy-focused providers now lead with.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;IKEv2 / IPsec&lt;/th&gt;
&lt;th&gt;WireGuard&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Algorithm choice&lt;/td&gt;
&lt;td&gt;Negotiated, wide menu&lt;/td&gt;
&lt;td&gt;Fixed set, no negotiation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codebase size&lt;/td&gt;
&lt;td&gt;Large; many years of accumulated options&lt;/td&gt;
&lt;td&gt;Small enough to read in an afternoon&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Misconfiguration risk&lt;/td&gt;
&lt;td&gt;Real; weak proposals are still expressible&lt;/td&gt;
&lt;td&gt;Low; there is little to get wrong&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise authentication&lt;/td&gt;
&lt;td&gt;Certificates, EAP, directory integration&lt;/td&gt;
&lt;td&gt;Static public keys, external tooling needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Network roaming&lt;/td&gt;
&lt;td&gt;MOBIKE&lt;/td&gt;
&lt;td&gt;Endpoint updates on any authenticated packet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Built into stock iOS and Android&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;App required&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The negotiation row is where the real trade-off sits. Algorithm agility is why IKEv2 can adopt a new primitive without a new protocol, and it is also why a deployment can be configured into weakness while every component reports success. WireGuard removed the choice deliberately and accepted that upgrading means a new version.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Diffie-Hellman group problem
&lt;/h2&gt;

&lt;p&gt;The most instructive failure in IPsec's history is a configuration default rather than a broken algorithm. In 2015 the Logjam paper, by Adrian and colleagues, examined how much of the internet performed Diffie-Hellman over a small number of standardised 1024-bit groups. Because the expensive part of the relevant attack depends on the group rather than on the individual connection, an adversary who invested once in precomputation against a widely used group could then break many individual exchanges cheaply.&lt;/p&gt;

&lt;p&gt;The authors noted that IKE was a particularly good fit for this, since a handful of groups were baked into standards and reused nearly everywhere, and argued that it offered a plausible explanation for reports of large-scale VPN decryption capability. The practical response was straightforward: stop using 1024-bit groups, prefer 2048-bit or larger, and prefer elliptic curve groups where available. Any IKEv2 configuration you inherit is worth auditing for exactly this.&lt;/p&gt;

&lt;p&gt;The forward-looking version of the same concern is quantum. Two extensions exist: RFC 8784 mixes a post-quantum pre-shared key into IKEv2's key derivation so that a recorded session cannot be opened later by breaking the Diffie-Hellman alone, and RFC 9370 allows multiple key exchanges to be combined in one negotiation, which is the same hybrid strategy now being deployed in &lt;a href="https://havenmessenger.com/blog/posts/hybrid-post-quantum-tls-key-exchange/" rel="noopener noreferrer"&gt;TLS&lt;/a&gt;. Support varies by implementation, so it is a question to ask rather than an assumption to make.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it fits
&lt;/h2&gt;

&lt;p&gt;IKEv2 is an old protocol that aged unusually well, mostly because IKEv2 in 2005 was a deliberate simplification of a first version that had grown unmanageable. It is the right answer when you need certificate or directory-backed authentication, when you need the tunnel to survive a network change, or when you cannot install software on the endpoint. WireGuard is the better answer when you control both ends and want the smallest thing that works.&lt;/p&gt;

&lt;p&gt;Neither changes what the tunnel is for. A VPN moves the point at which your traffic joins the open internet, and it moves your trust to whoever runs the far end. That is a useful thing to move, and it is not the same as end-to-end encryption of the content, which stays the job of the application. For the difference between the two, &lt;a href="https://havenmessenger.com/blog/posts/what-e2e-encryption-protects/" rel="noopener noreferrer"&gt;what end-to-end encryption actually protects&lt;/a&gt; is the shorter read.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/ipsec-ikev2-explained/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>encryption</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Carrier-Grade NAT: Why Your IP Address Is Not Yours</title>
      <dc:creator>Haven Messenger</dc:creator>
      <pubDate>Thu, 30 Jul 2026 12:22:30 +0000</pubDate>
      <link>https://dev.to/havenmessenger/carrier-grade-nat-why-your-ip-address-is-not-yours-2kjd</link>
      <guid>https://dev.to/havenmessenger/carrier-grade-nat-why-your-ip-address-is-not-yours-2kjd</guid>
      <description>&lt;p&gt;A request arrives at an ISP naming an IP address and a moment in time. Fifteen years ago that pair identified one subscriber line. Today, for a large fraction of mobile and fixed customers, it identifies a pool of several hundred people who were all using that address simultaneously, and the ISP may have kept nothing that narrows it further.&lt;/p&gt;

&lt;p&gt;The mechanism is carrier-grade NAT, also written CGNAT or large-scale NAT. It is the same translation your home router performs, moved up one level so that the carrier does it on behalf of many customers at once. Your router already hides a dozen devices behind one address. CGNAT hides a neighbourhood behind one address.&lt;/p&gt;

&lt;p&gt;This is a deployment detail with consequences well outside networking. It quietly changed what an IP address means as evidence, it breaks a category of software that assumed one address meant one household, and it created a logging problem that carriers and law enforcement have been arguing about for over a decade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why carriers ran out of addresses to hand out
&lt;/h2&gt;

&lt;p&gt;IPv4 addresses are 32 bits, which caps the total at roughly 4.3 billion, minus large reserved ranges. IANA handed out the last of its free blocks to the regional registries in February 2011. RIPE NCC, covering Europe and the Middle East, reached its final block in 2012 and declared full exhaustion in 2019. Mobile networks in particular grew past the point where a public address per subscriber was arithmetically possible.&lt;/p&gt;

&lt;p&gt;The workaround was to give subscribers an address from a private range and translate at the carrier's edge. This needed its own address block, because reusing &lt;code&gt;192.168.0.0/16&lt;/code&gt; or &lt;code&gt;10.0.0.0/8&lt;/code&gt; would collide with the customer's own LAN. RFC 6598 set aside &lt;code&gt;100.64.0.0/10&lt;/code&gt; as Shared Address Space for exactly this purpose. If your router's WAN interface holds an address in that range, you are behind a carrier NAT right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it breaks for you
&lt;/h2&gt;

&lt;p&gt;The first casualty is inbound connections. There is no port to forward, because the port on the public address is not yours and can be reassigned. Self-hosting anything at home, running a game server, or accepting a direct file transfer all stop working. Some carriers sell a static address or an opt-out as an add-on, which is the clearest signal of what has actually been taken away.&lt;/p&gt;

&lt;p&gt;Peer-to-peer protocols degrade rather than fail. Two parties behind separate carrier NATs cannot always establish a direct path, so they fall back to a relay, which means a third party carries the traffic and can see its volume and timing even when it cannot read it. Anything built on WebRTC hits this constantly, which is why &lt;a href="https://havenmessenger.com/blog/posts/webrtc-ip-leaks/" rel="noopener noreferrer"&gt;TURN relays&lt;/a&gt; exist.&lt;/p&gt;

&lt;p&gt;The consequence people actually notice is shared reputation. When one person behind your address gets the address blocked, everyone behind it inherits the block. That is the source of the endless CAPTCHA, the mail server rejection, the forum ban you did not earn, the Wikipedia edit block on a whole mobile carrier. A blocklist entry that was written against a person now lands on a few hundred strangers.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it breaks for attribution
&lt;/h2&gt;

&lt;p&gt;To resolve an address back to a subscriber behind a carrier NAT you need three things: the public address, the exact time, and &lt;strong&gt;the source port&lt;/strong&gt;. Without the port, the translation table cannot be reversed, because the port is the only field that distinguishes one customer's session from another's.&lt;/p&gt;

&lt;p&gt;RFC 6302 asks internet-facing servers to log the source port alongside an accurate UTC timestamp for precisely this reason. Most server software still does not, by default. So a large amount of retained log data is now unresolvable in principle: it names an address that hundreds of people were sharing, and the field that would have separated them was never recorded.&lt;/p&gt;

&lt;p&gt;RFC 6888 sets out the requirements for carrier NAT deployments, including the expectation that translations can be logged, and acknowledges the volume problem that creates. A busy gateway produces a record per connection, and a phone browsing the web opens a great many connections. Europol has named carrier-grade NAT as an obstacle to attribution in its public cybercrime assessments and has argued for either mandatory logging or a move to IPv6.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key distinction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An IP address was never an identity. Courts and engineers have said so for years, usually against a service provider's assumption otherwise. Carrier NAT is the point where the argument stops being a subtle one about households and shared Wi-Fi, and becomes arithmetic: one address, several hundred subscribers, one timestamp.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The two exits, and what each one costs
&lt;/h2&gt;

&lt;p&gt;The first exit is to log less by making the mapping predictable. RFC 7422 describes deterministic address mapping: give each subscriber a fixed block of ports on a shared address for a defined period, and the carrier only has to record one row per subscriber per block instead of one per connection. Operators like this because the storage problem disappears.&lt;/p&gt;

&lt;p&gt;Read it from the other direction and deterministic mapping is a much more durable surveillance record than per-connection logs. A single compact table lets anyone holding it reverse an address and port to a named subscriber for the whole retention window, without needing to have captured the moment. The engineering tradeoff is log volume against permanent legibility, and the version that is cheaper to keep is the version that is easier to query later.&lt;/p&gt;

&lt;p&gt;The second exit is IPv6, which ends the sharing by giving every subscriber real addresses. That fixes attribution by removing the ambiguity, which is not the same thing as fixing privacy. IPv6 introduces its own exposure: an address derived from a stable interface identifier follows a device between networks and works as a tracking cookie you cannot clear. RFC 8981 temporary addresses exist to blunt that, and whether they are enabled depends on your operating system's defaults. We covered the detail in &lt;a href="https://havenmessenger.com/blog/posts/ipv6-privacy-extensions-explained/" rel="noopener noreferrer"&gt;IPv6 privacy extensions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you build things, stop using IP as identity
&lt;/h2&gt;

&lt;p&gt;This is the practical half. A lot of production code still treats a client address as a proxy for a person: one signup per IP, per-IP rate limits, per-IP bans, fraud scores weighted on address reputation, geo-blocking, session pinning to an address.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you want to know&lt;/th&gt;
&lt;th&gt;What an IP address tells you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Is this the same person as before?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nothing reliable. Mobile addresses rotate, and a shared address is shared with strangers.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Is this one person or a thousand?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Undecidable from the address. A carrier NAT, a university, and a VPN exit all look the same.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Where is this person?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Where the carrier's gateway is, which can be a different region or country from the subscriber.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Did this address do the thing?&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only with the source port and an accurate timestamp, and only if the carrier still holds the mapping.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three changes follow. Log the source port and a UTC timestamp with sub-second precision if you log addresses at all, because a record without the port has no evidentiary value and you are retaining personal data that cannot answer the question you kept it for. Move abuse controls onto authenticated identity, proof of work, or per-account budgets rather than address buckets. And when you do block an address, set an expiry, because you are blocking whoever holds it next.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you are a subscriber
&lt;/h2&gt;

&lt;p&gt;Check first. Compare the WAN address on your router's status page against what an external address-lookup service reports. If they differ and your WAN address is in &lt;code&gt;100.64.0.0/10&lt;/code&gt;, you are behind a carrier NAT. Some deployments use other ranges, so a mismatch alone is the signal.&lt;/p&gt;

&lt;p&gt;What you get from it is a form of deniability you did not choose and cannot depend on. Your carrier still holds the subscriber record, still sees every destination you connect to, and can still be compelled to produce both. Address sharing obscures you from the far end of the connection, not from the party in the middle. For that problem the tools are different, and both their limits are worth knowing: see &lt;a href="https://havenmessenger.com/blog/posts/vpn-limitations/" rel="noopener noreferrer"&gt;what a VPN actually does&lt;/a&gt; and &lt;a href="https://havenmessenger.com/blog/posts/isp-surveillance-privacy/" rel="noopener noreferrer"&gt;what your ISP can see&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The broader point is that a piece of infrastructure adopted for a purely economic reason, the price of IPv4, ended up rewriting the evidentiary weight of the most commonly cited identifier on the internet. Nobody designed that. It is a side effect, and it is now the environment everything else is built in.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://havenmessenger.com/blog/posts/cgnat-ip-address-attribution/" rel="noopener noreferrer"&gt;havenmessenger.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>privacy</category>
      <category>networking</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
