<?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: Paulo Victor Leite Lima Gomes</title>
    <description>The latest articles on DEV Community by Paulo Victor Leite Lima Gomes (@pvgomes).</description>
    <link>https://dev.to/pvgomes</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%2F109646%2F27accb17-594d-4776-b421-db7cca109bfe.jpg</url>
      <title>DEV Community: Paulo Victor Leite Lima Gomes</title>
      <link>https://dev.to/pvgomes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pvgomes"/>
    <language>en</language>
    <item>
      <title>Staged npm publishing is production change control</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Sat, 24 Oct 2026 09:00:49 +0000</pubDate>
      <link>https://dev.to/pvgomes/staged-npm-publishing-is-production-change-control-31n1</link>
      <guid>https://dev.to/pvgomes/staged-npm-publishing-is-production-change-control-31n1</guid>
      <description>&lt;p&gt;I think we have been lying to ourselves about &lt;code&gt;npm publish&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We call it a release step, which makes it sound small and administrative: tests pass, CI uploads a tarball, someone updates a changelog, and we move on. But publishing a library is closer to a production deployment than it is to uploading a build artifact. The audience just happens to be every application, every developer laptop, and every downstream CI pipeline that trusts that package name.&lt;/p&gt;

&lt;p&gt;That is a pretty impressive blast radius for a job step that is often protected by one long-lived secret named something like &lt;code&gt;NPM_TOKEN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The good news is that npm's publishing model has finally caught up with that reality. Trusted publishing, staged releases, malware scanning, and independent workflow identities let us build a release lane with actual controls. The important part is not ticking a supply-chain-security box. It is deciding that making a package public is a production change and operating it that way.&lt;/p&gt;

&lt;h2&gt;
  
  
  A registry publish is a deployment with strangers on the other side
&lt;/h2&gt;

&lt;p&gt;When I deploy a service, my team normally has some guardrails: an environment, a deployment record, observable health signals, a rollback plan, and a person who can decide whether to continue. A library publish often has less ceremony despite affecting systems we do not own and cannot observe.&lt;/p&gt;

&lt;p&gt;Once a new version is tagged &lt;code&gt;latest&lt;/code&gt;, consumers may pull it into fresh CI runs within minutes. A compromised publish workflow can ship credential theft. A packaging mistake can break installs across a wide ecosystem. A post-install surprise can land in a build environment before the consumer has had a chance to understand what changed.&lt;/p&gt;

&lt;p&gt;This is not a reason to turn every patch release into a meeting. It is a reason to put the decision at the correct boundary. Producing a package and making it available to the public are different actions. They should not share the same authorization by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  The release is now a state machine
&lt;/h2&gt;

&lt;p&gt;The useful mental model is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;build → stage → scan → approve → public&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sequence is a meaningful improvement over “CI has a secret, therefore CI may publish.”&lt;/p&gt;

&lt;p&gt;In the current npm model, a trusted publisher authenticates with an OpenID Connect (OIDC) identity from its CI provider rather than presenting a reusable registry token. npm checks that identity against a configured repository, workflow, and environment. It also creates provenance automatically for supported trusted-publishing flows. &lt;a href="https://docs.npmjs.com/trusted-publishers/" rel="noopener noreferrer"&gt;npm's trusted-publishing documentation&lt;/a&gt; is worth reading closely because the details are the policy: the identity is not merely “GitHub Actions,” but a particular workflow running in a particular context.&lt;/p&gt;

&lt;p&gt;Then comes the part I like most: staging keeps the version out of the public registry until a human approves it. npm scans published packages before they are available for install; a scan can allow, hold, or block a package. Staged packages cannot be approved until that scan is complete. That means the registry itself now acknowledges that availability is a lifecycle, not an instantaneous side effect of a successful command. &lt;a href="https://github.blog/changelog/2026-09-03-multiple-trusted-publishing-configurations-for-npm/" rel="noopener noreferrer"&gt;GitHub's npm update&lt;/a&gt; describes the staged history maintainers can review, while the earlier &lt;a href="https://github.blog/changelog/2026-07-28-npm-publish-time-malware-scanning-and-dual-use-metadata/" rel="noopener noreferrer"&gt;malware-scanning announcement&lt;/a&gt; spells out the possible delay and review outcomes.&lt;/p&gt;

&lt;p&gt;This is not bureaucracy for its own sake. It buys time for the two questions that matter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Did the intended release workflow create this exact artifact?&lt;/li&gt;
&lt;li&gt;Should this exact artifact become public now?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Those questions are related, but they are not the same question.&lt;/p&gt;

&lt;h2&gt;
  
  
  OIDC proposes; approval promotes
&lt;/h2&gt;

&lt;p&gt;OIDC is excellent at constraining &lt;em&gt;who may propose a release&lt;/em&gt;. A trusted-publishing configuration can say, in effect, “only this workflow in this repository, under this environment, may obtain publish authority.” It removes a copied secret from the pipeline and makes an unexpected publishing attempt easier to reason about.&lt;/p&gt;

&lt;p&gt;OIDC does &lt;strong&gt;not&lt;/strong&gt; decide whether the release is sensible. It cannot notice that someone selected the wrong &lt;code&gt;latest&lt;/code&gt; tag, that a generated file is missing, or that a perfectly legitimate change needs a careful rollout. It also cannot make a human owner accountable for the public-release decision.&lt;/p&gt;

&lt;p&gt;Staging covers that second boundary: &lt;em&gt;who may make it public&lt;/em&gt;. It is the change-control gate.&lt;/p&gt;

&lt;p&gt;That distinction keeps the design honest. Provenance can establish where an artifact came from; it does not prove that the code is safe or that the release is appropriate. The &lt;a href="https://repos.openssf.org/attestations-style-guide.html" rel="noopener noreferrer"&gt;OpenSSF attestation UX guide&lt;/a&gt; makes the same caution in broader terms: attestation is evidence, not a safety verdict. Treat it as useful forensic material and a release-review input, not a green shield beside a dependency name.&lt;/p&gt;

&lt;h2&gt;
  
  
  An operating model that does not depend on heroic maintainers
&lt;/h2&gt;

&lt;p&gt;The September npm update made multiple trusted-publishing configurations available for a package. That is more than a convenience feature. It lets a team stop pretending all release paths are equivalent.&lt;/p&gt;

&lt;p&gt;I would set up three lanes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stable releases
&lt;/h3&gt;

&lt;p&gt;Use a dedicated release workflow, ideally protected by the repository's normal review and release-environment rules. It stages a version and produces a release record with the commit, version, changelog, test result, package contents, and provenance link.&lt;/p&gt;

&lt;p&gt;Promotion to public should require a named package maintainer with 2FA. For a team, make it a deliberate approval responsibility rather than an ambient permission held by anyone who happens to be on call. The approver checks the staged package, confirms the dist-tag, and records the decision in the normal release trail.&lt;/p&gt;

&lt;p&gt;That is not a four-eyes ritual for every typo. For small teams, one accountable maintainer may be entirely appropriate. The control is that the same compromised CI context cannot silently decide to publish broadly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prereleases
&lt;/h3&gt;

&lt;p&gt;Use a separate trusted-publishing configuration and workflow for versions such as &lt;code&gt;2.4.0-rc.1&lt;/code&gt; and tags such as &lt;code&gt;next&lt;/code&gt; or &lt;code&gt;beta&lt;/code&gt;. Keep its OIDC conditions distinct from the stable-release workflow.&lt;/p&gt;

&lt;p&gt;This makes experimentation cheaper without weakening the stable lane. A prerelease can still be staged and scanned, while its distribution tag makes the intended audience explicit. More importantly, a release engineer does not have to retain a broad token simply because the prerelease workflow has slightly different triggers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Emergency releases
&lt;/h3&gt;

&lt;p&gt;An emergency path should be faster, not invisible. Use another narrowly scoped workflow identity, require a short incident note, and preserve the same staging and human-promotion boundary. A designated incident commander or package owner can approve it, but the exception must leave evidence.&lt;/p&gt;

&lt;p&gt;Do not confuse “we need to fix this now” with “we should bypass every control.” The fastest reliable emergency process is the one people have rehearsed: publish a patched version, verify its provenance, move consumers to it, and deprecate a bad version if that is the appropriate registry response. A package version is hard to take back once consumers have cached or mirrored it, which is exactly why the release record matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the approval observable
&lt;/h2&gt;

&lt;p&gt;There is a failure mode here too: teams add a human button and call it governance, while the button says nothing useful. Then the process becomes an unreviewed rubber stamp with extra latency.&lt;/p&gt;

&lt;p&gt;An approver should be able to answer a short set of concrete questions without spelunking through CI logs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What commit and source repository produced this package?&lt;/li&gt;
&lt;li&gt;Which release workflow and environment requested the stage?&lt;/li&gt;
&lt;li&gt;What changed from the previous public version?&lt;/li&gt;
&lt;li&gt;Did the expected tests and package-content checks pass?&lt;/li&gt;
&lt;li&gt;Has registry scanning completed, and what is the state?&lt;/li&gt;
&lt;li&gt;Which tag will consumers receive?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Put that information in the release description or a small generated summary next to the approval action. If the answer depends on a maintainer remembering which run URL was the good one, the process is not yet operational.&lt;/p&gt;

&lt;p&gt;Keep the evidence after promotion too. GitHub documents how to verify artifact attestations offline, which is useful when investigating a suspicious release or preserving evidence outside a web UI. You do not need to perform offline verification on every ordinary release; you do need a tested procedure for doing it when trust is in question. See &lt;a href="https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/verify-attestations-offline" rel="noopener noreferrer"&gt;GitHub's offline-attestation verification guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Monday-morning migration list
&lt;/h2&gt;

&lt;p&gt;If your current process is &lt;code&gt;npm publish&lt;/code&gt; from CI with a long-lived token, I would do this in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inventory publishing authority.&lt;/strong&gt; Find every publish token, every workflow that can use one, and every person or service account that can change package settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Install trusted publishing.&lt;/strong&gt; Bind separate OIDC configurations to stable, prerelease, and emergency workflows. Keep their repository, workflow, and environment criteria narrow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stage by default.&lt;/strong&gt; npm supports staging by default per trusted-publishing configuration; make direct publishing an exceptional, explicit choice rather than the convenient default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name the approvers.&lt;/strong&gt; Decide who may promote stable versions, who covers incidents, and what evidence they must review. “Any maintainer” is an answer, but usually a lazy one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exercise a bad release.&lt;/strong&gt; Rehearse how you would stop recommending a bad version, release a fix, communicate to consumers, and collect provenance and workflow evidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify provenance when it matters.&lt;/strong&gt; Document the commands and access needed to verify an attestation independently during an incident.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is some migration pressure here, and it is welcome. npm has announced that granular access tokens configured to bypass 2FA will lose the ability to publish directly around January 2027; the remaining automated use is staging, with a human promotion step. &lt;a href="https://github.blog/changelog/2026-07-08-npm-install-time-security-and-gat-bypass2fa-deprecation/" rel="noopener noreferrer"&gt;The announcement&lt;/a&gt; is a good reason to remove those old publish tokens before they become an outage disguised as a security migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accountable beats magical
&lt;/h2&gt;

&lt;p&gt;None of this makes an npm dependency safe. Malware scanning catches some things, not everything. Provenance can show that a release came from the expected workflow even when that workflow faithfully built a bad change. A human approver can still make the wrong call.&lt;/p&gt;

&lt;p&gt;But that is not an argument for keeping a reusable secret in CI and hoping for the best. It is an argument for a release path that can answer basic questions after the fact: who proposed the package, what produced it, what checks ran, who made it public, and what happened next.&lt;/p&gt;

&lt;p&gt;That is production change control. It happens to be good supply-chain security too.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.npmjs.com/trusted-publishers/" rel="noopener noreferrer"&gt;Trusted publishing for npm packages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-09-03-multiple-trusted-publishing-configurations-for-npm/" rel="noopener noreferrer"&gt;Multiple trusted publishing configurations for npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-07-28-npm-publish-time-malware-scanning-and-dual-use-metadata/" rel="noopener noreferrer"&gt;npm publish-time malware scanning and dual-use metadata&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-07-08-npm-install-time-security-and-gat-bypass2fa-deprecation/" rel="noopener noreferrer"&gt;npm install-time security and GAT bypass-2FA deprecation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://repos.openssf.org/attestations-style-guide.html" rel="noopener noreferrer"&gt;OpenSSF attestation UI/UX guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/how-tos/secure-your-work/use-artifact-attestations/verify-attestations-offline" rel="noopener noreferrer"&gt;Verifying artifact attestations offline&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
    <item>
      <title>writable Kubernetes volumes are security contracts now</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Sat, 24 Oct 2026 09:00:32 +0000</pubDate>
      <link>https://dev.to/pvgomes/writable-kubernetes-volumes-are-security-contracts-now-89l</link>
      <guid>https://dev.to/pvgomes/writable-kubernetes-volumes-are-security-contracts-now-89l</guid>
      <description>&lt;p&gt;There is a familiar Kubernetes hardening checklist that makes everyone feel briefly responsible.&lt;/p&gt;

&lt;p&gt;Run as non-root. Drop Linux capabilities. Disable privilege escalation. Set &lt;code&gt;readOnlyRootFilesystem: true&lt;/code&gt;. Add resource limits. Avoid host paths. Use admission policy so nobody has to remember all of this by hand.&lt;/p&gt;

&lt;p&gt;Good checklist. Keep it.&lt;/p&gt;

&lt;p&gt;Then the application fails because it cannot write to &lt;code&gt;/tmp&lt;/code&gt;, a framework wants a cache directory, a sidecar needs a handoff path, an upload flow stages files before scanning them, or a model server wants somewhere to unpack artifacts. So we add an &lt;code&gt;emptyDir&lt;/code&gt;, or a persistent volume, or a shared mount between containers.&lt;/p&gt;

&lt;p&gt;And just like that, the supposedly immutable container has a writable filesystem again.&lt;/p&gt;

&lt;p&gt;Not the root filesystem, sure. But still a writable filesystem. One the process can use to write scripts, unpack binaries, race another container, leave junk for a later step, or turn "temporary storage" into the most interesting part of the compromise.&lt;/p&gt;

&lt;p&gt;This is the part of container hardening we have been hand-waving for years. We treated writable volumes as plumbing. Kubernetes v1.37 is a useful reminder that they are policy.&lt;/p&gt;

&lt;h2&gt;
  
  
  the old checklist was incomplete
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;readOnlyRootFilesystem: true&lt;/code&gt; is still one of the better low-drama controls in Kubernetes. It breaks lazy application assumptions. It makes persistence harder for an attacker. It forces teams to separate the image from runtime state.&lt;/p&gt;

&lt;p&gt;But it has always had an escape hatch: workloads still need writable paths.&lt;/p&gt;

&lt;p&gt;That escape hatch is not a footnote. It is where many real applications do their work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/tmp&lt;/code&gt; for framework scratch files&lt;/li&gt;
&lt;li&gt;caches for package managers, templates, compiled views, or ML runtime state&lt;/li&gt;
&lt;li&gt;upload staging directories&lt;/li&gt;
&lt;li&gt;sidecar exchange volumes&lt;/li&gt;
&lt;li&gt;init-container-to-app handoff paths&lt;/li&gt;
&lt;li&gt;plugin directories&lt;/li&gt;
&lt;li&gt;generated config&lt;/li&gt;
&lt;li&gt;logs when the app is not properly writing to stdout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of these paths should be boring scratch space. Some are intentionally shared. Some should never execute code. Some are explicitly designed to receive executable code, which is another way of saying they deserve a much louder review.&lt;/p&gt;

&lt;p&gt;If all of those end up as "just mount an &lt;code&gt;emptyDir&lt;/code&gt;", the security contract is missing the important sentence.&lt;/p&gt;

&lt;h2&gt;
  
  
  what Kubernetes v1.37 changes
&lt;/h2&gt;

&lt;p&gt;Kubernetes v1.37 introduced two alpha storage-hardening features that look small and are not.&lt;/p&gt;

&lt;p&gt;The first is &lt;code&gt;bindMountOptions&lt;/code&gt; on &lt;code&gt;volumeMounts&lt;/code&gt;. It lets a pod specify Linux bind mount flags such as &lt;code&gt;noexec&lt;/code&gt;, &lt;code&gt;nodev&lt;/code&gt;, and &lt;code&gt;nosuid&lt;/code&gt; per volume mount. That means a container can mount a writable directory while still saying: files written here must not be executable, device files should not matter, and setuid/setgid bits should be ignored.&lt;/p&gt;

&lt;p&gt;The second is &lt;code&gt;emptyDir.mode&lt;/code&gt;. It lets the pod spec declare the Unix permission mode for an &lt;code&gt;emptyDir&lt;/code&gt;, including the sticky-bit pattern people expect from a real &lt;code&gt;/tmp&lt;/code&gt;, such as &lt;code&gt;01777&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Both are alpha in v1.37. They require feature gates. &lt;code&gt;bindMountOptions&lt;/code&gt; also depends on runtime support for the CRI mount options field. This is not a "go turn it on everywhere by Friday" post.&lt;/p&gt;

&lt;p&gt;The point is more important than the rollout status: Kubernetes is finally giving the pod spec vocabulary for writable mount intent.&lt;/p&gt;

&lt;p&gt;Here is the shape of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Pod&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hardened-scratch-example&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;linux&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example/app:latest&lt;/span&gt;
      &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;readOnlyRootFilesystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;allowPrivilegeEscalation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scratch&lt;/span&gt;
          &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/tmp&lt;/span&gt;
          &lt;span class="na"&gt;bindMountOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;noexec&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;nodev&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;nosuid&lt;/span&gt;
  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scratch&lt;/span&gt;
      &lt;span class="na"&gt;emptyDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;01777&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is still YAML, yes. Kubernetes remains undefeated at producing YAML.&lt;/p&gt;

&lt;p&gt;But this YAML says something that was previously buried in convention: this writable directory exists for scratch data, not for executable code, device files, or privilege tricks.&lt;/p&gt;

&lt;h2&gt;
  
  
  PV mount options were not enough
&lt;/h2&gt;

&lt;p&gt;One subtle but important detail: this is not the same as PersistentVolume &lt;code&gt;mountOptions&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;PersistentVolume mount options operate at the storage layer. They are about how the volume is mounted by the storage system. The new &lt;code&gt;bindMountOptions&lt;/code&gt; field applies to the bind mount inside the container.&lt;/p&gt;

&lt;p&gt;That distinction matters because a pod can have multiple containers mounting the same volume for different reasons. The storage backend may be the same, but the intent is not.&lt;/p&gt;

&lt;p&gt;An init container may need to write generated files. The main application may need to read them but never execute from that path. A sidecar may need a shared exchange directory. Another container may not need the mount at all.&lt;/p&gt;

&lt;p&gt;Per-container mount policy is the interesting part.&lt;/p&gt;

&lt;p&gt;If the only policy lives at the storage object, the pod loses nuance. If the policy lives at the &lt;code&gt;volumeMount&lt;/code&gt;, the platform can say: this container gets this path with these constraints.&lt;/p&gt;

&lt;p&gt;That is a much better security contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  writable does not mean executable
&lt;/h2&gt;

&lt;p&gt;The most useful default is also the most obvious one:&lt;/p&gt;

&lt;p&gt;Most writable volumes should be non-executable.&lt;/p&gt;

&lt;p&gt;If the application needs &lt;code&gt;/tmp&lt;/code&gt;, a cache directory, or an upload staging path, why should a binary copied there be executable? If the answer is "because Linux defaults", that is not a good answer. It is just the absence of a decision.&lt;/p&gt;

&lt;p&gt;The Kubernetes feature blog uses exactly this example: without &lt;code&gt;noexec&lt;/code&gt;, a compromised process can use any writable volume to download or create a binary, mark it executable, and run it even when the root filesystem is read-only.&lt;/p&gt;

&lt;p&gt;This does not make &lt;code&gt;noexec&lt;/code&gt; magic. Interpreters exist. Shells exist. A process can still feed data to something already executable elsewhere. Security controls rarely delete entire attack classes by themselves.&lt;/p&gt;

&lt;p&gt;But &lt;code&gt;noexec&lt;/code&gt; does remove a very common and very convenient step. That matters. Good hardening is often about making the cheap path expensive.&lt;/p&gt;

&lt;p&gt;The same logic applies to &lt;code&gt;nodev&lt;/code&gt; and &lt;code&gt;nosuid&lt;/code&gt;. Most application scratch paths have no business honoring device special files or setuid bits. If a workload needs those semantics, it should say so loudly.&lt;/p&gt;

&lt;h2&gt;
  
  
  emptyDir permissions were also a contract
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;emptyDir&lt;/code&gt; has always been a little too easy.&lt;/p&gt;

&lt;p&gt;Need a writable directory? Add this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tmp&lt;/span&gt;
    &lt;span class="na"&gt;emptyDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Done. Ship it.&lt;/p&gt;

&lt;p&gt;The default behavior is convenient, but convenience is not the same as intent. If the directory behaves like shared &lt;code&gt;/tmp&lt;/code&gt;, it probably needs the sticky bit so one user cannot delete another user's files. If it is an app-private cache, maybe it should not be world-writable at all. If it is a sidecar exchange path, the permissions should match the actual producers and consumers instead of whatever happened after an init container ran &lt;code&gt;chmod&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That last workaround is worth calling out. Before &lt;code&gt;emptyDir.mode&lt;/code&gt;, teams often used init containers to create directories and fix permissions. It worked, but it made the pod's storage policy procedural. You had to read the init container command to understand the contract.&lt;/p&gt;

&lt;p&gt;An API field is better. It is visible to admission policy. It is visible to review. It is visible to humans who are tired and trying to understand why a pod is allowed to have a writable mount.&lt;/p&gt;

&lt;h2&gt;
  
  
  classify mounts by intent
&lt;/h2&gt;

&lt;p&gt;The practical move is not to wait for every managed Kubernetes provider to make these alpha fields boring. The practical move is to start classifying writable mounts now.&lt;/p&gt;

&lt;p&gt;I would use buckets like these.&lt;/p&gt;

&lt;h3&gt;
  
  
  scratch temp
&lt;/h3&gt;

&lt;p&gt;This is the ordinary &lt;code&gt;/tmp&lt;/code&gt; case: framework scratch files, temporary decompression, request-local intermediate data, things that should not survive the pod.&lt;/p&gt;

&lt;p&gt;Default posture:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;bindMountOptions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;noexec&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;nodev&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;nosuid&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;emptyDir.mode: 01777&lt;/code&gt; only when it is really shared temp with multiple users or containers that need normal &lt;code&gt;/tmp&lt;/code&gt; behavior. If it is private to one container and one user, consider narrower permissions.&lt;/p&gt;

&lt;h3&gt;
  
  
  shared tmp
&lt;/h3&gt;

&lt;p&gt;Shared temp is where people get casual and attackers get comfortable.&lt;/p&gt;

&lt;p&gt;If multiple containers or multiple users share the directory, say that explicitly. Use the sticky bit when the model is "everyone can create files, but cannot delete each other's files." Do not let world-writable become the default just because it made the first test pass.&lt;/p&gt;

&lt;p&gt;Also ask why it is shared. Many "shared temp" volumes are actually lazy IPC, lazy logging, or lazy configuration handoff.&lt;/p&gt;

&lt;h3&gt;
  
  
  app cache
&lt;/h3&gt;

&lt;p&gt;Most caches should not be executable.&lt;/p&gt;

&lt;p&gt;Template caches, dependency caches, image transformation caches, model runtime caches, and web framework caches are usually data. If a runtime insists on generating executable code into a cache, that should be documented as an exception, not discovered during an incident.&lt;/p&gt;

&lt;p&gt;This is where admission policy can help later: executable writable cache directories should need a reason.&lt;/p&gt;

&lt;h3&gt;
  
  
  uploads and quarantine
&lt;/h3&gt;

&lt;p&gt;Upload staging directories should be treated as hostile by default.&lt;/p&gt;

&lt;p&gt;That means non-executable, no device files, no suid semantics, and ideally separated from the final storage path. If the application scans or transforms uploads, make the handoff stages explicit. "Uploaded file exists somewhere under &lt;code&gt;/tmp&lt;/code&gt;" is not a design.&lt;/p&gt;

&lt;p&gt;This matters even more when sidecars are involved. The scanner and the app may need different views of the same volume.&lt;/p&gt;

&lt;h3&gt;
  
  
  plugin and executable drop zones
&lt;/h3&gt;

&lt;p&gt;Some systems really do need writable executable directories.&lt;/p&gt;

&lt;p&gt;Plugin systems. Build workers. Notebook environments. CI runners. Developer sandboxes. Some ML serving setups that materialize runtime code or native extensions.&lt;/p&gt;

&lt;p&gt;Fine. But call them what they are: privileged exceptions.&lt;/p&gt;

&lt;p&gt;An executable writable mount is not automatically wrong. It is just not ordinary storage. It should have an owner, a threat model, a retention story, a review path, and ideally a much smaller blast radius than the main application container.&lt;/p&gt;

&lt;p&gt;If a team cannot explain why a writable mount must be executable, it probably should not be executable.&lt;/p&gt;

&lt;h3&gt;
  
  
  sidecar handoff volumes
&lt;/h3&gt;

&lt;p&gt;Sidecars are where per-container mount policy becomes more than a nice detail.&lt;/p&gt;

&lt;p&gt;Imagine an init container writes generated config to a volume. The app reads it. A reload sidecar watches it. Those containers do not need identical mount semantics.&lt;/p&gt;

&lt;p&gt;Or imagine an upload scanner. The app writes incoming files. The scanner reads and marks results. The app consumes only approved outputs. Again, different containers have different intent.&lt;/p&gt;

&lt;p&gt;The old pattern treated the volume as the policy unit. The better pattern treats each mount as the policy unit.&lt;/p&gt;

&lt;h2&gt;
  
  
  admission policy should ask for reasons
&lt;/h2&gt;

&lt;p&gt;The future I want here is not every developer memorizing mount flags.&lt;/p&gt;

&lt;p&gt;The future is admission policy that understands writable storage intent.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writable mounts must declare a purpose label or annotation.&lt;/li&gt;
&lt;li&gt;Writable mounts default to &lt;code&gt;noexec&lt;/code&gt;, &lt;code&gt;nodev&lt;/code&gt;, and &lt;code&gt;nosuid&lt;/code&gt; where supported.&lt;/li&gt;
&lt;li&gt;Executable writable mounts require an explicit exception.&lt;/li&gt;
&lt;li&gt;Shared &lt;code&gt;emptyDir&lt;/code&gt; volumes require a declared permission mode.&lt;/li&gt;
&lt;li&gt;Upload staging mounts cannot be executable.&lt;/li&gt;
&lt;li&gt;Plugin directories must be isolated from the main app container unless approved.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the same pattern we already use for capabilities, host networking, privileged pods, and service account tokens. Make the common safe thing easy. Make the dangerous thing possible but explicit.&lt;/p&gt;

&lt;p&gt;The alpha fields are not required to start this work. You can inventory pod specs today. You can classify mounts today. You can add annotations today. You can update review templates today. You can teach platform teams to stop saying "it only writes to &lt;code&gt;/tmp&lt;/code&gt;" as if that ends the conversation.&lt;/p&gt;

&lt;p&gt;When the fields become stable enough for your environment, the policy vocabulary is already there.&lt;/p&gt;

&lt;h2&gt;
  
  
  migration advice
&lt;/h2&gt;

&lt;p&gt;I would not start by enabling feature gates in production.&lt;/p&gt;

&lt;p&gt;I would start with an inventory:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;List every workload with a writable volume mount.&lt;/li&gt;
&lt;li&gt;Record the mount path, volume type, containers that mount it, and whether it is shared.&lt;/li&gt;
&lt;li&gt;Assign a purpose: scratch, shared temp, cache, upload staging, generated config, plugin/executable, sidecar handoff, or "unknown".&lt;/li&gt;
&lt;li&gt;Treat "unknown" as a bug in the platform contract.&lt;/li&gt;
&lt;li&gt;Add admission warnings for new writable mounts without a purpose.&lt;/li&gt;
&lt;li&gt;Test &lt;code&gt;bindMountOptions&lt;/code&gt; and &lt;code&gt;emptyDir.mode&lt;/code&gt; on non-critical clusters once your Kubernetes version, feature gates, and runtime support line up.&lt;/li&gt;
&lt;li&gt;Require a written reason for executable writable mounts.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The important artifact is not the YAML field. It is the classification.&lt;/p&gt;

&lt;p&gt;Once a team has that inventory, the v1.37 features become a way to encode decisions instead of a last-minute compliance retrofit. Without that inventory, the fields become another checkbox nobody trusts.&lt;/p&gt;

&lt;h2&gt;
  
  
  the boring field is the lesson
&lt;/h2&gt;

&lt;p&gt;I like features like this because they expose where the old mental model was too simple.&lt;/p&gt;

&lt;p&gt;Read-only root filesystem was never the same thing as read-only workload state. It was a good control with an obvious exception. We just spent years pretending the exception was operational trivia.&lt;/p&gt;

&lt;p&gt;Writable pod storage is not trivia. It is where applications stage data, share state, receive hostile input, and sometimes execute code. That makes it part of the workload security contract.&lt;/p&gt;

&lt;p&gt;Kubernetes v1.37 did not invent that contract. It just made the missing words harder to ignore.&lt;/p&gt;

&lt;h2&gt;
  
  
  references
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/blog/2026/09/16/kubernetes-v1-37-hardening-container-storage/" rel="noopener noreferrer"&gt;Kubernetes v1.37: Hardening Container Storage with Bind Mount Options and EmptyDir Permissions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-bind-mount-options/" rel="noopener noreferrer"&gt;Set Bind Mount Options on Volume Mounts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/concepts/storage/volumes/" rel="noopener noreferrer"&gt;Kubernetes volumes documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.kubernetes.dev/resources/keps/5855/" rel="noopener noreferrer"&gt;KEP-5855: Allow bind mount options on volumeMounts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.k8s.dev/resources/keps/5502/" rel="noopener noreferrer"&gt;KEP-5502: EmptyDir Volume Permission Mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/blog/2026/08/26/kubernetes-v1-37-release/" rel="noopener noreferrer"&gt;Kubernetes v1.37 release announcement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://media.defense.gov/2022/Aug/29/2003066362/1/1/0/CTR_KUBERNETES_HARDENING_GUIDANCE_1.2_20220829.PDF" rel="noopener noreferrer"&gt;NSA/CISA Kubernetes Hardening Guidance v1.2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
    <item>
      <title>Your AI API key should be a break-glass credential now</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Thu, 22 Oct 2026 09:00:35 +0000</pubDate>
      <link>https://dev.to/pvgomes/your-ai-api-key-should-be-a-break-glass-credential-now-4f76</link>
      <guid>https://dev.to/pvgomes/your-ai-api-key-should-be-a-break-glass-credential-now-4f76</guid>
      <description>&lt;p&gt;Let's talk about something uncomfortable: if your production AI API key is still a long, static string copied into a secret store, you're clinging to a dangerous default. Even worse, it's a default that flies in the face of what your workloads already know about identity. The most common AI production credential today remains a secret copied from one place to another, while the very system running it often has a perfectly good identity that could be leveraged.&lt;/p&gt;

&lt;p&gt;This isn't just an academic point; it's a security vulnerability waiting to happen, especially with the rise of AI agents. Static API keys leak. They leak through logs, through tool outputs, from compromised MCP servers, in CI variables, in local configuration files, in hastily copied examples, and in long-lived automation scripts. The more places you copy that string, the wider the attack surface. An agent with a long-lived, over-permissioned static key is a significant blast radius.&lt;/p&gt;

&lt;p&gt;The good news? OpenAI, Microsoft, Google, GitHub, and the broader identity community are all pointing towards a better path: &lt;strong&gt;Workload Identity Federation (WIF)&lt;/strong&gt;. This is a game-changer that's more significant than any new model launch. WIF allows your GitHub Actions, Kubernetes workloads, cloud runtimes (AWS, Azure, Google Cloud, OCI), and SPIFFE-compliant identities to exchange their &lt;em&gt;own&lt;/em&gt; short-lived tokens for provider-specific access tokens. Think about it: instead of copying a secret, your CI job authenticates with GitHub, gets an OIDC token, and exchanges that with OpenAI for a short-lived access token, complete with conditions tied to the repository, branch, namespace, service account, audience, and environment.&lt;/p&gt;

&lt;p&gt;The practical shift is profound. WIF moves the control from "who knows the key" to "which workload, in which context, may mint a token for which scope." This allows for granular policy enforcement on attributes rather than relying on the secrecy of a static string. You're no longer distributing break-glass credentials as your daily default.&lt;/p&gt;

&lt;p&gt;Now for the skeptical part. Workload Identity Federation is not a magic bullet for all agent security. It's a foundational primitive, not a complete strategy. It doesn't solve prompt injection, prevent overbroad tools from being invoked, magically fix bad scopes, or ensure your verification mechanisms are robust. What it &lt;em&gt;does&lt;/em&gt; do is remove one of the most dangerous defaults we've inherited: relying on long-lived, static secrets for production AI access.&lt;/p&gt;

&lt;p&gt;So, what's your Monday checklist to start moving away from static AI API keys?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Inventory Your AI API Keys:&lt;/strong&gt; Find every long-lived AI API key in your systems.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Classify Runtime Identities:&lt;/strong&gt; Understand what identities your CI jobs, Kubernetes pods, and cloud services already possess (e.g., GitHub OIDC, Kubernetes Service Accounts, AWS IAM Roles).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Replace CI and Kubernetes Keys First:&lt;/strong&gt; These are usually the easiest wins for WIF adoption.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Set Short Token Lifetimes:&lt;/strong&gt; Configure tokens to expire quickly, forcing frequent re-authentication.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Bind Claims to Environments:&lt;/strong&gt; Use conditions (repo, branch, namespace, service account) to restrict token issuance to specific contexts.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Log Token Exchanges:&lt;/strong&gt; Ensure you have audit trails for every token minting operation.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Keep One Break-Glass Path:&lt;/strong&gt; You'll still need an emergency, human-controlled path, but it should be just that: an emergency path, not the default.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Test Revocation:&lt;/strong&gt; Verify that when a workload identity is compromised or decommissioned, its ability to mint AI API tokens is immediately revoked.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This isn't about making security harder; it's about making it smarter and more aligned with modern cloud practices. Your AI API keys should be a break-glass credential now.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://developers.openai.com/api/docs/llms.txt" rel="noopener noreferrer"&gt;OpenAI API Docs Index&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://developers.openai.com/api/docs/guides/workload-identity-federation/github-actions.md" rel="noopener noreferrer"&gt;OpenAI GitHub Actions Workload Identity Federation Guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://developers.openai.com/api/docs/guides/workload-identity-federation/federation-rules.md" rel="noopener noreferrer"&gt;OpenAI Federation Rule Reference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://cloud.google.com/iam/docs/workload-identity-federation" rel="noopener noreferrer"&gt;Google Cloud Workload Identity Federation Overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation" rel="noopener noreferrer"&gt;Microsoft Entra Workload Identity Federation Concepts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-cloud-providers" rel="noopener noreferrer"&gt;GitHub Actions OIDC Guidance&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://spiffe.io/docs/latest/spiffe-about/overview/" rel="noopener noreferrer"&gt;SPIFFE Overview&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
    <item>
      <title>copilot approvals need separation of duties</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Sun, 18 Oct 2026 10:00:31 +0000</pubDate>
      <link>https://dev.to/pvgomes/copilot-approvals-need-separation-of-duties-55jl</link>
      <guid>https://dev.to/pvgomes/copilot-approvals-need-separation-of-duties-55jl</guid>
      <description>&lt;p&gt;GitHub shipped one of those changelog entries that looks small until you read it like an engineer responsible for production.&lt;/p&gt;

&lt;p&gt;Copilot code review can now approve pull requests.&lt;/p&gt;

&lt;p&gt;Not just comment. Not just summarize. Not just say "this looks ready" in a friendly overview paragraph.&lt;/p&gt;

&lt;p&gt;Approve.&lt;/p&gt;

&lt;p&gt;That is a different verb.&lt;/p&gt;

&lt;p&gt;A review comment is advice. An approval is part of the merge protocol. It interacts with branch protection, ownership rules, audit logs, deployment gates, CI trust, package publishing, and the boring little controls that keep a software organization from becoming a vibes-based merge machine.&lt;/p&gt;

&lt;p&gt;So the question is not "should AI be allowed to review code?"&lt;/p&gt;

&lt;p&gt;That question is already stale.&lt;/p&gt;

&lt;p&gt;The better question is: when an AI review is allowed to count, what duties must it be separated from?&lt;/p&gt;

&lt;h2&gt;
  
  
  approval is not just better review UX
&lt;/h2&gt;

&lt;p&gt;I like AI code review in the same way I like linters, static analysis, dependency alerts, and good test output. The best version reduces noise and catches the obvious stuff before a human wastes attention on it.&lt;/p&gt;

&lt;p&gt;Copilot approval assessments are useful in that world. If the tool reviews a pull request and says it thinks the change is ready, that can be a signal. Maybe it found no blocking issues. Maybe it saw only low-risk edits. Maybe it gives the human reviewer a faster way to triage the queue.&lt;/p&gt;

&lt;p&gt;Fine.&lt;/p&gt;

&lt;p&gt;But the moment the approval can count toward required approvals, it is no longer just a signal.&lt;/p&gt;

&lt;p&gt;It becomes one of the things that can move code from "proposed" to "mergeable."&lt;/p&gt;

&lt;p&gt;That changes the threat model.&lt;/p&gt;

&lt;p&gt;Teams have spent years teaching developers that the merge button is not just a button. It is a controlled boundary. We put rules around it because code review is not only about code quality. It is also about accountability.&lt;/p&gt;

&lt;p&gt;Who looked at this?&lt;/p&gt;

&lt;p&gt;Who had enough context to accept the risk?&lt;/p&gt;

&lt;p&gt;Which automated checks passed?&lt;/p&gt;

&lt;p&gt;Which paths changed?&lt;/p&gt;

&lt;p&gt;Was the person approving independent from the person making the change?&lt;/p&gt;

&lt;p&gt;If Copilot can now participate in that protocol, it needs to be governed like a participant in that protocol. Treating it as "another reviewer" is lazy architecture.&lt;/p&gt;

&lt;p&gt;It is a new merge primitive.&lt;/p&gt;

&lt;h2&gt;
  
  
  the useful version is narrow
&lt;/h2&gt;

&lt;p&gt;The useful version of Copilot approvals is not hard to imagine.&lt;/p&gt;

&lt;p&gt;There are pull requests where a machine approval is probably acceptable, or at least acceptable as one part of the evidence.&lt;/p&gt;

&lt;p&gt;Generated documentation. Test fixture updates. Formatting-only changes. Mechanical refactors where the compiler, tests, and ownership rules give strong evidence. Maybe low-risk generated code in a repository where the generation process itself is controlled and reproducible.&lt;/p&gt;

&lt;p&gt;For those changes, an AI approval could reduce human review drag. Nobody should have to spend senior-engineer attention rubber-stamping a thousand-line generated diff that a deterministic tool produced and CI already validated.&lt;/p&gt;

&lt;p&gt;But that is the key phrase: as one part of the evidence.&lt;/p&gt;

&lt;p&gt;The dangerous version is broader.&lt;/p&gt;

&lt;p&gt;An agent writes a change. Another agent, or the same class of tool wearing a different hat, reviews it. CI passes because the test suite is weak or because the change altered the workflow that runs the tests. The approval counts. The merge button lights up. Everyone gets to pretend there was independent review.&lt;/p&gt;

&lt;p&gt;That is not separation of duties.&lt;/p&gt;

&lt;p&gt;That is automation laundering.&lt;/p&gt;

&lt;h2&gt;
  
  
  some paths should be human-only
&lt;/h2&gt;

&lt;p&gt;The first policy should be boring and explicit:&lt;/p&gt;

&lt;p&gt;Copilot approvals should not count for sensitive paths.&lt;/p&gt;

&lt;p&gt;I would start with a denylist that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deployment workflows&lt;/li&gt;
&lt;li&gt;authentication and authorization code&lt;/li&gt;
&lt;li&gt;payments and billing code&lt;/li&gt;
&lt;li&gt;ledger, reconciliation, and money-movement logic&lt;/li&gt;
&lt;li&gt;secrets handling&lt;/li&gt;
&lt;li&gt;CI and release automation&lt;/li&gt;
&lt;li&gt;dependency manifests and lockfiles&lt;/li&gt;
&lt;li&gt;infrastructure as code&lt;/li&gt;
&lt;li&gt;package publishing configuration&lt;/li&gt;
&lt;li&gt;production incident tooling&lt;/li&gt;
&lt;li&gt;security policy and code scanning configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not because Copilot is useless in those areas. It may be very useful there.&lt;/p&gt;

&lt;p&gt;It can still comment. It can still explain. It can still point out suspicious patterns. It can still help the human reviewer ask better questions.&lt;/p&gt;

&lt;p&gt;But its approval should not satisfy the merge rule.&lt;/p&gt;

&lt;p&gt;There is a difference between using a tool to improve judgment and delegating the control decision to that tool.&lt;/p&gt;

&lt;p&gt;Sensitive paths are where that distinction matters most.&lt;/p&gt;

&lt;p&gt;If a pull request changes a GitHub Actions workflow, I do not want the same platform that will execute that workflow to be treated as an independent approver of the change. If a pull request changes authentication behavior, I do not want a generic "looks good" from an AI reviewer to count as a security sign-off. If a pull request changes package publishing, I want the approval path to be as boring and traceable as the release path.&lt;/p&gt;

&lt;p&gt;The point is not fear of AI.&lt;/p&gt;

&lt;p&gt;The point is that critical controls should not be collapsed into one convenient product surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  context exclusions matter more now
&lt;/h2&gt;

&lt;p&gt;There is another uncomfortable detail: agents do not always see everything.&lt;/p&gt;

&lt;p&gt;GitHub also made content exclusions generally available for Copilot app and CLI. That is good. Enterprises need a way to keep sensitive files out of agent context.&lt;/p&gt;

&lt;p&gt;But if an agent is allowed to approve code, the exclusion policy becomes part of the approval policy.&lt;/p&gt;

&lt;p&gt;An approval from a reviewer who was not allowed to read the relevant files is weaker evidence.&lt;/p&gt;

&lt;p&gt;That sounds obvious when stated plainly, but I expect many organizations to miss it. They will configure content exclusions for privacy or data-boundary reasons, then later enable AI approvals as if the reviewer had normal repository visibility.&lt;/p&gt;

&lt;p&gt;That is not how review works.&lt;/p&gt;

&lt;p&gt;Imagine a human reviewer saying: "I approve this auth refactor, but I was not allowed to open the policy files, the integration tests, or the deployment workflow."&lt;/p&gt;

&lt;p&gt;You would not count that as a strong review.&lt;/p&gt;

&lt;p&gt;The same standard should apply to the agent.&lt;/p&gt;

&lt;p&gt;Approval policy needs to know not only which files changed, but also which files the tool was allowed to inspect while forming the approval. For low-risk generated docs, maybe that does not matter much. For a service boundary, it matters a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  CI is not automatically independent
&lt;/h2&gt;

&lt;p&gt;The easy answer is to say: let Copilot approve only when CI passes.&lt;/p&gt;

&lt;p&gt;That is necessary.&lt;/p&gt;

&lt;p&gt;It is not sufficient.&lt;/p&gt;

&lt;p&gt;CI is only independent evidence when the pull request cannot cheaply compromise the checks that are supposed to constrain it.&lt;/p&gt;

&lt;p&gt;If the change edits workflow files, reusable workflow references, build scripts, dependency installation, test selection, or artifact publishing, then the CI result is part of the thing being changed. You need a stronger review path.&lt;/p&gt;

&lt;p&gt;This is why the nearby GitHub Actions and CodeQL changes are relevant. GitHub has been tightening the trust boundary around Actions: more precise CodeQL detection for GitHub Actions issues, clearer reusable workflow identity context, least-privilege permissions, and read-only cache tokens for untrusted triggers.&lt;/p&gt;

&lt;p&gt;That is the right mental model.&lt;/p&gt;

&lt;p&gt;Automation is not a blob of trust. It has boundaries.&lt;/p&gt;

&lt;p&gt;An AI approval should inherit those boundaries, not float above them.&lt;/p&gt;

&lt;p&gt;If the diff changes the machinery that produces the green check, then "green check plus AI approval" is not enough. The reviewer needs evidence that the check still means what everyone thinks it means.&lt;/p&gt;

&lt;h2&gt;
  
  
  agent-authored code needs independent review
&lt;/h2&gt;

&lt;p&gt;Here is the rule I would make non-negotiable:&lt;/p&gt;

&lt;p&gt;An agent should not be allowed to approve a pull request that was primarily authored by the same class of agent.&lt;/p&gt;

&lt;p&gt;I am not saying every AI-assisted pull request needs a committee. That would be silly. Developers already use autocomplete, chat, and refactoring tools all day.&lt;/p&gt;

&lt;p&gt;The interesting case is a pull request where the agent did the substantive work: planned the change, edited the files, wrote the tests, and opened the PR.&lt;/p&gt;

&lt;p&gt;In that case, an AI approval from the same product family should not count as independent review.&lt;/p&gt;

&lt;p&gt;Maybe a human can approve it. Maybe a different automated control can provide evidence. Maybe a deterministic generator plus reproducible build plus strong tests is enough for a narrow path. But "agent wrote it, agent approved it" should not satisfy separation of duties.&lt;/p&gt;

&lt;p&gt;This sounds strict until you translate it back into human terms.&lt;/p&gt;

&lt;p&gt;We usually do not let authors be their own independent reviewers. We do not treat a developer saying "I checked my own work" as the same thing as another qualified person reviewing it.&lt;/p&gt;

&lt;p&gt;AI does not make that principle obsolete. It makes it easier to accidentally violate.&lt;/p&gt;

&lt;h2&gt;
  
  
  the policy ladder
&lt;/h2&gt;

&lt;p&gt;I would not start by enabling AI approvals everywhere and hoping repository admins figure it out later.&lt;/p&gt;

&lt;p&gt;I would use a ladder.&lt;/p&gt;

&lt;p&gt;At the bottom: approval assessments only.&lt;/p&gt;

&lt;p&gt;Let Copilot say whether it thinks the pull request is ready. Do not let that count toward required approvals. Watch the quality of the signal. See where it helps. See where it is noisy. Tune the instructions and review effort.&lt;/p&gt;

&lt;p&gt;Next: allow counted approvals only on explicitly low-risk paths.&lt;/p&gt;

&lt;p&gt;Examples: documentation, generated examples, formatting-only changes, test-only changes, fixture updates, and mechanical refactors that have strong CI coverage. Require ownership rules and branch protection to pass. Require the approval to be dismissed on new commits.&lt;/p&gt;

&lt;p&gt;Next: require policy evidence.&lt;/p&gt;

&lt;p&gt;The approval should be explainable. Which files changed? Which paths were allowed? Which content exclusions applied? Which checks passed? Was the PR human-authored, agent-authored, or mixed? Did any sensitive path rule trigger?&lt;/p&gt;

&lt;p&gt;Next: expire exceptions.&lt;/p&gt;

&lt;p&gt;Temporary policy exceptions should have expiration dates, just like temporary budgets. A team may need a short-lived allowance during a migration. Fine. But permanent exceptions become folklore. Folklore becomes production risk.&lt;/p&gt;

&lt;p&gt;At the top: keep some repositories human-only.&lt;/p&gt;

&lt;p&gt;Not every repo needs AI approvals. Authentication platforms, payment systems, ledgers, infrastructure modules, release automation, security tooling, and regulated workloads may still benefit from AI comments without letting the tool count as an approver.&lt;/p&gt;

&lt;p&gt;That is not anti-AI.&lt;/p&gt;

&lt;p&gt;That is normal engineering judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  publishing has the right analogy
&lt;/h2&gt;

&lt;p&gt;The npm trusted publishing changes are a good analogy.&lt;/p&gt;

&lt;p&gt;Modern publishing systems are moving away from long-lived tokens and toward OIDC-based workflows, independent configurations, staged publishing, malware scanning, and explicit human approval before release.&lt;/p&gt;

&lt;p&gt;That is the pattern: reduce secret sprawl, automate the boring checks, preserve the meaningful gate.&lt;/p&gt;

&lt;p&gt;Pull request approvals should move in the same direction.&lt;/p&gt;

&lt;p&gt;If AI review becomes part of the merge path, then the policy should be explicit about what the tool can approve, what it can only comment on, and where a human or separate control must remain in the loop.&lt;/p&gt;

&lt;p&gt;The mature answer is not "never let AI approve anything."&lt;/p&gt;

&lt;p&gt;The mature answer is "do not confuse convenience with independence."&lt;/p&gt;

&lt;h2&gt;
  
  
  the real risk is pretending nothing changed
&lt;/h2&gt;

&lt;p&gt;I expect some people to overreact to AI approvals.&lt;/p&gt;

&lt;p&gt;They will say no machine should ever approve a pull request. That is too simple. We already let machines block and unblock changes in many ways. Tests, linters, scanners, policy engines, deployment gates, and generated attestations all participate in software delivery.&lt;/p&gt;

&lt;p&gt;The problem is not machine participation.&lt;/p&gt;

&lt;p&gt;The problem is unclear authority.&lt;/p&gt;

&lt;p&gt;If a linter fails, we know what it means. If CodeQL flags a vulnerability, we know what kind of evidence it provides. If branch protection requires two approvals, we know the human accountability model we intended.&lt;/p&gt;

&lt;p&gt;AI approval muddies that unless we define it carefully.&lt;/p&gt;

&lt;p&gt;What does it mean for Copilot to approve?&lt;/p&gt;

&lt;p&gt;Does it mean the code is correct? No.&lt;/p&gt;

&lt;p&gt;Does it mean there are no security issues? No.&lt;/p&gt;

&lt;p&gt;Does it mean the tool found no blocking concerns within the context and policy it was allowed to use? That is closer.&lt;/p&gt;

&lt;p&gt;And if that is what it means, then the policy needs to say where that kind of evidence is strong enough to count.&lt;/p&gt;

&lt;p&gt;My bias is simple: let AI review aggressively, but let it approve conservatively.&lt;/p&gt;

&lt;p&gt;Use it to reduce noise. Use it to catch boring mistakes. Use it to summarize risk. Use it to make human review sharper.&lt;/p&gt;

&lt;p&gt;But when the approval becomes part of merge control, stop treating it as a productivity feature.&lt;/p&gt;

&lt;p&gt;Treat it as a security and governance feature.&lt;/p&gt;

&lt;p&gt;Separate the duties. Name the paths. Preserve independence. Keep the audit trail boring.&lt;/p&gt;

&lt;p&gt;Agent approvals are not inherently bad.&lt;/p&gt;

&lt;p&gt;Pretending they are just another reviewer is.&lt;/p&gt;

&lt;h2&gt;
  
  
  references
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-09-01-copilot-code-review-can-now-approve-pull-requests/" rel="noopener noreferrer"&gt;GitHub Changelog: Copilot code review can now approve pull requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-08-28-upcoming-changes-to-github-copilot-policies-and-billing/" rel="noopener noreferrer"&gt;GitHub Changelog: Upcoming changes to GitHub Copilot policies and billing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-09-02-content-exclusions-generally-available-in-copilot-app-and-cli/" rel="noopener noreferrer"&gt;GitHub Changelog: Content exclusions generally available in Copilot app and CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-09-01-set-an-expiration-date-for-individual-user-budgets/" rel="noopener noreferrer"&gt;GitHub Changelog: Set an expiration date for individual user budgets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-09-03-codeql-2-26-4-improves-github-actions-security-detections/" rel="noopener noreferrer"&gt;GitHub Changelog: CodeQL 2.26.4 improves GitHub actions security detections&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-09-03-github-actions-early-september-2026-updates/" rel="noopener noreferrer"&gt;GitHub Changelog: GitHub Actions: Early September 2026 updates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-06-26-read-only-actions-cache-for-untrusted-triggers/" rel="noopener noreferrer"&gt;GitHub Changelog: Read-only Actions cache for untrusted triggers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/changelog/2026-09-03-multiple-trusted-publishing-configurations-for-npm/" rel="noopener noreferrer"&gt;GitHub Changelog: Multiple trusted publishing configurations for npm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
    <item>
      <title>observability sinks are becoming the audit contract for AI agents</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Sun, 18 Oct 2026 10:00:20 +0000</pubDate>
      <link>https://dev.to/pvgomes/observability-sinks-are-becoming-the-audit-contract-for-ai-agents-1111</link>
      <guid>https://dev.to/pvgomes/observability-sinks-are-becoming-the-audit-contract-for-ai-agents-1111</guid>
      <description>&lt;p&gt;You built an agent that can execute trades.&lt;/p&gt;

&lt;p&gt;Now prove what it did.&lt;/p&gt;

&lt;p&gt;Not in the demo. Not in the Slack thread where everyone was excited. Not in the application log that the same agent runtime can write, redact, rotate, or accidentally forget.&lt;/p&gt;

&lt;p&gt;Prove it to the regulator.&lt;/p&gt;

&lt;p&gt;Prove which model was used, which prompt was active, which tools were called, which data was read, which policy allowed the action, which human approved the exception, which account paid for the run, and why the agent chose one path instead of another.&lt;/p&gt;

&lt;p&gt;That is the part most agent demos skip.&lt;/p&gt;

&lt;p&gt;And it is the part that will matter first in fintech, infrastructure, security, healthcare, and any company brave enough to let agents touch production.&lt;/p&gt;

&lt;p&gt;My take is simple: &lt;strong&gt;observability sinks are becoming the audit contract boundary for AI agents.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not dashboards.&lt;br&gt;
Not "we log everything."&lt;br&gt;
Not a vendor trace view inside the same hosted agent product.&lt;/p&gt;

&lt;p&gt;An operator-owned place where agent behavior is streamed, stored, verified, and governed independently from the agent runtime itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  application logs were built for a different world
&lt;/h2&gt;

&lt;p&gt;Traditional observability assumes a fairly boring relationship between code and behavior.&lt;/p&gt;

&lt;p&gt;Humans write code. The code runs. The system emits logs, metrics, and traces. When something breaks, engineers inspect the signals and reconstruct what happened.&lt;/p&gt;

&lt;p&gt;That model is still useful. It is not enough for agents.&lt;/p&gt;

&lt;p&gt;Agents are different in four annoying ways.&lt;/p&gt;

&lt;p&gt;First, the execution path is dynamic. A normal service may branch, but the shape of the branch is encoded in the program. An agent can choose a tool, inspect the result, call another tool, rewrite its own plan, ask another agent, retry with a broader query, and only then mutate state.&lt;/p&gt;

&lt;p&gt;Second, the important thing is often semantic, not mechanical. It is not enough to know that &lt;code&gt;POST /orders&lt;/code&gt; happened at 10:42. You need to know the agent believed the user had approved the order, that the risk policy returned green, that the position size was under the limit, and that no override was used.&lt;/p&gt;

&lt;p&gt;Third, hosted agents create custody problems. If the agent runs inside a vendor platform, and the only audit trail also lives inside that vendor platform, the operator has a weak story. "Trust us, our supplier has the logs" is not the same as an independent record.&lt;/p&gt;

&lt;p&gt;Fourth, agents can spend money invisibly. A bad loop can burn model tokens, cloud APIs, search calls, database queries, and human review time. Cost is no longer just a monthly dashboard problem. It is part of the runtime behavior that needs attribution.&lt;/p&gt;

&lt;p&gt;So when people say "just add tracing," I get the instinct, but it is incomplete.&lt;/p&gt;

&lt;p&gt;Tracing tells you how work flowed.&lt;/p&gt;

&lt;p&gt;An audit contract tells you what must be recorded, where it must land, who controls it, how it is verified, how long it is retained, and what happens when the agent cannot emit it.&lt;/p&gt;

&lt;p&gt;That is a different bar.&lt;/p&gt;

&lt;h2&gt;
  
  
  the sink matters more than the screenshot
&lt;/h2&gt;

&lt;p&gt;The word "sink" sounds boring because it is boring. Good.&lt;/p&gt;

&lt;p&gt;A sink is where telemetry lands: an S3 bucket, an append-only database, a data lake, an observability backend, a ledger-like event store, or a streaming system that fans out to several of those.&lt;/p&gt;

&lt;p&gt;For agent auditability, the important part is not that the sink exists. It is who owns it and what contract it enforces.&lt;/p&gt;

&lt;p&gt;If the agent runtime owns the only durable record, the agent runtime is marking its own homework.&lt;/p&gt;

&lt;p&gt;That may be fine for local experiments. It is not fine for regulated workflows.&lt;/p&gt;

&lt;p&gt;The serious version looks more like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The operator owns the sink.&lt;/li&gt;
&lt;li&gt;The agent cannot delete or rewrite events after emission.&lt;/li&gt;
&lt;li&gt;Events are forwarded in near real time, not uploaded later as a convenience.&lt;/li&gt;
&lt;li&gt;Each event carries enough structure to reconstruct the decision path.&lt;/li&gt;
&lt;li&gt;Events are signed or chained so tampering is detectable.&lt;/li&gt;
&lt;li&gt;Missing telemetry is treated as a policy failure, not a debugging inconvenience.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the mental shift: observability is not just a debugging aid anymore.&lt;/p&gt;

&lt;p&gt;For autonomous systems, observability becomes part of the permission model.&lt;/p&gt;

&lt;p&gt;An agent should not be allowed to execute a high-risk action unless it can also produce the audit events required for that action.&lt;/p&gt;

&lt;p&gt;No audit trail, no mutation.&lt;/p&gt;

&lt;p&gt;That rule sounds harsh until the first incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  event sourcing is the better metaphor
&lt;/h2&gt;

&lt;p&gt;Most logging strategies are optimized for diagnosis after a system misbehaves.&lt;/p&gt;

&lt;p&gt;Agent audit trails need to be optimized for reconstruction.&lt;/p&gt;

&lt;p&gt;That is why event sourcing is a better metaphor than logging.&lt;/p&gt;

&lt;p&gt;In an event-sourced system, the important facts are represented as a sequence of events. The current state is something you derive from the history, not something you trust by itself.&lt;/p&gt;

&lt;p&gt;That maps very naturally to agents.&lt;/p&gt;

&lt;p&gt;Instead of "the agent completed task 123," the audit stream should contain the decision history:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;task accepted&lt;/li&gt;
&lt;li&gt;identity selected&lt;/li&gt;
&lt;li&gt;policy context loaded&lt;/li&gt;
&lt;li&gt;data source queried&lt;/li&gt;
&lt;li&gt;model invoked&lt;/li&gt;
&lt;li&gt;tool call proposed&lt;/li&gt;
&lt;li&gt;tool call approved or rejected&lt;/li&gt;
&lt;li&gt;external system mutated&lt;/li&gt;
&lt;li&gt;cost attributed&lt;/li&gt;
&lt;li&gt;result verified&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of those events belong to the agent. Some belong to the control plane. Some belong to the tool gateway. Some belong to the human approval system.&lt;/p&gt;

&lt;p&gt;That is exactly why the sink should be outside the agent.&lt;/p&gt;

&lt;p&gt;The agent is one witness. It is not the court.&lt;/p&gt;

&lt;h2&gt;
  
  
  what belongs in the audit stream
&lt;/h2&gt;

&lt;p&gt;I would not try to record every token forever. That gets expensive, creepy, and often useless.&lt;/p&gt;

&lt;p&gt;But I would be strict about the events that define accountability.&lt;/p&gt;

&lt;p&gt;At minimum, for production agents, I want:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Run identity.&lt;/strong&gt; Agent id, run id, conversation id, tenant, environment, model, model provider, prompt or policy version, and the human or system that initiated the work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authority.&lt;/strong&gt; The identity used for each tool call, scopes granted, policy decision, approval id if applicable, and whether the action was read-only or mutating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision points.&lt;/strong&gt; The agent's plan changes, tool selection, rejected alternatives when available, confidence signals if used, and the reason a risky action was allowed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool I/O boundaries.&lt;/strong&gt; Not necessarily every payload in full, because privacy still matters, but enough hashes, references, schemas, and redaction markers to prove what category of data crossed the boundary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost.&lt;/strong&gt; Tokens, provider calls, cloud resources, search calls, database queries, and anything else that can become a bill. Cost attribution should not be a separate archaeology project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outcome.&lt;/strong&gt; What changed, where it changed, how it was verified, and whether a human reviewed the final result.&lt;/p&gt;

&lt;p&gt;This is not exotic. It is the same boring engineering discipline we already apply to payments, ledgers, deployments, and security-sensitive admin actions.&lt;/p&gt;

&lt;p&gt;Agents just force us to apply it earlier.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenTelemetry helps, but it is not the contract
&lt;/h2&gt;

&lt;p&gt;OpenTelemetry is probably the right default vocabulary for a lot of this work.&lt;/p&gt;

&lt;p&gt;The ecosystem is already moving toward generative AI and agent semantic conventions: model calls, tools, agent spans, conversation identifiers, token usage, and the kind of trace structure you need to see multi-step behavior.&lt;/p&gt;

&lt;p&gt;That is good.&lt;/p&gt;

&lt;p&gt;Standard naming matters because nobody wants each framework inventing a private schema for "tool call with LLM context and cost metadata."&lt;/p&gt;

&lt;p&gt;But I would be careful not to confuse a telemetry standard with an audit contract.&lt;/p&gt;

&lt;p&gt;OpenTelemetry can describe events and traces. It does not, by itself, decide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which events are mandatory before a production action&lt;/li&gt;
&lt;li&gt;which sink is authoritative&lt;/li&gt;
&lt;li&gt;whether the event stream is tamper-evident&lt;/li&gt;
&lt;li&gt;how long records must be retained&lt;/li&gt;
&lt;li&gt;which fields must be redacted or tokenized&lt;/li&gt;
&lt;li&gt;which missing span blocks the workflow&lt;/li&gt;
&lt;li&gt;who is allowed to query the evidence later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those are platform and governance decisions.&lt;/p&gt;

&lt;p&gt;The best architecture will probably use OpenTelemetry-style instrumentation for portability, then enforce stronger organization-specific rules at the sink.&lt;/p&gt;

&lt;p&gt;Common format. Operator-owned contract.&lt;/p&gt;

&lt;p&gt;That is the useful combination.&lt;/p&gt;

&lt;h2&gt;
  
  
  cost is part of the audit trail
&lt;/h2&gt;

&lt;p&gt;One underrated reason this matters: agents can spend money in ways humans do not notice until the invoice arrives.&lt;/p&gt;

&lt;p&gt;A human engineer usually has friction. They get bored. They stop. They ask someone. They go to lunch.&lt;/p&gt;

&lt;p&gt;An agent with a retry loop has none of those virtues.&lt;/p&gt;

&lt;p&gt;It can call a model hundreds of times, fan out across tools, run cloud queries, create test environments, scrape documents, invoke evaluators, and ask another agent to inspect the result.&lt;/p&gt;

&lt;p&gt;Each individual step may look small.&lt;/p&gt;

&lt;p&gt;The chain may be expensive.&lt;/p&gt;

&lt;p&gt;So the sink should not only answer "what did the agent do?"&lt;/p&gt;

&lt;p&gt;It should answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what did this run cost?&lt;/li&gt;
&lt;li&gt;which tool or model created the cost?&lt;/li&gt;
&lt;li&gt;which user, team, product, or customer should own it?&lt;/li&gt;
&lt;li&gt;which policy allowed the spend?&lt;/li&gt;
&lt;li&gt;did the spend produce a verified outcome?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the observability sink can attribute cost at the same boundary where it records action, it becomes a budget enforcement point.&lt;/p&gt;

&lt;p&gt;That is much better than discovering a token bonfire in a monthly report.&lt;/p&gt;

&lt;h2&gt;
  
  
  fintech will not accept vibes as evidence
&lt;/h2&gt;

&lt;p&gt;This is where fintech gets interesting.&lt;/p&gt;

&lt;p&gt;Financial systems already know that logs are not enough. Payments, ledgers, approvals, reconciliations, fraud reviews, access decisions, and trade workflows all need durable evidence.&lt;/p&gt;

&lt;p&gt;The moment an agent enters that world, it inherits the same expectations.&lt;/p&gt;

&lt;p&gt;If an agent drafts a customer support answer, maybe a normal trace is enough.&lt;/p&gt;

&lt;p&gt;If an agent changes a fraud rule, approves a chargeback, liquidates collateral, moves money, tunes a trading strategy, or sends data to a regulator, the story changes.&lt;/p&gt;

&lt;p&gt;The organization needs to explain the decision chain.&lt;/p&gt;

&lt;p&gt;Not because regulators are anti-AI. Because regulated businesses have always had to prove control over material decisions. AI does not remove that requirement. It makes the evidence harder to collect.&lt;/p&gt;

&lt;p&gt;The SEC has been publicly wrestling with AI and predictive analytics in investment contexts. The CFTC has reminded registered entities that AI usage does not erase existing obligations. The PRA's model risk principles already push banks toward governance, validation, controls, and accountability for models.&lt;/p&gt;

&lt;p&gt;You do not need to overclaim that every regulator has issued agent-specific audit-sink rules.&lt;/p&gt;

&lt;p&gt;They have not.&lt;/p&gt;

&lt;p&gt;The safer and more useful claim is this: regulated firms already need control, evidence, explainability, and accountability around automated decision-making. Autonomous agents increase the pressure on those existing obligations.&lt;/p&gt;

&lt;p&gt;That pressure has to land somewhere.&lt;/p&gt;

&lt;p&gt;I think it lands in the observability sink.&lt;/p&gt;

&lt;h2&gt;
  
  
  what I would build first
&lt;/h2&gt;

&lt;p&gt;I would not start with a grand "agent ledger" project.&lt;/p&gt;

&lt;p&gt;That will become a platform initiative with a steering committee and six months of schema arguments.&lt;/p&gt;

&lt;p&gt;Start with one high-risk agent workflow and make the audit boundary explicit.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an agent that opens infrastructure pull requests&lt;/li&gt;
&lt;li&gt;an agent that investigates production incidents&lt;/li&gt;
&lt;li&gt;an agent that reviews fraud cases&lt;/li&gt;
&lt;li&gt;an agent that performs cost optimization recommendations&lt;/li&gt;
&lt;li&gt;an agent that touches customer data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then define the contract.&lt;/p&gt;

&lt;p&gt;What events must exist before the agent can act?&lt;br&gt;
Which events are emitted by the runtime, the gateway, the policy engine, and the human approval tool?&lt;br&gt;
Where is the authoritative sink?&lt;br&gt;
Who can write to it?&lt;br&gt;
Who can read it?&lt;br&gt;
What gets signed?&lt;br&gt;
What gets redacted?&lt;br&gt;
What happens when emission fails?&lt;/p&gt;

&lt;p&gt;The last question is the one that separates serious systems from demos.&lt;/p&gt;

&lt;p&gt;If the sink is down, does the agent keep working?&lt;/p&gt;

&lt;p&gt;For low-risk read-only actions, maybe yes.&lt;/p&gt;

&lt;p&gt;For production mutations, financial actions, customer data export, or security-sensitive changes, I think the default should be no.&lt;/p&gt;

&lt;p&gt;Observability failure becomes control-plane failure.&lt;/p&gt;

&lt;p&gt;That is the whole point.&lt;/p&gt;

&lt;h2&gt;
  
  
  the skeptical part
&lt;/h2&gt;

&lt;p&gt;Observability sinks are not magic.&lt;/p&gt;

&lt;p&gt;They do not make a bad policy good.&lt;br&gt;
They do not prove the model reasoned correctly.&lt;br&gt;
They do not prevent prompt injection by themselves.&lt;br&gt;
They do not replace least privilege, human approvals, sandboxing, evals, rollback design, or boring access control.&lt;/p&gt;

&lt;p&gt;They also create their own risks.&lt;/p&gt;

&lt;p&gt;An audit sink can become a sensitive data swamp if teams dump full prompts, retrieved documents, customer identifiers, secrets, and model outputs into it without discipline.&lt;/p&gt;

&lt;p&gt;So the sink needs privacy engineering too: redaction, tokenization, field-level access, retention classes, and a clear distinction between evidence and hoarding.&lt;/p&gt;

&lt;p&gt;Still, I would rather have that problem than the alternative.&lt;/p&gt;

&lt;p&gt;Because the alternative is an agent that can act, spend, mutate, and coordinate with other agents while the operator has only whatever logs the runtime felt like leaving behind.&lt;/p&gt;

&lt;p&gt;That is not governance.&lt;/p&gt;

&lt;p&gt;That is optimism with timestamps.&lt;/p&gt;

&lt;h2&gt;
  
  
  the punchline
&lt;/h2&gt;

&lt;p&gt;Agents are pushing observability out of the debugging corner and into the governance layer.&lt;/p&gt;

&lt;p&gt;For normal software, logs help engineers understand what the code did.&lt;/p&gt;

&lt;p&gt;For autonomous agents, observability sinks help organizations prove what work was delegated, what authority was used, what decisions were made, what costs were incurred, and what changed as a result.&lt;/p&gt;

&lt;p&gt;That proof has to live somewhere the operator controls.&lt;/p&gt;

&lt;p&gt;It has to be structured enough to reconstruct the run.&lt;/p&gt;

&lt;p&gt;It has to be durable enough to survive an incident.&lt;/p&gt;

&lt;p&gt;And for serious workflows, it has to be mandatory enough that an agent cannot simply act first and explain later.&lt;/p&gt;

&lt;p&gt;That is why I think the next boring piece of agent infrastructure will matter a lot:&lt;/p&gt;

&lt;p&gt;your bucket, your event stream, your audit database, your retention policy, your cryptographic proof.&lt;/p&gt;

&lt;p&gt;The agent can do the work.&lt;/p&gt;

&lt;p&gt;The sink keeps it honest.&lt;/p&gt;

&lt;h2&gt;
  
  
  sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://opentelemetry.io/docs/concepts/semantic-conventions/" rel="noopener noreferrer"&gt;OpenTelemetry semantic conventions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opentelemetry.io/blog/2025/ai-agent-observability/" rel="noopener noreferrer"&gt;OpenTelemetry: AI agent observability - evolving standards and best practices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/open-telemetry/semantic-conventions-genai/blob/main/docs/gen-ai/gen-ai-agent-spans.md" rel="noopener noreferrer"&gt;OpenTelemetry GenAI agent span conventions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://martinfowler.com/eaaDev/EventSourcing.html" rel="noopener noreferrer"&gt;Martin Fowler: Event Sourcing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.honeycomb.io/use-cases/agent-observability" rel="noopener noreferrer"&gt;Honeycomb: Agentic AI observability for production agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://support.claude.com/en/articles/9970975-access-audit-logs" rel="noopener noreferrer"&gt;Claude Help Center: Access audit logs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.cloud.google.com/agent-registry/audit-logging" rel="noopener noreferrer"&gt;Google Cloud: Agent Registry audit logging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sec.gov/newsroom/speeches-statements/daly-020326-artificial-intelligence-future-investment-management" rel="noopener noreferrer"&gt;SEC: Artificial Intelligence and the Future of Investment Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.cftc.gov/PressRoom/PressReleases/9013-24" rel="noopener noreferrer"&gt;CFTC staff advisory on the use of AI by registered entities and registrants&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bankofengland.co.uk/prudential-regulation/publication/2023/may/model-risk-management-principles-for-banks-ss" rel="noopener noreferrer"&gt;Bank of England PRA: SS1/23 model risk management principles for banks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
    <item>
      <title>A vulnerability report is not a bug ticket</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Wed, 16 Sep 2026 14:00:20 +0000</pubDate>
      <link>https://dev.to/pvgomes/a-vulnerability-report-is-not-a-bug-ticket-25hg</link>
      <guid>https://dev.to/pvgomes/a-vulnerability-report-is-not-a-bug-ticket-25hg</guid>
      <description>&lt;p&gt;It is 16:47 on a Friday.&lt;/p&gt;

&lt;p&gt;The report does not arrive in the security inbox. It arrives in a public GitHub issue, or worse, in the community Slack, or a DM to whoever was last active on the repo. It is written by someone who clearly knows what they are doing. There is a payload. There is a reproduction. There is a version number, and it is the version you shipped to production last week.&lt;/p&gt;

&lt;p&gt;And it is public.&lt;/p&gt;

&lt;p&gt;By 17:05 you have three problems, not one. There is a vulnerability. There is a disclosure control failure. And there is a small group of people trying to decide, in real time, who is allowed to read the thread, who owns the fix, and whether the person who found it is going to publish on Monday regardless of what you say.&lt;/p&gt;

&lt;p&gt;That last part is not a security problem. It is an operations problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  SECURITY.md is the front door, not the process
&lt;/h2&gt;

&lt;p&gt;Most projects that "have disclosure" have a &lt;code&gt;SECURITY.md&lt;/code&gt; with an email address and a sentence about responsible disclosure. Maybe a PGP key. Maybe a 90-day quote lifted from a blog post.&lt;/p&gt;

&lt;p&gt;That is a front door. A door is not a building.&lt;/p&gt;

&lt;p&gt;CNCF published a &lt;a href="https://www.cncf.io/blog/2026/09/07/handling-vulnerability-reports-recipe-card/" rel="noopener noreferrer"&gt;handling vulnerability reports recipe card&lt;/a&gt; in September 2026 aimed exactly at small and medium projects without a security team. It is good guidance, and it is honest about scope: it covers the policy artifacts. The hard part is not the policy text. The hard part is that a policy document does not decide who gets woken up, who has write access to the private fix branch, or who signs off on the advisory wording.&lt;/p&gt;

&lt;p&gt;GitHub gives you &lt;a href="https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/about-privately-reporting-a-security-vulnerability" rel="noopener noreferrer"&gt;private vulnerability reporting&lt;/a&gt; and &lt;a href="https://docs.github.com/en/code-security/concepts/vulnerability-reporting-and-management/repository-security-advisories" rel="noopener noreferrer"&gt;repository security advisories&lt;/a&gt; with private forks, private discussion, CVE requests, and coordinated publication. OpenSSF's &lt;a href="https://github.com/ossf/wg-vulnerability-disclosures" rel="noopener noreferrer"&gt;vulnerability disclosures working group&lt;/a&gt; publishes templates and runbooks. CISA has a &lt;a href="https://www.cisa.gov/resources-tools/resources/vulnerability-disclosure-policy-template" rel="noopener noreferrer"&gt;disclosure policy template&lt;/a&gt;. FIRST has an entire &lt;a href="https://www.first.org/standards/frameworks/psirts/psirt_services_framework_v1.1" rel="noopener noreferrer"&gt;PSIRT services framework&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The tooling exists. The templates exist. And teams still improvise the moment a real report lands, because none of that tells you who owns triage at 16:47 on a Friday.&lt;/p&gt;

&lt;p&gt;My take:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a vulnerability report is not a bug ticket. It is an operational event with a clock attached.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The clock is the entire point. A bug can sit in a backlog for a quarter. A vulnerability report starts an embargo, and an embargo is a countdown that a stranger is holding.&lt;/p&gt;

&lt;h2&gt;
  
  
  the first 24 hours decide everything
&lt;/h2&gt;

&lt;p&gt;The first 24 hours determine whether this becomes engineering work or organizational panic. Panic looks like: a dozen people pulled into a call, three half-fixes started in parallel, a draft advisory circulating in a doc that is not access-controlled, and public speculation while nobody has confirmed impact.&lt;/p&gt;

&lt;p&gt;The output of the first 24 hours should be small and boring:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Acknowledged.&lt;/strong&gt; The reporter knows a human received it, and knows approximately when they will hear more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contained.&lt;/strong&gt; The report is in a private channel, not a public issue, and comments are frozen in the public place if it leaked there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Owned.&lt;/strong&gt; One named person owns the report until it closes. Not a team. A person.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classified.&lt;/strong&gt; Initial severity, affected versions, and exploitability — provisional is fine, unstated is not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled.&lt;/strong&gt; A tentative disclosure date, communicated to the reporter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you cannot produce those five things within a day, your &lt;code&gt;SECURITY.md&lt;/code&gt; is marketing.&lt;/p&gt;

&lt;h2&gt;
  
  
  the intake contract
&lt;/h2&gt;

&lt;p&gt;Intake is where most processes quietly fail, because the reporting path is whatever channel the reporter happens to find. You cannot fix that by asking nicely. You fix it by making the intended path obviously the best one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One canonical intake.&lt;/strong&gt; Private vulnerability reporting enabled on the repo, plus a monitored security address for people who do not want to use GitHub. Both routed to the same place.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Say what happens next on the page.&lt;/strong&gt; "We acknowledge within 3 business days, we triage within 5, we will tell you our severity assessment and target disclosure window." A reporter who knows the timeline argues less about the timeline.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Require evidence, not drama.&lt;/strong&gt; Affected version or commit, component, reproduction steps or PoC, observed impact, and whether the reporter has shared it anywhere else. That last question matters more than people expect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Restrict the audience from the start.&lt;/strong&gt; A security alias that forwards to a 40-person engineering mailing list is not a private channel. It is a leak with extra steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assume reports will land in public anyway.&lt;/strong&gt; Someone will file the issue publicly. Have a canned response that moves the conversation without confirming exploitability, and a moderator who can lock the thread fast.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The intake contract is not about gatekeeping researchers. It is about making sure the first person who reads the report is the right person.&lt;/p&gt;

&lt;h2&gt;
  
  
  the triage contract
&lt;/h2&gt;

&lt;p&gt;Triage is where "vulnerability" and "bug" get separated, and it is the step AI is currently making harder.&lt;/p&gt;

&lt;p&gt;A working triage decision answers five questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Is this a vulnerability or a robustness bug?&lt;/strong&gt; A crash on malformed input is not automatically a security issue. An auth bypass is, even if the user must already be authenticated.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What is the impact if exploited?&lt;/strong&gt; Confidentiality, integrity, availability, or privilege boundary crossed. Be specific about which boundary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How exploitable is it really?&lt;/strong&gt; Does it require a local attacker, an authenticated tenant, a non-default configuration, or a specific race window? Severity without exploitability context is a number nobody can act on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which versions are affected, and which are supported?&lt;/strong&gt; Fixing an unsupported version is a gift, not an obligation. Say so early.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What does the reporter hear, and when?&lt;/strong&gt; A triaged report always gets a reply with the assessment, even when the assessment is "not a vulnerability, here is why."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point is the one teams skip, and it is the cause of most hostile disclosures. Researchers escalate when they are ignored, not when they are told no.&lt;/p&gt;

&lt;h2&gt;
  
  
  the embargo contract
&lt;/h2&gt;

&lt;p&gt;An embargo is not secrecy. It is a coordinated agreement with a deadline, and it should have the smallest useful group of people inside it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smallest useful group.&lt;/strong&gt; Everyone who must act, nobody who is merely curious. Product managers who are not shipping a mitigation do not need the PoC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the timeline down.&lt;/strong&gt; Report date, triage date, fix target, disclosure date. Everyone in the thread can see the same clock.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Know what confidentiality means in practice.&lt;/strong&gt; Private advisory or private fork instead of a public PR. No screenshots of the exploit in a shared doc. No vague "we have an issue" in the incident channel that turns into a game of twenty questions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decide the default window before you are under pressure.&lt;/strong&gt; 90 days is a convention, not a rule. Some projects use 7 days for actively exploited issues and 30 for everything else. What matters is that the number is written down and defensible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handle disagreement explicitly.&lt;/strong&gt; If the reporter wants to publish early, or you need an extension, that is a negotiation with a stated reason — not silence and not a legal threat.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The embargo ends when the fix is available, or when the deadline arrives and it is not. Both are allowed. Pretending the deadline does not exist is how you end up reading about your own bug on a security news site with no patch ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  the fix and release contract
&lt;/h2&gt;

&lt;p&gt;This is where disclosure becomes ordinary engineering, with two differences: the branch is private, and the communication is public.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Private fix path.&lt;/strong&gt; Private fork or advisory branch, minimal diff, and reviewers who were explicitly added. No drive-by refactors while the clock runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focused review.&lt;/strong&gt; Security fixes get a second pair of eyes from someone who can evaluate the boundary being crossed, not just the code style. Reviewers outside the embargo circle do not get the context, and that is fine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test evidence.&lt;/strong&gt; A regression test that fails before the fix and passes after. If you cannot write it, say why in the advisory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixed version plus mitigation.&lt;/strong&gt; Not every team can upgrade immediately. Backports, config workarounds, feature flags, and WAF rules are all legitimate. An advisory that says "upgrade" and nothing else gets ignored by everyone who cannot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advisory, CVE, and user notification.&lt;/strong&gt; GHSA draft, CVE requested when the ecosystem needs it, severity with the exploitability caveats from triage, affected versions, credits to the reporter, and a link to the fixed release.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tell your users where they actually look.&lt;/strong&gt; Release notes, a mailing list, a security page, an RSS feed, a Slack or Discord announcement. Publishing the advisory is not notifying users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The measure of a good fix-and-release contract is the person running your software in production who finds out what to do without reading a research write-up.&lt;/p&gt;

&lt;h2&gt;
  
  
  the AI wrinkle
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://www.cncf.io/blog/2026/04/16/the-ai-driven-shift-in-vulnerability-discovery-what-maintainers-and-bug-finders-need-to-know/" rel="noopener noreferrer"&gt;AI-driven shift in vulnerability discovery&lt;/a&gt; is real, and it cuts both ways.&lt;/p&gt;

&lt;p&gt;More reports are now generated by models pointed at codebases, and some of them are genuinely good: real bugs, real reproduction steps, reachable paths that a human reviewer missed. Others are confident, well-formatted, plausible-sounding findings with no reachable impact — a stack trace, an invented threat model, and a severity score chosen for drama.&lt;/p&gt;

&lt;p&gt;Two things change:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Triage volume goes up without triage quality going up with it.&lt;/strong&gt; A process that assumed a few thoughtful reports a month now gets a stream of synthetically detailed ones. That is fine as long as triage is evidence-based: does the repro actually work against a supported version? Is the code path reachable in a default deployment? Is the described impact real, or does it assume an attacker who already has the access the finding claims to escalate?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;False positives get expensive because they look like real work.&lt;/strong&gt; Every convincing-but-wrong report costs an engineer a day. Track that cost. If a share of your inbound reports never reproduce, that is a process input, not an annoyance — it tells you where your intake needs a reproduction requirement enforced harder.&lt;/p&gt;

&lt;p&gt;The upside is equally real. AI-assisted review is genuinely good at finding the class of bug that humans skim past: missing authorization checks, unsafe deserialization, off-by-one in parsing, weak validation at boundaries. The maintainers who benefit are the ones whose triage process can absorb a higher volume without lowering the bar.&lt;/p&gt;

&lt;p&gt;Which is the whole point of an operations contract. It is the thing that lets you say "this is credible" or "this is not" quickly, and move on either way.&lt;/p&gt;

&lt;h2&gt;
  
  
  a practical checklist for maintainers
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;code&gt;SECURITY.md&lt;/code&gt; points to one canonical private intake channel and states response timelines.&lt;/li&gt;
&lt;li&gt;[ ] Private vulnerability reporting is enabled on every actively maintained repo.&lt;/li&gt;
&lt;li&gt;[ ] One named owner for triage, with a documented backup.&lt;/li&gt;
&lt;li&gt;[ ] A severity assessment template: impact, exploitability, affected versions, default-config reachability.&lt;/li&gt;
&lt;li&gt;[ ] A written disclosure window with defaults and an escalation path for active exploitation.&lt;/li&gt;
&lt;li&gt;[ ] An embargo list discipline: smallest group, audited access, no public forks or PRs.&lt;/li&gt;
&lt;li&gt;[ ] A private fix procedure: advisory branch, focused reviewers, regression test required.&lt;/li&gt;
&lt;li&gt;[ ] A release procedure that ships the fix, the advisory, the CVE, the mitigation, and the notification.&lt;/li&gt;
&lt;li&gt;[ ] A public-leak playbook: canned response, thread lock, move to private, no confirmation of exploitability.&lt;/li&gt;
&lt;li&gt;[ ] Credit and thank reporters, including the ones who file a false positive in good faith.&lt;/li&gt;
&lt;li&gt;[ ] A quarterly game day: walk a synthetic report through the whole path and time it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this requires a security team. It requires someone to write down the decision that would otherwise be made by five people in a panic under time pressure.&lt;/p&gt;

&lt;p&gt;A bug ticket asks "what should we build next." A vulnerability report asks "what do we do in the next 24 hours, and who decides." Different queues, different clocks, different consequences.&lt;/p&gt;

&lt;p&gt;Write the contract before the reporter finds the door.&lt;/p&gt;




&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;CNCF/TAG Security: &lt;a href="https://www.cncf.io/blog/2026/09/07/handling-vulnerability-reports-recipe-card/" rel="noopener noreferrer"&gt;Handling vulnerability reports — recipe card&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CNCF: &lt;a href="https://www.cncf.io/blog/2026/04/16/the-ai-driven-shift-in-vulnerability-discovery-what-maintainers-and-bug-finders-need-to-know/" rel="noopener noreferrer"&gt;The AI-driven shift in vulnerability discovery&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OpenSSF: &lt;a href="https://github.com/ossf/wg-vulnerability-disclosures" rel="noopener noreferrer"&gt;Vulnerability Disclosures Working Group repo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OpenSSF: &lt;a href="https://openssf.org/groups/vulnerability-disclosures/" rel="noopener noreferrer"&gt;Vulnerability Disclosures group overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub Docs: &lt;a href="https://docs.github.com/en/code-security/concepts/vulnerability-reporting-and-management/repository-security-advisories" rel="noopener noreferrer"&gt;Repository security advisories&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub Docs: &lt;a href="https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/about-privately-reporting-a-security-vulnerability" rel="noopener noreferrer"&gt;About privately reporting a security vulnerability&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CISA: &lt;a href="https://www.cisa.gov/resources-tools/resources/vulnerability-disclosure-policy-template" rel="noopener noreferrer"&gt;Vulnerability disclosure policy template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;FIRST: &lt;a href="https://www.first.org/standards/frameworks/psirts/psirt_services_framework_v1.1" rel="noopener noreferrer"&gt;PSIRT Services Framework v1.1&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
    <item>
      <title>the revolut breach is an automation boundary problem</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Tue, 15 Sep 2026 16:47:45 +0000</pubDate>
      <link>https://dev.to/pvgomes/the-revolut-breach-is-an-automation-boundary-problem-1kje</link>
      <guid>https://dev.to/pvgomes/the-revolut-breach-is-an-automation-boundary-problem-1kje</guid>
      <description>&lt;p&gt;Revolut did not get hacked.&lt;/p&gt;

&lt;p&gt;Someone asked for customer data from an email that looked like it came from a government agency, and Revolut sent it.&lt;/p&gt;

&lt;p&gt;That is the whole story, and it is worse than a hack.&lt;/p&gt;

&lt;h2&gt;
  
  
  what actually happened
&lt;/h2&gt;

&lt;p&gt;Revolut confirmed it disclosed sensitive customer data to fraudsters who submitted fraudulent information requests from a legitimate government agency email domain. In its own words, it identified "a sophisticated external impersonation scam where an unauthorised third party utilised a legitimate government agency domain email to submit fraudulent requests for information."&lt;/p&gt;

&lt;p&gt;The exposed data is the kind that cannot be reissued: passport and driver's licence copies, verification selfies, dates of birth, postal and email addresses, phone numbers, bank statements, IBANs, withdrawal records, and transaction histories including Bitcoin activity.&lt;/p&gt;

&lt;p&gt;Revolut says a limited number of customers were affected, that it notified them directly, and that its systems and customer funds were not compromised. On detection it blocked the sender and alerted the government agency, law enforcement, data protection, and financial regulators.&lt;/p&gt;

&lt;p&gt;The attackers appear to have gone after high net worth individuals, many of them in crypto, and an extortion payment was reportedly demanded.&lt;/p&gt;

&lt;p&gt;None of this is new in shape. Researchers linked a wave of similar incidents in 2021 and 2022 to the Lapsus$ group, which used compromised law enforcement accounts and forged emergency data requests to pull data out of Apple, Meta, and Discord. The FBI issued an alert in 2024 about fraudulent emergency data requests, noting a growing market on criminal forums for access to compromised email accounts specifically to send them.&lt;/p&gt;

&lt;p&gt;So the pattern is documented, the tactic is known, and it still worked.&lt;/p&gt;

&lt;h2&gt;
  
  
  the weak link was identity, not cryptography
&lt;/h2&gt;

&lt;p&gt;Everything in that pipeline probably worked exactly as designed. TLS terminated correctly. The domain authenticated. The ticket was created, the approval probably existed, the audit log was written.&lt;/p&gt;

&lt;p&gt;None of that answers the only question that matters: is the human on the other end who they claim to be?&lt;/p&gt;

&lt;p&gt;Domain authentication proves a mail server, not a person. SPF, DKIM, and DMARC tell you the message really came from that domain. They tell you nothing about who composed it, whether the mailbox is compromised, or whether an insider sold access to it. A valid domain is a weak signal dressed up as a strong one, because it is the only signal most teams look at.&lt;/p&gt;

&lt;p&gt;The attacker did not defeat Revolut's security. They used the fact that the request was boring enough to be processed and official enough to be trusted.&lt;/p&gt;

&lt;h2&gt;
  
  
  your security ends where your process begins
&lt;/h2&gt;

&lt;p&gt;Every company has workflows that make decisions based on an external identity claim. A request from a regulator. A vendor onboarding email. A "support" phone call. A bank details change form with a letterhead attached. A legal letter asking for records.&lt;/p&gt;

&lt;p&gt;Those dependencies are not failures by themselves. You cannot verify the world. But they are the boundary of your security model, and most teams have never drawn that boundary anywhere.&lt;/p&gt;

&lt;p&gt;Here is the exercise that matters, and it is not a security tool purchase:&lt;/p&gt;

&lt;p&gt;List every automated workflow that can be triggered by someone outside the company. Then mark, for each one, whether the trigger's identity is verified by you or merely asserted by them.&lt;/p&gt;

&lt;p&gt;Asserted identity plus automation equals a breach waiting for a plausible email.&lt;/p&gt;

&lt;p&gt;That single column usually explains incidents like this better than any threat model.&lt;/p&gt;

&lt;h2&gt;
  
  
  the channels we never treated as engineering
&lt;/h2&gt;

&lt;p&gt;Look at the asymmetry in how we treat interfaces.&lt;/p&gt;

&lt;p&gt;An API gets tokens, scopes, mTLS, network boundaries, rotation, rate limits, and a team that looks at it every day. If someone changes an API integration, it goes through review.&lt;/p&gt;

&lt;p&gt;Email and phone calls got treated as plain data transfer. Not engineering. Just the way humans talk to companies.&lt;/p&gt;

&lt;p&gt;But the moment an email can trigger a workflow that exports identity documents, email is not data transfer anymore. It is an unauthenticated control plane with a human-shaped interface. It is also the most automated channel in the company, because we wired inboxes into ticketing systems, compliance queues, and now AI agents that triage and summarise.&lt;/p&gt;

&lt;p&gt;We hardened the channel we already understood and left the one that arrives as text.&lt;/p&gt;

&lt;p&gt;That is the structural finding in this incident, and it applies far beyond Revolut.&lt;/p&gt;

&lt;h2&gt;
  
  
  guardrails, not reminders
&lt;/h2&gt;

&lt;p&gt;If the root cause is a workflow that trusts an unverified channel, then "be more careful" is not a control. These are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tier by reversibility, not by category.&lt;/strong&gt; If an action cannot be undone, it should never run fully automated. Handing over passport scans, selfies, and transaction histories is irreversible. That step needs a human with a name attached to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Separate routine from exceptional, and default the exceptional path to human.&lt;/strong&gt; Automate the common case if you must. Anything unusual becomes a break-glass path with named approvers. Make "unusual" a computable property: new requester, broader data scope than previous requests, unusual volume, unusual urgency, unusual time of day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify out of band, always.&lt;/strong&gt; Call the agency on a number you already had, not one from the email. Use a portal with mutual authentication. If you must accept email, require signed requests with keys exchanged out of band. "The domain looked right" is not verification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use AI to screen, not to decide.&lt;/strong&gt; Models are genuinely good at the anomaly detection humans skip under deadline pressure: pressure language, a request much broader than the last ten, first-time contact, mismatched signatures, formatting that does not match the agency's usual output. Let AI raise the flag and route to a human. Never let it be the final approver for an irreversible disclosure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cap the blast radius structurally.&lt;/strong&gt; Ask why one request can return passports, selfies, statements, IBANs, and crypto transaction history together. Separate stores, shorter retention on biometrics, per-request record limits, and alerts on bulk document export turn a catastrophe into an inconvenience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Log decisions as data.&lt;/strong&gt; Who asked, what was disclosed, who approved, and on what evidence. If you cannot reconstruct that in an hour, you cannot answer a regulator in a week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rehearse the manual path.&lt;/strong&gt; An untested review process becomes a rubber stamp the first time a legal deadline meets a tired engineer.&lt;/p&gt;

&lt;h2&gt;
  
  
  is revolut the villain here
&lt;/h2&gt;

&lt;p&gt;Partly, and it is fair to say so. They owned the workflow, and the workflow handed over documents.&lt;/p&gt;

&lt;p&gt;But look at what they did not own. The government's email domain. The agency's inability to be impersonated. And the assumption, shared across the industry, that a request arriving through an official channel is an official request.&lt;/p&gt;

&lt;p&gt;If a legitimate domain can be used to request identity documents, and nobody in the loop is required to verify the requester, then every fintech running the same compliance process has the same exposure. Revolut is the one that got the email. It is not the only one that would have answered it.&lt;/p&gt;

&lt;p&gt;Regulators have a part to play too. Lawful data requests should travel over authenticated channels: signed requests, registered endpoints, mutual TLS, an auditable registry of who is authorised to ask. Until that exists, companies are expected to be polite, fast, and legally compliant over a channel that proves nothing. That is a bad deal, and it is being paid for by customers whose passports are now circulating.&lt;/p&gt;

&lt;h2&gt;
  
  
  what to do on monday
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Inventory every automated workflow that a third party can trigger.&lt;/li&gt;
&lt;li&gt;Mark each trigger as verified or merely asserted.&lt;/li&gt;
&lt;li&gt;Remove full automation from exceptional and irreversible paths.&lt;/li&gt;
&lt;li&gt;Add out-of-band verification for any disclosure of identity documents.&lt;/li&gt;
&lt;li&gt;Put AI in the screening layer, with a human on the approval.&lt;/li&gt;
&lt;li&gt;Alert on bulk access to documents, selfies, and transaction history.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The lesson is not that Revolut trusted an email. The lesson is that a whole industry automated a channel that was never designed to prove identity, and then treated the resulting trust as a security control.&lt;/p&gt;

&lt;p&gt;Fix the boundary first. Then automate.&lt;/p&gt;

&lt;h2&gt;
  
  
  sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://therecord.media/revolut-scam-crypto-impersonation" rel="noopener noreferrer"&gt;The Record: Revolut handed customer data to fraudsters using government email account&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bleepingcomputer.com/news/security/revolut-discloses-data-breach-exposing-financial-info-passports/" rel="noopener noreferrer"&gt;BleepingComputer: Revolut discloses data breach exposing financial info, passports&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.malwarebytes.com/blog/news/2026/09/revolut-gave-customer-ids-and-financial-data-to-a-government-impostor" rel="noopener noreferrer"&gt;Malwarebytes: Revolut gave customer IDs and financial data to a government impostor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.forbes.com/sites/boazsobrado/2026/09/15/revolut-shock-fake-government-email-leaks-passports-bitcoin-77200/" rel="noopener noreferrer"&gt;Forbes: Revolut shock, fake government email leaks passports and Bitcoin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ic3.gov/CSA/2024/241104.pdf" rel="noopener noreferrer"&gt;FBI IC3: Cyber criminals use compromised email accounts to submit fraudulent emergency data requests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
    <item>
      <title>post-quantum tls is a platform migration, not a crypto project</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Tue, 15 Sep 2026 15:00:18 +0000</pubDate>
      <link>https://dev.to/pvgomes/post-quantum-tls-is-a-platform-migration-not-a-crypto-project-50df</link>
      <guid>https://dev.to/pvgomes/post-quantum-tls-is-a-platform-migration-not-a-crypto-project-50df</guid>
      <description>&lt;p&gt;Every few months someone asks me when quantum computers will break RSA.&lt;/p&gt;

&lt;p&gt;I have stopped answering that question, because it is not the question engineering teams actually have.&lt;/p&gt;

&lt;p&gt;The question they have is much less glamorous: do we know which of our services, SDKs, middleboxes, payment integrations, and certificate workflows will tolerate a bigger handshake, a hybrid key exchange, and eventually post-quantum signatures? Most teams cannot answer that today. And 2026 is the year the cloud providers started answering it for them, by changing the defaults.&lt;/p&gt;

&lt;p&gt;That is the whole story. The quantum timeline is a distraction. The migration is already arriving through the boring doors: managed TLS endpoints, SDK defaults, CDN edge configuration, OS crypto libraries, and certificate tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  the narrow technical shift
&lt;/h2&gt;

&lt;p&gt;Strip away the hype and the change is small and specific.&lt;/p&gt;

&lt;p&gt;TLS 1.3 key exchange is currently dominated by X25519, an elliptic-curve Diffie-Hellman variant. It is fast, small, and well understood. The post-quantum concern is not that someone recorded your traffic and can decrypt it now. It is that a future quantum computer could decrypt recorded traffic later, which is exactly why anything with a long confidentiality lifetime, like a banking session log or a signed document, gets uncomfortable first.&lt;/p&gt;

&lt;p&gt;The industry response was never "replace X25519 with something quantum-safe." It was hybrid: run the classical curve and the post-quantum key encapsulation together, and combine the results. If either holds, the session holds. That is what ML-KEM (FIPS 203, the standardized descendant of CRYSTALS-Kyber) provides, and it is why the IETF draft on ML-KEM for TLS 1.3 exists in the first place.&lt;/p&gt;

&lt;p&gt;The practical consequence is size. A hybrid key share is much larger than an X25519 key share. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bigger ClientHello messages&lt;/li&gt;
&lt;li&gt;more bytes before the handshake completes&lt;/li&gt;
&lt;li&gt;more chances to hit fragmentation, MTU limits, or middleboxes that "helpfully" drop what they do not recognize&lt;/li&gt;
&lt;li&gt;more chances for an old client to negotiate a fallback group and nobody notice&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here is the part people conflate: key exchange and signatures are different problems with different timelines. ML-KEM protects the session key. Post-quantum signatures and how they land in certificates and code signing is a separate migration with its own compatibility and trust-chain pain. You can ship the first without having solved the second, and you probably should, because the first is already being turned on for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  what changed in 2026
&lt;/h2&gt;

&lt;p&gt;This stopped being a standards-track slide deck this year.&lt;/p&gt;

&lt;p&gt;AWS shipped ML-KEM hybrid post-quantum TLS support across KMS, ACM, and Secrets Manager, and it is explicit that the older CRYSTALS-Kyber support will be removed across AWS service endpoints in 2026. That second sentence is the one to underline. This is not an opt-in curiosity anymore. It is a controlled API surface with a deprecation calendar attached.&lt;/p&gt;

&lt;p&gt;Cloudflare documents post-quantum support for edge-to-origin TLS, including X25519MLKEM768 for key agreement and ML-DSA for origin authentication, with clear notes about where it is supported and where it is constrained. Microsoft shipped Windows platform support for ML-KEM hybrid TLS groups and is openly talking about an accelerated migration path for critical products and services toward 2029. The IETF draft for ML-KEM in TLS 1.3 is active.&lt;/p&gt;

&lt;p&gt;And then there is the measurement reality. A June 2026 measurement paper looking at post-quantum readiness across more than 32,000 domains found the internet is not uniformly ready, with particular lag around banking and government TLS 1.2 endpoints and post-quantum certificate adoption. I find that more useful than any roadmap slide, because it says the failure modes will be uneven and depend on what your specific clients do.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhzgu3hiae5nlit5zn7l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhzgu3hiae5nlit5zn7l.gif" alt="this is fine" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  translate it into platform work
&lt;/h2&gt;

&lt;p&gt;Here is where I push back on how most teams are framing this.&lt;/p&gt;

&lt;p&gt;If PQC lives only in a security-owned ticket, it will get treated as a cryptography review that produces a PDF and no changes. That is a mistake. The actual work is platform work, and it looks a lot like every other platform migration you have done badly before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inventory your outbound clients and TLS stacks.&lt;/strong&gt; Not your externally facing load balancers, which are usually the easy part, but everything that makes an outbound TLS connection. Application runtimes, language crypto libraries, JDK versions, Go and Rust toolchains, database drivers, message bus clients, cron jobs, batch exports, and the one internal tool that has not been rebuilt since a migration ago. Different stacks gain hybrid group support at different times, and some old ones never will.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test service-to-service paths end to end.&lt;/strong&gt; A handshake does not happen between two applications. It happens through whatever is in the middle: proxies, API gateways, service meshes with their own TLS origination, CDNs, WAFs, egress filters, and vendor middleboxes that terminate and re-establish TLS. Those are where the surprises live. Payment and fintech integrations are the highest-stakes version of this, because a partner that pins groups, inspects traffic, or terminates in something old will fail in a way that looks like "the vendor is down."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watch the right signals.&lt;/strong&gt; This migration is observable, which is the only good news in the story. Track negotiated group, not just protocol version. Track handshake size and handshake latency, because hybrid key exchange changes both. Track fallback and retry counts, because a silent fall back to a classical group is the most likely failure mode and it will look like success unless you instrument it. Track TLS error rates by client version and by dependency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Split certificates and code signing from key exchange.&lt;/strong&gt; Do not let an ML-KEM rollout turn into an ML-DSA certificate plan. Hybrid key exchange is mostly a library-and-config change. Post-quantum certificates and code signing involve CA support, trust stores, chain sizes, and signing infrastructure that your build pipeline may not tolerate yet. Separate owners, separate timelines, separate proof.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not hand it to security alone.&lt;/strong&gt; Security should define the standard and the target state. Platform should own the inventory, the rollout mechanics, the fallback policy, and the observability. Application teams own their own clients. If nobody owns the list of things that must still work, the list will be incomplete at exactly the wrong moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  "turn it on" is not a strategy
&lt;/h2&gt;

&lt;p&gt;My biggest skepticism about how this is being sold is the implied simplicity. Enable hybrid groups, prefer PQC, done.&lt;/p&gt;

&lt;p&gt;That is not a strategy, because it cannot answer three questions:&lt;/p&gt;

&lt;p&gt;What actually negotiated? If you cannot show, per path, which group was used, you do not know whether you are post-quantum or whether a proxy quietly negotiated something classical on your behalf.&lt;/p&gt;

&lt;p&gt;What fell back, and why? Fallback is not automatically a failure, but an unobserved fallback is. Browsers and clients will happily downgrade. If you are not measuring it, you are guessing.&lt;/p&gt;

&lt;p&gt;What broke? Bigger handshakes hit real constraints: MTU and fragmentation, connection setup latency budgets, throughput on high-connection-count services, and any queue or timeout that was tuned against a smaller handshake. You will find these in a canary, or you will find them in production.&lt;/p&gt;

&lt;p&gt;A migration you cannot observe is a migration you cannot finish. You will end up with a partial rollout, a permanent exception list, and a security posture that only exists on the diagram.&lt;/p&gt;

&lt;h2&gt;
  
  
  a small checklist to start without panic
&lt;/h2&gt;

&lt;p&gt;You do not need to rewrite anything this quarter. You need to know things you currently do not know.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;List every TLS client you operate, with the runtime and crypto library version behind each one.&lt;/li&gt;
&lt;li&gt;Pick three paths: one internal service-to-service, one through a proxy or mesh, one to an external partner or payment integration.&lt;/li&gt;
&lt;li&gt;Turn on hybrid key exchange in a non-production environment and capture what negotiated, what fell back, and how big the handshake got.&lt;/li&gt;
&lt;li&gt;Add negotiated group and handshake metrics to your existing TLS observability before you roll anything out.&lt;/li&gt;
&lt;li&gt;Write down your fallback policy explicitly: are silent classical fallbacks acceptable, and for how long?&lt;/li&gt;
&lt;li&gt;Track the AWS CRYSTALS-Kyber removal timeline and any provider deprecation notices for the endpoints you depend on.&lt;/li&gt;
&lt;li&gt;Keep certificate and code-signing PQC work in a separate track with its own owner.&lt;/li&gt;
&lt;li&gt;Give the whole thing a name, an owner, and a date. A migration without an owner is a rumor.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this requires predicting quantum computing timelines. It requires knowing your own system, which is the same work that makes every other migration survivable.&lt;/p&gt;

&lt;p&gt;The teams that treat post-quantum TLS as a platform inventory problem will barely notice when the defaults flip. The teams that wait for the cryptography debate to resolve will discover, under pressure, that the change already shipped in a dependency they do not control.&lt;/p&gt;

&lt;h2&gt;
  
  
  sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/security/ml-kem-post-quantum-tls-now-supported-in-aws-kms-acm-and-secrets-manager/" rel="noopener noreferrer"&gt;ML-KEM post-quantum TLS now supported in AWS KMS, ACM, and Secrets Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/kms/latest/developerguide/pqtls.html" rel="noopener noreferrer"&gt;AWS KMS post-quantum TLS client configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/ssl/post-quantum-cryptography/" rel="noopener noreferrer"&gt;Cloudflare post-quantum cryptography documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/ssl/post-quantum-cryptography/pqc-to-origin/" rel="noopener noreferrer"&gt;Cloudflare PQC to origin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcommunity.microsoft.com/blog/microsoft-security-blog/new-windows-features-to-secure-today%E2%80%99s-data-in-a-post-quantum-world/4523370" rel="noopener noreferrer"&gt;New Windows features to secure today's data in a post-quantum world&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/draft-ietf-tls-mlkem/" rel="noopener noreferrer"&gt;IETF draft: ML-KEM for TLS 1.3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2606.16473" rel="noopener noreferrer"&gt;Measurement of post-quantum readiness across the web (arXiv)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
    <item>
      <title>post-quantum tls is a platform migration, not a crypto project</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Tue, 15 Sep 2026 14:00:24 +0000</pubDate>
      <link>https://dev.to/pvgomes/post-quantum-tls-is-a-platform-migration-not-a-crypto-project-1iek</link>
      <guid>https://dev.to/pvgomes/post-quantum-tls-is-a-platform-migration-not-a-crypto-project-1iek</guid>
      <description>&lt;p&gt;Every few months someone asks me when quantum computers will break RSA.&lt;/p&gt;

&lt;p&gt;I have stopped answering that question, because it is not the question engineering teams actually have.&lt;/p&gt;

&lt;p&gt;The question they have is much less glamorous: do we know which of our services, SDKs, middleboxes, payment integrations, and certificate workflows will tolerate a bigger handshake, a hybrid key exchange, and eventually post-quantum signatures? Most teams cannot answer that today. And 2026 is the year the cloud providers started answering it for them, by changing the defaults.&lt;/p&gt;

&lt;p&gt;That is the whole story. The quantum timeline is a distraction. The migration is already arriving through the boring doors: managed TLS endpoints, SDK defaults, CDN edge configuration, OS crypto libraries, and certificate tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  the narrow technical shift
&lt;/h2&gt;

&lt;p&gt;Strip away the hype and the change is small and specific.&lt;/p&gt;

&lt;p&gt;TLS 1.3 key exchange is currently dominated by X25519, an elliptic-curve Diffie-Hellman variant. It is fast, small, and well understood. The post-quantum concern is not that someone recorded your traffic and can decrypt it now. It is that a future quantum computer could decrypt recorded traffic later, which is exactly why anything with a long confidentiality lifetime, like a banking session log or a signed document, gets uncomfortable first.&lt;/p&gt;

&lt;p&gt;The industry response was never "replace X25519 with something quantum-safe." It was hybrid: run the classical curve and the post-quantum key encapsulation together, and combine the results. If either holds, the session holds. That is what ML-KEM (FIPS 203, the standardized descendant of CRYSTALS-Kyber) provides, and it is why the IETF draft on ML-KEM for TLS 1.3 exists in the first place.&lt;/p&gt;

&lt;p&gt;The practical consequence is size. A hybrid key share is much larger than an X25519 key share. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bigger ClientHello messages&lt;/li&gt;
&lt;li&gt;more bytes before the handshake completes&lt;/li&gt;
&lt;li&gt;more chances to hit fragmentation, MTU limits, or middleboxes that "helpfully" drop what they do not recognize&lt;/li&gt;
&lt;li&gt;more chances for an old client to negotiate a fallback group and nobody notice&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here is the part people conflate: key exchange and signatures are different problems with different timelines. ML-KEM protects the session key. Post-quantum signatures and how they land in certificates and code signing is a separate migration with its own compatibility and trust-chain pain. You can ship the first without having solved the second, and you probably should, because the first is already being turned on for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  what changed in 2026
&lt;/h2&gt;

&lt;p&gt;This stopped being a standards-track slide deck this year.&lt;/p&gt;

&lt;p&gt;AWS shipped ML-KEM hybrid post-quantum TLS support across KMS, ACM, and Secrets Manager, and it is explicit that the older CRYSTALS-Kyber support will be removed across AWS service endpoints in 2026. That second sentence is the one to underline. This is not an opt-in curiosity anymore. It is a controlled API surface with a deprecation calendar attached.&lt;/p&gt;

&lt;p&gt;Cloudflare documents post-quantum support for edge-to-origin TLS, including X25519MLKEM768 for key agreement and ML-DSA for origin authentication, with clear notes about where it is supported and where it is constrained. Microsoft shipped Windows platform support for ML-KEM hybrid TLS groups and is openly talking about an accelerated migration path for critical products and services toward 2029. The IETF draft for ML-KEM in TLS 1.3 is active.&lt;/p&gt;

&lt;p&gt;And then there is the measurement reality. A June 2026 measurement paper looking at post-quantum readiness across more than 32,000 domains found the internet is not uniformly ready, with particular lag around banking and government TLS 1.2 endpoints and post-quantum certificate adoption. I find that more useful than any roadmap slide, because it says the failure modes will be uneven and depend on what your specific clients do.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhzgu3hiae5nlit5zn7l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhzgu3hiae5nlit5zn7l.gif" alt="this is fine" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  translate it into platform work
&lt;/h2&gt;

&lt;p&gt;Here is where I push back on how most teams are framing this.&lt;/p&gt;

&lt;p&gt;If PQC lives only in a security-owned ticket, it will get treated as a cryptography review that produces a PDF and no changes. That is a mistake. The actual work is platform work, and it looks a lot like every other platform migration you have done badly before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inventory your outbound clients and TLS stacks.&lt;/strong&gt; Not your externally facing load balancers, which are usually the easy part, but everything that makes an outbound TLS connection. Application runtimes, language crypto libraries, JDK versions, Go and Rust toolchains, database drivers, message bus clients, cron jobs, batch exports, and the one internal tool that has not been rebuilt since a migration ago. Different stacks gain hybrid group support at different times, and some old ones never will.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test service-to-service paths end to end.&lt;/strong&gt; A handshake does not happen between two applications. It happens through whatever is in the middle: proxies, API gateways, service meshes with their own TLS origination, CDNs, WAFs, egress filters, and vendor middleboxes that terminate and re-establish TLS. Those are where the surprises live. Payment and fintech integrations are the highest-stakes version of this, because a partner that pins groups, inspects traffic, or terminates in something old will fail in a way that looks like "the vendor is down."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watch the right signals.&lt;/strong&gt; This migration is observable, which is the only good news in the story. Track negotiated group, not just protocol version. Track handshake size and handshake latency, because hybrid key exchange changes both. Track fallback and retry counts, because a silent fall back to a classical group is the most likely failure mode and it will look like success unless you instrument it. Track TLS error rates by client version and by dependency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Split certificates and code signing from key exchange.&lt;/strong&gt; Do not let an ML-KEM rollout turn into an ML-DSA certificate plan. Hybrid key exchange is mostly a library-and-config change. Post-quantum certificates and code signing involve CA support, trust stores, chain sizes, and signing infrastructure that your build pipeline may not tolerate yet. Separate owners, separate timelines, separate proof.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not hand it to security alone.&lt;/strong&gt; Security should define the standard and the target state. Platform should own the inventory, the rollout mechanics, the fallback policy, and the observability. Application teams own their own clients. If nobody owns the list of things that must still work, the list will be incomplete at exactly the wrong moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  "turn it on" is not a strategy
&lt;/h2&gt;

&lt;p&gt;My biggest skepticism about how this is being sold is the implied simplicity. Enable hybrid groups, prefer PQC, done.&lt;/p&gt;

&lt;p&gt;That is not a strategy, because it cannot answer three questions:&lt;/p&gt;

&lt;p&gt;What actually negotiated? If you cannot show, per path, which group was used, you do not know whether you are post-quantum or whether a proxy quietly negotiated something classical on your behalf.&lt;/p&gt;

&lt;p&gt;What fell back, and why? Fallback is not automatically a failure, but an unobserved fallback is. Browsers and clients will happily downgrade. If you are not measuring it, you are guessing.&lt;/p&gt;

&lt;p&gt;What broke? Bigger handshakes hit real constraints: MTU and fragmentation, connection setup latency budgets, throughput on high-connection-count services, and any queue or timeout that was tuned against a smaller handshake. You will find these in a canary, or you will find them in production.&lt;/p&gt;

&lt;p&gt;A migration you cannot observe is a migration you cannot finish. You will end up with a partial rollout, a permanent exception list, and a security posture that only exists on the diagram.&lt;/p&gt;

&lt;h2&gt;
  
  
  a small checklist to start without panic
&lt;/h2&gt;

&lt;p&gt;You do not need to rewrite anything this quarter. You need to know things you currently do not know.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;List every TLS client you operate, with the runtime and crypto library version behind each one.&lt;/li&gt;
&lt;li&gt;Pick three paths: one internal service-to-service, one through a proxy or mesh, one to an external partner or payment integration.&lt;/li&gt;
&lt;li&gt;Turn on hybrid key exchange in a non-production environment and capture what negotiated, what fell back, and how big the handshake got.&lt;/li&gt;
&lt;li&gt;Add negotiated group and handshake metrics to your existing TLS observability before you roll anything out.&lt;/li&gt;
&lt;li&gt;Write down your fallback policy explicitly: are silent classical fallbacks acceptable, and for how long?&lt;/li&gt;
&lt;li&gt;Track the AWS CRYSTALS-Kyber removal timeline and any provider deprecation notices for the endpoints you depend on.&lt;/li&gt;
&lt;li&gt;Keep certificate and code-signing PQC work in a separate track with its own owner.&lt;/li&gt;
&lt;li&gt;Give the whole thing a name, an owner, and a date. A migration without an owner is a rumor.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this requires predicting quantum computing timelines. It requires knowing your own system, which is the same work that makes every other migration survivable.&lt;/p&gt;

&lt;p&gt;The teams that treat post-quantum TLS as a platform inventory problem will barely notice when the defaults flip. The teams that wait for the cryptography debate to resolve will discover, under pressure, that the change already shipped in a dependency they do not control.&lt;/p&gt;

&lt;h2&gt;
  
  
  sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/security/ml-kem-post-quantum-tls-now-supported-in-aws-kms-acm-and-secrets-manager/" rel="noopener noreferrer"&gt;ML-KEM post-quantum TLS now supported in AWS KMS, ACM, and Secrets Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/kms/latest/developerguide/pqtls.html" rel="noopener noreferrer"&gt;AWS KMS post-quantum TLS client configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/ssl/post-quantum-cryptography/" rel="noopener noreferrer"&gt;Cloudflare post-quantum cryptography documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/ssl/post-quantum-cryptography/pqc-to-origin/" rel="noopener noreferrer"&gt;Cloudflare PQC to origin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcommunity.microsoft.com/blog/microsoft-security-blog/new-windows-features-to-secure-today%E2%80%99s-data-in-a-post-quantum-world/4523370" rel="noopener noreferrer"&gt;New Windows features to secure today's data in a post-quantum world&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/draft-ietf-tls-mlkem/" rel="noopener noreferrer"&gt;IETF draft: ML-KEM for TLS 1.3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2606.16473" rel="noopener noreferrer"&gt;Measurement of post-quantum readiness across the web (arXiv)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
    <item>
      <title>post-quantum tls is a platform migration, not a crypto project</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Tue, 15 Sep 2026 12:00:32 +0000</pubDate>
      <link>https://dev.to/pvgomes/post-quantum-tls-is-a-platform-migration-not-a-crypto-project-24fe</link>
      <guid>https://dev.to/pvgomes/post-quantum-tls-is-a-platform-migration-not-a-crypto-project-24fe</guid>
      <description>&lt;p&gt;Every few months someone asks me when quantum computers will break RSA.&lt;/p&gt;

&lt;p&gt;I have stopped answering that question, because it is not the question engineering teams actually have.&lt;/p&gt;

&lt;p&gt;The question they have is much less glamorous: do we know which of our services, SDKs, middleboxes, payment integrations, and certificate workflows will tolerate a bigger handshake, a hybrid key exchange, and eventually post-quantum signatures? Most teams cannot answer that today. And 2026 is the year the cloud providers started answering it for them, by changing the defaults.&lt;/p&gt;

&lt;p&gt;That is the whole story. The quantum timeline is a distraction. The migration is already arriving through the boring doors: managed TLS endpoints, SDK defaults, CDN edge configuration, OS crypto libraries, and certificate tooling.&lt;/p&gt;

&lt;h2&gt;
  
  
  the narrow technical shift
&lt;/h2&gt;

&lt;p&gt;Strip away the hype and the change is small and specific.&lt;/p&gt;

&lt;p&gt;TLS 1.3 key exchange is currently dominated by X25519, an elliptic-curve Diffie-Hellman variant. It is fast, small, and well understood. The post-quantum concern is not that someone recorded your traffic and can decrypt it now. It is that a future quantum computer could decrypt recorded traffic later, which is exactly why anything with a long confidentiality lifetime, like a banking session log or a signed document, gets uncomfortable first.&lt;/p&gt;

&lt;p&gt;The industry response was never "replace X25519 with something quantum-safe." It was hybrid: run the classical curve and the post-quantum key encapsulation together, and combine the results. If either holds, the session holds. That is what ML-KEM (FIPS 203, the standardized descendant of CRYSTALS-Kyber) provides, and it is why the IETF draft on ML-KEM for TLS 1.3 exists in the first place.&lt;/p&gt;

&lt;p&gt;The practical consequence is size. A hybrid key share is much larger than an X25519 key share. That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bigger ClientHello messages&lt;/li&gt;
&lt;li&gt;more bytes before the handshake completes&lt;/li&gt;
&lt;li&gt;more chances to hit fragmentation, MTU limits, or middleboxes that "helpfully" drop what they do not recognize&lt;/li&gt;
&lt;li&gt;more chances for an old client to negotiate a fallback group and nobody notice&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here is the part people conflate: key exchange and signatures are different problems with different timelines. ML-KEM protects the session key. Post-quantum signatures and how they land in certificates and code signing is a separate migration with its own compatibility and trust-chain pain. You can ship the first without having solved the second, and you probably should, because the first is already being turned on for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  what changed in 2026
&lt;/h2&gt;

&lt;p&gt;This stopped being a standards-track slide deck this year.&lt;/p&gt;

&lt;p&gt;AWS shipped ML-KEM hybrid post-quantum TLS support across KMS, ACM, and Secrets Manager, and it is explicit that the older CRYSTALS-Kyber support will be removed across AWS service endpoints in 2026. That second sentence is the one to underline. This is not an opt-in curiosity anymore. It is a controlled API surface with a deprecation calendar attached.&lt;/p&gt;

&lt;p&gt;Cloudflare documents post-quantum support for edge-to-origin TLS, including X25519MLKEM768 for key agreement and ML-DSA for origin authentication, with clear notes about where it is supported and where it is constrained. Microsoft shipped Windows platform support for ML-KEM hybrid TLS groups and is openly talking about an accelerated migration path for critical products and services toward 2029. The IETF draft for ML-KEM in TLS 1.3 is active.&lt;/p&gt;

&lt;p&gt;And then there is the measurement reality. A June 2026 measurement paper looking at post-quantum readiness across more than 32,000 domains found the internet is not uniformly ready, with particular lag around banking and government TLS 1.2 endpoints and post-quantum certificate adoption. I find that more useful than any roadmap slide, because it says the failure modes will be uneven and depend on what your specific clients do.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhzgu3hiae5nlit5zn7l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqhzgu3hiae5nlit5zn7l.gif" alt="this is fine" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  translate it into platform work
&lt;/h2&gt;

&lt;p&gt;Here is where I push back on how most teams are framing this.&lt;/p&gt;

&lt;p&gt;If PQC lives only in a security-owned ticket, it will get treated as a cryptography review that produces a PDF and no changes. That is a mistake. The actual work is platform work, and it looks a lot like every other platform migration you have done badly before.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inventory your outbound clients and TLS stacks.&lt;/strong&gt; Not your externally facing load balancers, which are usually the easy part, but everything that makes an outbound TLS connection. Application runtimes, language crypto libraries, JDK versions, Go and Rust toolchains, database drivers, message bus clients, cron jobs, batch exports, and the one internal tool that has not been rebuilt since a migration ago. Different stacks gain hybrid group support at different times, and some old ones never will.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test service-to-service paths end to end.&lt;/strong&gt; A handshake does not happen between two applications. It happens through whatever is in the middle: proxies, API gateways, service meshes with their own TLS origination, CDNs, WAFs, egress filters, and vendor middleboxes that terminate and re-establish TLS. Those are where the surprises live. Payment and fintech integrations are the highest-stakes version of this, because a partner that pins groups, inspects traffic, or terminates in something old will fail in a way that looks like "the vendor is down."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watch the right signals.&lt;/strong&gt; This migration is observable, which is the only good news in the story. Track negotiated group, not just protocol version. Track handshake size and handshake latency, because hybrid key exchange changes both. Track fallback and retry counts, because a silent fall back to a classical group is the most likely failure mode and it will look like success unless you instrument it. Track TLS error rates by client version and by dependency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Split certificates and code signing from key exchange.&lt;/strong&gt; Do not let an ML-KEM rollout turn into an ML-DSA certificate plan. Hybrid key exchange is mostly a library-and-config change. Post-quantum certificates and code signing involve CA support, trust stores, chain sizes, and signing infrastructure that your build pipeline may not tolerate yet. Separate owners, separate timelines, separate proof.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not hand it to security alone.&lt;/strong&gt; Security should define the standard and the target state. Platform should own the inventory, the rollout mechanics, the fallback policy, and the observerability. Application teams own their own clients. If nobody owns the list of things that must still work, the list will be incomplete at exactly the wrong moment.&lt;/p&gt;

&lt;h2&gt;
  
  
  "turn it on" is not a strategy
&lt;/h2&gt;

&lt;p&gt;My biggest skepticism about how this is being sold is the implied simplicity. Enable hybrid groups, prefer PQC, done.&lt;/p&gt;

&lt;p&gt;That is not a strategy, because it cannot answer three questions:&lt;/p&gt;

&lt;p&gt;What actually negotiated? If you cannot show, per path, which group was used, you do not know whether you are post-quantum or whether a proxy quietly negotiated something classical on your behalf.&lt;/p&gt;

&lt;p&gt;What fell back, and why? Fallback is not automatically a failure, but an unobserved fallback is. Browsers and clients will happily downgrade. If you are not measuring it, you are guessing.&lt;/p&gt;

&lt;p&gt;What broke? Bigger handshakes hit real constraints: MTU and fragmentation, connection setup latency budgets, throughput on high-connection-count services, and any queue or timeout that was tuned against a smaller handshake. You will find these in a canary, or you will find them in production.&lt;/p&gt;

&lt;p&gt;A migration you cannot observe is a migration you cannot finish. You will end up with a partial rollout, a permanent exception list, and a security posture that only exists on the diagram.&lt;/p&gt;

&lt;h2&gt;
  
  
  a small checklist to start without panic
&lt;/h2&gt;

&lt;p&gt;You do not need to rewrite anything this quarter. You need to know things you currently do not know.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;List every TLS client you operate, with the runtime and crypto library version behind each one.&lt;/li&gt;
&lt;li&gt;Pick three paths: one internal service-to-service, one through a proxy or mesh, one to an external partner or payment integration.&lt;/li&gt;
&lt;li&gt;Turn on hybrid key exchange in a non-production environment and capture what negotiated, what fell back, and how big the handshake got.&lt;/li&gt;
&lt;li&gt;Add negotiated group and handshake metrics to your existing TLS observability before you roll anything out.&lt;/li&gt;
&lt;li&gt;Write down your fallback policy explicitly: are silent classical fallbacks acceptable, and for how long?&lt;/li&gt;
&lt;li&gt;Track the AWS CRYSTALS-Kyber removal timeline and any provider deprecation notices for the endpoints you depend on.&lt;/li&gt;
&lt;li&gt;Keep certificate and code-signing PQC work in a separate track with its own owner.&lt;/li&gt;
&lt;li&gt;Give the whole thing a name, an owner, and a date. A migration without an owner is a rumor.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of this requires predicting quantum computing timelines. It requires knowing your own system, which is the same work that makes every other migration survivable.&lt;/p&gt;

&lt;p&gt;The teams that treat post-quantum TLS as a platform inventory problem will barely notice when the defaults flip. The teams that wait for the cryptography debate to resolve will discover, under pressure, that the change already shipped in a dependency they do not control.&lt;/p&gt;

&lt;h2&gt;
  
  
  sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/security/ml-kem-post-quantum-tls-now-supported-in-aws-kms-acm-and-secrets-manager/" rel="noopener noreferrer"&gt;ML-KEM post-quantum TLS now supported in AWS KMS, ACM, and Secrets Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/kms/latest/developerguide/pqtls.html" rel="noopener noreferrer"&gt;AWS KMS post-quantum TLS client configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/ssl/post-quantum-cryptography/" rel="noopener noreferrer"&gt;Cloudflare post-quantum cryptography documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/ssl/post-quantum-cryptography/pqc-to-origin/" rel="noopener noreferrer"&gt;Cloudflare PQC to origin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcommunity.microsoft.com/blog/microsoft-security-blog/new-windows-features-to-secure-today%E2%80%99s-data-in-a-post-quantum-world/4523370" rel="noopener noreferrer"&gt;New Windows features to secure today's data in a post-quantum world&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/draft-ietf-tls-mlkem/" rel="noopener noreferrer"&gt;IETF draft: ML-KEM for TLS 1.3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2606.16473" rel="noopener noreferrer"&gt;Measurement of post-quantum readiness across the web (arXiv)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
    <item>
      <title>post-quantum TLS is a platform migration, not a crypto project</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Tue, 15 Sep 2026 10:32:04 +0000</pubDate>
      <link>https://dev.to/pvgomes/post-quantum-tls-is-a-platform-migration-not-a-crypto-project-325b</link>
      <guid>https://dev.to/pvgomes/post-quantum-tls-is-a-platform-migration-not-a-crypto-project-325b</guid>
      <description>&lt;p&gt;Post-quantum TLS stopped being a cryptography conference topic and became ordinary platform work some time in 2026.&lt;/p&gt;

&lt;p&gt;Most engineering teams did not notice, because it arrived the way most infrastructure changes arrive: as defaults.&lt;/p&gt;

&lt;p&gt;A cloud SDK bump. A CDN flag flipped at the edge. A KMS endpoint that negotiates something different than it did last quarter. A browser quietly preferring a hybrid group on every TLS 1.3 handshake. Nobody got a migration project. Everybody got a migration surface.&lt;/p&gt;

&lt;p&gt;The quantum-timeline argument is a distraction here. Whether RSA falls in 2030, 2035, or later than anyone alive cares about is a legitimate research question and a completely useless planning input for a platform team. The engineering problem is not "when does quantum break RSA?" The problem is:&lt;/p&gt;

&lt;p&gt;Do we know which of our services, SDKs, middleboxes, payment integrations, and certificate workflows actually tolerate larger handshakes, hybrid key exchange, ML-KEM defaults, and eventually post-quantum signatures?&lt;/p&gt;

&lt;p&gt;That question has a boring, testable answer. That is what makes it a platform problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  the narrow technical shift nobody explained clearly
&lt;/h2&gt;

&lt;p&gt;Let me compress the crypto down to the part platform engineers need.&lt;/p&gt;

&lt;p&gt;TLS 1.3 has two cryptographic jobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Key agreement&lt;/strong&gt; — both sides derive a shared secret so the rest of the session can be encrypted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt; — the server proves who it is, usually with an RSA or ECDSA certificate signature.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Post-quantum work is hitting these two at different times, with different maturity, and different operational blast radius. Conflating them is how teams end up with a two-year plan that should have been a two-week test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key agreement is the part already shipping.&lt;/strong&gt; The dominant approach is hybrid: keep the classical X25519 exchange and add an ML-KEM (formerly Kyber) component alongside it. The session secret stays safe as long as either component holds. Cloudflare's implementation is the one most people will meet first — X25519MLKEM768 is now a standard group in TLS 1.3, supported at the edge and documented for edge-to-origin paths.&lt;/p&gt;

&lt;p&gt;The practically relevant property of hybrid key exchange? &lt;strong&gt;Nothing breaks because it's post-quantum.&lt;/strong&gt; It breaks because it's bigger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signatures and certificates are the slower half.&lt;/strong&gt; ML-DSA exists and is being integrated, but post-quantum certificate authentication touches CA hierarchies, trust stores, client compatibility, device firmware, and the whole certification lifecycle. That is a genuinely multi-year migration. It is also &lt;em&gt;not&lt;/em&gt; what most of the "we support PQC" announcements are about, which is why reading them carefully matters.&lt;/p&gt;

&lt;p&gt;IETF work on ML-KEM for TLS 1.3 is active through 2026, so the wire format is close to settled. Good news: you can test now.&lt;/p&gt;

&lt;h2&gt;
  
  
  why this is already on your platform, whether you planned it or not
&lt;/h2&gt;

&lt;p&gt;The reason I think platform teams should care right now is not standards activity. It is that the defaults are moving underneath you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS&lt;/strong&gt; already supports ML-KEM hybrid post-quantum TLS for KMS, ACM, and Secrets Manager, and has signaled that older CRYSTALS-Kyber support will be removed across AWS service endpoints in 2026. That is a deprecation with a date, which is the most reliable form of "you will deal with this."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare&lt;/strong&gt; documents PQC across its TLS stack, including X25519MLKEM768 and ML-DSA for origin authentication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft&lt;/strong&gt; has shipped Windows platform support for ML-KEM hybrid TLS groups and is talking publicly about accelerating migration of critical products toward 2029.&lt;/li&gt;
&lt;li&gt;Measurement work from mid-2026 across tens of thousands of domains shows readiness is deeply uneven — banking and government endpoints lagging, post-quantum certificate adoption near zero.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point is the most useful one for anyone building fintech infrastructure. The interesting question is never "does PQC work?" It obviously works in a lab. The interesting question is &lt;strong&gt;where in your call graph it stops working&lt;/strong&gt;, because that is where your production traffic goes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpqqai5gqi4fow8om981.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbpqqai5gqi4fow8om981.gif" alt="the handshake got bigger and nobody told the middlebox" width="478" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  translate it into platform work
&lt;/h2&gt;

&lt;p&gt;Here is the honest version of the migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  inventory outbound clients and TLS stacks
&lt;/h3&gt;

&lt;p&gt;Every service that opens a TLS connection is a client, and most of them are invisible. Go's crypto/tls, Java's JSSE, Node's OpenSSL bindings, Python's ssl, Rust's rustls, plus every vendor SDK that bundles its own stack. Count the language runtimes, then count the SDKs that don't respect the runtime's defaults.&lt;/p&gt;

&lt;p&gt;That second number is usually the surprise.&lt;/p&gt;

&lt;h3&gt;
  
  
  test service-to-service paths through every middlebox
&lt;/h3&gt;

&lt;p&gt;This is where the migration actually gets hard, because the interesting failures live in components nobody considers TLS clients:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reverse proxies and load balancers&lt;/li&gt;
&lt;li&gt;API gateways&lt;/li&gt;
&lt;li&gt;service meshes with mTLS everywhere&lt;/li&gt;
&lt;li&gt;CDN edge-to-origin links&lt;/li&gt;
&lt;li&gt;WAFs doing TLS inspection&lt;/li&gt;
&lt;li&gt;payment and banking integrations with fixed TLS profiles&lt;/li&gt;
&lt;li&gt;old appliances that will never get a firmware update&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A middlebox that reconstructs or inspects TLS can choke on a ClientHello it doesn't recognize. Some will reject unknown key share groups. Some will negotiate down. Some will fail in a way that only shows up under load.&lt;/p&gt;

&lt;h3&gt;
  
  
  watch the right signals
&lt;/h3&gt;

&lt;p&gt;You cannot migrate what you cannot observe. The measurements that matter during a PQC rollout are not CPU graphs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;handshake size on the wire&lt;/li&gt;
&lt;li&gt;handshake latency, especially cold connections across regions&lt;/li&gt;
&lt;li&gt;TLS error rates split by client version and destination&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;negotiated group&lt;/strong&gt; per connection — this is the number that tells you whether the hybrid path is actually being used&lt;/li&gt;
&lt;li&gt;fallback rates, because a silent fallback to classical key exchange looks identical to success if you only check for errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That fallback point deserves emphasis. A connection that quietly negotiates X25519 instead of X25519MLKEM768 is &lt;em&gt;working&lt;/em&gt;. It is also not post-quantum. If your only signal is "did the request succeed," you will report a green migration that never happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  plan certificates as a separate track
&lt;/h3&gt;

&lt;p&gt;Key exchange and signatures are different projects with different timelines. Hybrid key agreement can be enabled, measured, and rolled back in weeks. Post-quantum certificate chains touch CA operations, trust stores, hardware, and code signing, and they are a genuinely long-horizon program.&lt;/p&gt;

&lt;p&gt;Do not let the first one create fake urgency for the second, and do not let the second block the first.&lt;/p&gt;

&lt;h3&gt;
  
  
  don't make this a security-team ticket
&lt;/h3&gt;

&lt;p&gt;This is the mistake I'd push back on hardest. If PQC lands in the security backlog as a single ticket titled "quantum readiness," it will sit there until a cloud provider forces the issue at a bad time.&lt;/p&gt;

&lt;p&gt;The work is distributed by nature:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;platform owns the runtime and library inventory&lt;/li&gt;
&lt;li&gt;service teams own their SDKs and integration tests&lt;/li&gt;
&lt;li&gt;networking owns proxies, gateways, and middleboxes&lt;/li&gt;
&lt;li&gt;security owns the crypto policy and the deprecation timeline awareness&lt;/li&gt;
&lt;li&gt;SRE owns the observability and rollback path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a coordination problem, not a crypto problem. Treating it as crypto is how it stays unowned.&lt;/p&gt;

&lt;h2&gt;
  
  
  "turn it on" is not a strategy
&lt;/h2&gt;

&lt;p&gt;The skeptical core of this post: enabling hybrid post-quantum TLS is a one-line config change in most stacks, and that is exactly why it is dangerous.&lt;/p&gt;

&lt;p&gt;If you flip the flag and nobody can answer these, you haven't migrated anything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which clients negotiated the hybrid group, and which silently fell back?&lt;/li&gt;
&lt;li&gt;Which services failed to connect, and did they fail loudly or retry down to classical?&lt;/li&gt;
&lt;li&gt;What does the handshake look like through the proxy, the mesh, and the CDN?&lt;/li&gt;
&lt;li&gt;Can we revert without a full deploy?&lt;/li&gt;
&lt;li&gt;Do we know the before/after handshake size and latency numbers for our real traffic, not a benchmark?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the standard I'd hold a PQC rollout to. Not "we enabled it." "We can prove what negotiated, what fell back, and what broke."&lt;/p&gt;

&lt;h2&gt;
  
  
  a practical starting checklist
&lt;/h2&gt;

&lt;p&gt;Small on purpose. This should be days of work, not a program.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;List every TLS stack you ship.&lt;/strong&gt; Runtimes, SDKs, proxies, sidecars, appliances. Note who owns each.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick one internal call path&lt;/strong&gt; — a low-risk service-to-service link through your gateway — and enable hybrid key exchange there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instrument the negotiated group per connection.&lt;/strong&gt; If you can't see it, stop and fix that first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Record baseline handshake size and latency&lt;/strong&gt; before the change, and compare after. Cold connections across regions, not localhost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test the middleboxes deliberately.&lt;/strong&gt; Force the new group, watch the proxy, mesh, and any TLS-inspecting appliance. Break it on purpose in staging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the rollback down.&lt;/strong&gt; One flag, one revert, one documented path back to classical.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track the deprecations.&lt;/strong&gt; Kyber removal, SDK changes, CDN defaults. These are the real deadlines; the quantum timeline is not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate the certificate track&lt;/strong&gt; and give it a real owner with a multi-year horizon.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do that and you will be ahead of most of the industry for a fraction of the cost, because the industry is currently waiting for a reason to start.&lt;/p&gt;

&lt;p&gt;The cloud providers are not waiting. They are making Post-quantum TLS the default quietly, endpoint by endpoint, and the only question that matters is whether you find out from a rollout you ran or from an incident you didn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/security/ml-kem-post-quantum-tls-now-supported-in-aws-kms-acm-and-secrets-manager/" rel="noopener noreferrer"&gt;AWS: ML-KEM post-quantum TLS now supported in AWS KMS, ACM, and Secrets Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/kms/latest/developerguide/pqtls.html" rel="noopener noreferrer"&gt;AWS KMS: post-quantum TLS client configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/ssl/post-quantum-cryptography/" rel="noopener noreferrer"&gt;Cloudflare: post-quantum cryptography&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/ssl/post-quantum-cryptography/pqc-to-origin/" rel="noopener noreferrer"&gt;Cloudflare: post-quantum cryptography to origin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcommunity.microsoft.com/blog/microsoft-security-blog/new-windows-features-to-secure-today%E2%80%99s-data-in-a-post-quantum-world/4523370" rel="noopener noreferrer"&gt;Microsoft: new Windows features to secure today's data in a post-quantum world&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/draft-ietf-tls-mlkem/" rel="noopener noreferrer"&gt;IETF draft: ML-KEM key agreement for TLS 1.3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2606.16473" rel="noopener noreferrer"&gt;Measurement of post-quantum readiness across 32,011 domains (June 2026)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
    <item>
      <title>post-quantum TLS is a platform migration, not a crypto project</title>
      <dc:creator>Paulo Victor Leite Lima Gomes</dc:creator>
      <pubDate>Tue, 15 Sep 2026 10:00:36 +0000</pubDate>
      <link>https://dev.to/pvgomes/post-quantum-tls-is-a-platform-migration-not-a-crypto-project-1bae</link>
      <guid>https://dev.to/pvgomes/post-quantum-tls-is-a-platform-migration-not-a-crypto-project-1bae</guid>
      <description>&lt;p&gt;Post-quantum TLS stopped being a cryptography conference topic and became ordinary platform work some time in 2026.&lt;/p&gt;

&lt;p&gt;Most engineering teams did not notice, because it arrived the way most infrastructure changes arrive: as defaults.&lt;/p&gt;

&lt;p&gt;A cloud SDK bump. A CDN flag flipped at the edge. A KMS endpoint that negotiates something different than it did last quarter. A browser quietly preferring a hybrid group on every TLS 1.3 handshake. Nobody got a migration project. Everybody got a migration surface.&lt;/p&gt;

&lt;p&gt;The quantum-timeline argument is a distraction here. Whether RSA falls in 2030, 2035, or later than anyone alive cares about is a legitimate research question and a completely useless planning input for a platform team. The engineering problem is not "when does quantum break RSA?" The problem is:&lt;/p&gt;

&lt;p&gt;Do we know which of our services, SDKs, middleboxes, payment integrations, and certificate workflows actually tolerate larger handshakes, hybrid key exchange, ML-KEM defaults, and eventually post-quantum signatures?&lt;/p&gt;

&lt;p&gt;That question has a boring, testable answer. That is what makes it a platform problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  the narrow technical shift nobody explained clearly
&lt;/h2&gt;

&lt;p&gt;Let me compress the crypto down to the part platform engineers need.&lt;/p&gt;

&lt;p&gt;TLS 1.3 has two cryptographic jobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Key agreement&lt;/strong&gt; — both sides derive a shared secret so the rest of the session can be encrypted.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt; — the server proves who it is, usually with an RSA or ECDSA certificate signature.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Post-quantum work is hitting these two at different times, with different maturity, and different operational blast radius. Conflating them is how teams end up with a two-year plan that should have been a two-week test.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key agreement is the part already shipping.&lt;/strong&gt; The dominant approach is hybrid: keep the classical X25519 exchange and add an ML-KEM (formerly Kyber) component alongside it. The session secret stays safe as long as either component holds. Cloudflare's implementation is the one most people will meet first — X25519MLKEM768 is now a standard group in TLS 1.3, supported at the edge and documented for edge-to-origin paths.&lt;/p&gt;

&lt;p&gt;The practically relevant property of hybrid key exchange? &lt;strong&gt;Nothing breaks because it's post-quantum.&lt;/strong&gt; It breaks because it's bigger.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signatures and certificates are the slower half.&lt;/strong&gt; ML-DSA exists and is being integrated, but post-quantum certificate authentication touches CA hierarchies, trust stores, client compatibility, device firmware, and the whole certification lifecycle. That is a genuinely multi-year migration. It is also &lt;em&gt;not&lt;/em&gt; what most of the "we support PQC" announcements are about, which is why reading them carefully matters.&lt;/p&gt;

&lt;p&gt;IETF work on ML-KEM for TLS 1.3 is active through 2026, so the wire format is close to settled. Good news: you can test now.&lt;/p&gt;

&lt;h2&gt;
  
  
  why this is already on your platform, whether you planned it or not
&lt;/h2&gt;

&lt;p&gt;The reason I think platform teams should care right now is not standards activity. It is that the defaults are moving underneath you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS&lt;/strong&gt; already supports ML-KEM hybrid post-quantum TLS for KMS, ACM, and Secrets Manager, and has signaled that older CRYSTALS-Kyber support will be removed across AWS service endpoints in 2026. That is a deprecation with a date, which is the most reliable form of "you will deal with this."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloudflare&lt;/strong&gt; documents PQC across its TLS stack, including X25519MLKEM768 and ML-DSA for origin authentication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft&lt;/strong&gt; has shipped Windows platform support for ML-KEM hybrid TLS groups and is talking publicly about accelerating migration of critical products toward 2029.&lt;/li&gt;
&lt;li&gt;Measurement work from mid-2026 across tens of thousands of domains shows readiness is deeply uneven — banking and government endpoints lagging, post-quantum certificate adoption near zero.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point is the most useful one for anyone building fintech infrastructure. The interesting question is never "does PQC work?" It obviously works in a lab. The interesting question is &lt;strong&gt;where in your call graph it stops working&lt;/strong&gt;, because that is where your production traffic goes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzs0vzzfds0vgl2kk8bl.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzs0vzzfds0vgl2kk8bl.gif" alt="the handshake got bigger and nobody told the middlebox" width="350" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  translate it into platform work
&lt;/h2&gt;

&lt;p&gt;Here is the honest version of the migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  inventory outbound clients and TLS stacks
&lt;/h3&gt;

&lt;p&gt;Every service that opens a TLS connection is a client, and most of them are invisible. Go's crypto/tls, Java's JSSE, Node's OpenSSL bindings, Python's ssl, Rust's rustls, plus every vendor SDK that bundles its own stack. Count the language runtimes, then count the SDKs that don't respect the runtime's defaults.&lt;/p&gt;

&lt;p&gt;That second number is usually the surprise.&lt;/p&gt;

&lt;h3&gt;
  
  
  test service-to-service paths through every middlebox
&lt;/h3&gt;

&lt;p&gt;This is where the migration actually gets hard, because the interesting failures live in components nobody considers TLS clients:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reverse proxies and load balancers&lt;/li&gt;
&lt;li&gt;API gateways&lt;/li&gt;
&lt;li&gt;service meshes with mTLS everywhere&lt;/li&gt;
&lt;li&gt;CDN edge-to-origin links&lt;/li&gt;
&lt;li&gt;WAFs doing TLS inspection&lt;/li&gt;
&lt;li&gt;payment and banking integrations with fixed TLS profiles&lt;/li&gt;
&lt;li&gt;old appliances that will never get a firmware update&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A middlebox that reconstructs or inspects TLS can choke on a ClientHello it doesn't recognize. Some will reject unknown key share groups. Some will negotiate down. Some will fail in a way that only shows up under load.&lt;/p&gt;

&lt;h3&gt;
  
  
  watch the right signals
&lt;/h3&gt;

&lt;p&gt;You cannot migrate what you cannot observe. The measurements that matter during a PQC rollout are not CPU graphs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;handshake size on the wire&lt;/li&gt;
&lt;li&gt;handshake latency, especially cold connections across regions&lt;/li&gt;
&lt;li&gt;TLS error rates split by client version and destination&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;negotiated group&lt;/strong&gt; per connection — this is the number that tells you whether the hybrid path is actually being used&lt;/li&gt;
&lt;li&gt;fallback rates, because a silent fallback to classical key exchange looks identical to success if you only check for errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That fallback point deserves emphasis. A connection that quietly negotiates X25519 instead of X25519MLKEM768 is &lt;em&gt;working&lt;/em&gt;. It is also not post-quantum. If your only signal is "did the request succeed," you will report a green migration that never happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  plan certificates as a separate track
&lt;/h3&gt;

&lt;p&gt;Key exchange and signatures are different projects with different timelines. Hybrid key agreement can be enabled, measured, and rolled back in weeks. Post-quantum certificate chains touch CA operations, trust stores, hardware, and code signing, and they are a genuinely long-horizon program.&lt;/p&gt;

&lt;p&gt;Do not let the first one create fake urgency for the second, and do not let the second block the first.&lt;/p&gt;

&lt;h3&gt;
  
  
  don't make this a security-team ticket
&lt;/h3&gt;

&lt;p&gt;This is the mistake I'd push back on hardest. If PQC lands in the security backlog as a single ticket titled "quantum readiness," it will sit there until a cloud provider forces the issue at a bad time.&lt;/p&gt;

&lt;p&gt;The work is distributed by nature:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;platform owns the runtime and library inventory&lt;/li&gt;
&lt;li&gt;service teams own their SDKs and integration tests&lt;/li&gt;
&lt;li&gt;networking owns proxies, gateways, and middleboxes&lt;/li&gt;
&lt;li&gt;security owns the crypto policy and the deprecation timeline awareness&lt;/li&gt;
&lt;li&gt;SRE owns the observability and rollback path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a coordination problem, not a crypto problem. Treating it as crypto is how it stays unowned.&lt;/p&gt;

&lt;h2&gt;
  
  
  "turn it on" is not a strategy
&lt;/h2&gt;

&lt;p&gt;The skeptical core of this post: enabling hybrid post-quantum TLS is a one-line config change in most stacks, and that is exactly why it is dangerous.&lt;/p&gt;

&lt;p&gt;If you flip the flag and nobody can answer these, you haven't migrated anything:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which clients negotiated the hybrid group, and which silently fell back?&lt;/li&gt;
&lt;li&gt;Which services failed to connect, and did they fail loudly or retry down to classical?&lt;/li&gt;
&lt;li&gt;What does the handshake look like through the proxy, the mesh, and the CDN?&lt;/li&gt;
&lt;li&gt;Can we revert without a full deploy?&lt;/li&gt;
&lt;li&gt;Do we know the before/after handshake size and latency numbers for our real traffic, not a benchmark?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the standard I'd hold a PQC rollout to. Not "we enabled it." "We can prove what negotiated, what fell back, and what broke."&lt;/p&gt;

&lt;h2&gt;
  
  
  a practical starting checklist
&lt;/h2&gt;

&lt;p&gt;Small on purpose. This should be days of work, not a program.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;List every TLS stack you ship.&lt;/strong&gt; Runtimes, SDKs, proxies, sidecars, appliances. Note who owns each.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick one internal call path&lt;/strong&gt; — a low-risk service-to-service link through your gateway — and enable hybrid key exchange there.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instrument the negotiated group per connection.&lt;/strong&gt; If you can't see it, stop and fix that first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Record baseline handshake size and latency&lt;/strong&gt; before the change, and compare after. Cold connections across regions, not localhost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test the middleboxes deliberately.&lt;/strong&gt; Force the new group, watch the proxy, mesh, and any TLS-inspecting appliance. Break it on purpose in staging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write the rollback down.&lt;/strong&gt; One flag, one revert, one documented path back to classical.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Track the deprecations.&lt;/strong&gt; Kyber removal, SDK changes, CDN defaults. These are the real deadlines; the quantum timeline is not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate the certificate track&lt;/strong&gt; and give it a real owner with a multi-year horizon.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do that and you will be ahead of most of the industry for a fraction of the cost, because the industry is currently waiting for a reason to start.&lt;/p&gt;

&lt;p&gt;The cloud providers are not waiting. They are making Post-quantum TLS the default quietly, endpoint by endpoint, and the only question that matters is whether you find out from a rollout you ran or from an incident you didn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/security/ml-kem-post-quantum-tls-now-supported-in-aws-kms-acm-and-secrets-manager/" rel="noopener noreferrer"&gt;AWS: ML-KEM post-quantum TLS now supported in AWS KMS, ACM, and Secrets Manager&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/kms/latest/developerguide/pqtls.html" rel="noopener noreferrer"&gt;AWS KMS: post-quantum TLS client configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/ssl/post-quantum-cryptography/" rel="noopener noreferrer"&gt;Cloudflare: post-quantum cryptography&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.cloudflare.com/ssl/post-quantum-cryptography/pqc-to-origin/" rel="noopener noreferrer"&gt;Cloudflare: post-quantum cryptography to origin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://techcommunity.microsoft.com/blog/microsoft-security-blog/new-windows-features-to-secure-today%E2%80%99s-data-in-a-post-quantum-world/4523370" rel="noopener noreferrer"&gt;Microsoft: new Windows features to secure today's data in a post-quantum world&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/draft-ietf-tls-mlkem/" rel="noopener noreferrer"&gt;IETF draft: ML-KEM key agreement for TLS 1.3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/abs/2606.16473" rel="noopener noreferrer"&gt;Measurement of post-quantum readiness across 32,011 domains (June 2026)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To test my projects, I use &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;Railway&lt;/a&gt;. If you want $20 USD to get started, &lt;a href="https://railway.com?referralCode=G_jRmP" rel="noopener noreferrer"&gt;use this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>opinion</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
