<?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: Lav Kumar Vishwakarma</title>
    <description>The latest articles on DEV Community by Lav Kumar Vishwakarma (@lav_vishwakarma).</description>
    <link>https://dev.to/lav_vishwakarma</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%2F4076452%2F3ed1401f-af2b-4f75-8200-f35817f42fa8.png</url>
      <title>DEV Community: Lav Kumar Vishwakarma</title>
      <link>https://dev.to/lav_vishwakarma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lav_vishwakarma"/>
    <language>en</language>
    <item>
      <title>Two Traefik Bugs, One Broken Boundary</title>
      <dc:creator>Lav Kumar Vishwakarma</dc:creator>
      <pubDate>Wed, 28 Oct 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/lav_vishwakarma/two-traefik-bugs-one-broken-boundary-50h2</link>
      <guid>https://dev.to/lav_vishwakarma/two-traefik-bugs-one-broken-boundary-50h2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmlvkvswko248ypkt7rz2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmlvkvswko248ypkt7rz2.png" alt="Traefik bugs" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How a router-name collision made another tenant’s application disappear, and a cached TLS option bypassed namespace restrictions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A few weeks ago, while digging through Traefik’s Kubernetes Ingress NGINX provider, I came across something that didn’t look quite right.&lt;/p&gt;

&lt;p&gt;The code was generating router names by joining different Kubernetes resource identifiers with hyphens.&lt;/p&gt;

&lt;p&gt;Nothing unusual there. I’ve written plenty of similar code myself.&lt;/p&gt;

&lt;p&gt;But then I had a thought: &lt;em&gt;What happens if those identifiers already contain hyphens?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That question eventually led me to a cross-namespace routing issue that could make another tenant’s application disappear from Traefik’s configuration.&lt;/p&gt;

&lt;p&gt;While investigating the provider further, I found another issue involving cached TLS options and cross-namespace authorization.&lt;/p&gt;

&lt;p&gt;Two different bugs, both involving Kubernetes namespace isolation, both reported to Traefik.&lt;/p&gt;

&lt;p&gt;Here’s what I found, how I reproduced the problems, and what happened after reporting them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovery #1: How one Kubernetes tenant could make another tenant’s route disappear
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;GHSA-vm53-8m79-wq7m&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Researcher-assessed severity: CVSS 8.5 (High)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let’s say you’re running a Kubernetes cluster shared by multiple teams.&lt;/p&gt;

&lt;p&gt;Each team has its own namespace, services, and Ingress resources.&lt;/p&gt;

&lt;p&gt;Naturally, you’d expect a team to be unable to interfere with another team’s routing just by creating an Ingress in its own namespace.&lt;/p&gt;

&lt;p&gt;But I discovered a way this could happen.&lt;/p&gt;

&lt;h3&gt;
  
  
  It started with a simple naming collision
&lt;/h3&gt;

&lt;p&gt;Traefik’s Kubernetes Ingress NGINX provider converts Ingress resources into internal routers.&lt;/p&gt;

&lt;p&gt;In the version I examined, it generated router identifiers using the namespace, Ingress name, and rule/path indices.&lt;/p&gt;

&lt;p&gt;The relevant code was essentially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;routerKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"%s-%s-rule-%d-path-%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IngressName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RuleIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocationIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at these two resources:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Namespace&lt;/th&gt;
&lt;th&gt;Ingress name&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;team&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dev-web&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;team-dev&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;web&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Although they belong to completely different namespaces, both produce:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;team-dev-web-rule-0-path-0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The separator doesn’t preserve where the namespace ends and the Ingress name begins.&lt;/p&gt;

&lt;p&gt;That alone might seem like an ordinary naming bug.&lt;/p&gt;

&lt;p&gt;But Traefik stores its generated routers in a shared map, and the generated name is the key.&lt;/p&gt;

&lt;p&gt;When two routers have the same key, one replaces the other.&lt;/p&gt;

&lt;p&gt;No collision check. No warning that another namespace’s configuration has been overwritten.&lt;/p&gt;

&lt;p&gt;And that’s where the security implications begin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reproducing it with the official Traefik image
&lt;/h3&gt;

&lt;p&gt;I didn’t want to stop at identifying a theoretical collision.&lt;/p&gt;

&lt;p&gt;I wanted to see what happened to actual traffic.&lt;/p&gt;

&lt;p&gt;So I created a local Kubernetes environment with two namespaces, two independent backend services, and two Ingress resources.&lt;/p&gt;

&lt;p&gt;I used the official &lt;code&gt;traefik:v3.7.13&lt;/code&gt; image for testing.&lt;/p&gt;

&lt;p&gt;Both Ingress resources were valid. Each had its own hostname and pointed to its own healthy backend.&lt;/p&gt;

&lt;p&gt;I expected both hostnames to work.&lt;/p&gt;

&lt;p&gt;Instead, I got:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;attacker.local -&amp;gt; HTTP 200
victim.local -&amp;gt; HTTP 404
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The victim’s Ingress hadn’t been deleted.&lt;/p&gt;

&lt;p&gt;The backend wasn’t down.&lt;/p&gt;

&lt;p&gt;The route had simply disappeared from Traefik’s generated configuration.&lt;/p&gt;

&lt;p&gt;Even more interesting, the outcome could change across configuration rebuilds because of Go map iteration order.&lt;/p&gt;

&lt;p&gt;One of the two routes was always lost, but which one survived wasn’t necessarily deterministic.&lt;/p&gt;

&lt;p&gt;Imagine debugging that in a production cluster. Everything in Kubernetes looks correct, yet an application’s route mysteriously disappears.&lt;/p&gt;

&lt;h3&gt;
  
  
  But could this go beyond denial of service?
&lt;/h3&gt;

&lt;p&gt;This was the more important question.&lt;/p&gt;

&lt;p&gt;An Ingress router isn’t responsible only for sending requests to a backend.&lt;/p&gt;

&lt;p&gt;It can also have authentication, IP allow-listing, and rate-limiting middlewares attached to it.&lt;/p&gt;

&lt;p&gt;When that router is overwritten, its middleware configuration disappears with it.&lt;/p&gt;

&lt;p&gt;I also tested a scenario where the attacker-controlled Ingress declared the victim’s hostname.&lt;/p&gt;

&lt;p&gt;When the attacker’s router was the surviving one, requests intended for the victim were directed to the attacker’s backend.&lt;/p&gt;

&lt;p&gt;The result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;Host: victim.local

Name: ATTACKER-BACKEND-team-dev
HTTP 200
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That demonstrated a potential cross-namespace route takeover, not merely a missing page.&lt;/p&gt;

&lt;p&gt;The attack still required suitable resource-name combinations and the attacker-controlled router to survive the collision. It wasn’t a universal takeover of arbitrary Kubernetes namespaces.&lt;/p&gt;

&lt;p&gt;But a tenant with permission to create an Ingress only in its own namespace could interfere with routing belonging to another tenant.&lt;/p&gt;

&lt;p&gt;To me, that was the most important part of the discovery.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happened after I reported it?
&lt;/h3&gt;

&lt;p&gt;I submitted the finding to Traefik through its private security reporting process, including the reproduction steps and demonstrated impact.&lt;/p&gt;

&lt;p&gt;My report assessed the issue as High severity, with a CVSS score of 8.5.&lt;/p&gt;

&lt;p&gt;The maintainers ultimately closed the security report and handled the underlying issue as a regular bug rather than publishing it as a security vulnerability.&lt;/p&gt;

&lt;p&gt;The fix was released on &lt;strong&gt;October 28, 2026&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Although the report wasn’t accepted as a security advisory, I’m glad the underlying problem was addressed.&lt;/p&gt;

&lt;p&gt;The technical lesson remains valuable: an internal identifier shouldn’t allow two resources from different tenants to overwrite each other.&lt;/p&gt;

&lt;p&gt;And a Kubernetes namespace boundary is only useful if the software translating Kubernetes resources into runtime configuration preserves that boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovery #2: A TLS cache that skipped the security check
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/traefik/traefik/security/advisories/GHSA-28hp-c82p-8vqj" rel="noopener noreferrer"&gt;GHSA-28hp-c82p-8vqj&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Official severity: Low (CVSS 4.0 score 2.1)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The second finding was a different kind of issue.&lt;/p&gt;

&lt;p&gt;This time, the problem wasn’t how Traefik named an object.&lt;/p&gt;

&lt;p&gt;It was how Traefik reused one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The feature was working as intended… initially
&lt;/h3&gt;

&lt;p&gt;Traefik supports the &lt;code&gt;nginx.ingress.kubernetes.io/auth-tls-secret&lt;/code&gt; annotation, which allows an Ingress to reference a Kubernetes Secret containing a certificate authority used for mutual TLS client authentication.&lt;/p&gt;

&lt;p&gt;Normally, Traefik restricts cross-namespace access.&lt;/p&gt;

&lt;p&gt;The relevant setting is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;allowCrossNamespaceResources = false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s the default.&lt;/p&gt;

&lt;p&gt;An Ingress in one namespace shouldn’t be allowed to use another namespace’s CA Secret unless cross-namespace access is explicitly enabled.&lt;/p&gt;

&lt;p&gt;The provider did have a check for this.&lt;/p&gt;

&lt;p&gt;But the interesting part was &lt;strong&gt;when&lt;/strong&gt; that check ran.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens when the TLS option already exists?
&lt;/h3&gt;

&lt;p&gt;Traefik caches and reuses generated TLS options.&lt;/p&gt;

&lt;p&gt;That’s a sensible optimization. If multiple resources need equivalent configuration, there’s no reason to rebuild everything unnecessarily.&lt;/p&gt;

&lt;p&gt;However, I found that the cross-namespace authorization check happened when Traefik initially built a TLS option.&lt;/p&gt;

&lt;p&gt;When the option was already present in the shared cache, a subsequent Ingress could reuse it without going through the same namespace authorization check.&lt;/p&gt;

&lt;p&gt;Essentially:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;First Ingress
    |
    v
Check namespace permissions
    |
    v
Build TLS option
    |
    v
Store in shared cache

Later Ingress
    |
    v
TLS option already cached?
    |
    v
Reuse existing option
    |
    v
Namespace check skipped
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The issue was subtle because the original authorization logic existed.&lt;/p&gt;

&lt;p&gt;It just wasn’t applied on every relevant path through the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why that matters
&lt;/h3&gt;

&lt;p&gt;Suppose an Ingress in Namespace A legitimately references a CA Secret.&lt;/p&gt;

&lt;p&gt;Traefik builds the TLS option and stores it.&lt;/p&gt;

&lt;p&gt;Later, someone with permission to create an Ingress in Namespace B references the same CA Secret.&lt;/p&gt;

&lt;p&gt;Even with cross-namespace resources disabled, the existing cached option could be reused.&lt;/p&gt;

&lt;p&gt;That meant the second namespace could use a CA configuration it wasn’t supposed to reference.&lt;/p&gt;

&lt;p&gt;The issue also allowed limited information disclosure about whether the referenced CA Secret existed and was already in use.&lt;/p&gt;

&lt;p&gt;It did not disclose the Secret’s contents or private keys.&lt;/p&gt;

&lt;p&gt;This is why the official advisory classifies the issue as Low severity rather than High.&lt;/p&gt;

&lt;p&gt;Still, I find this kind of bug particularly interesting because it points to a broader engineering problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authorization is not a property of a cached object. It’s a decision about who is allowed to access that object.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Just because something was authorized for one requester doesn’t mean it’s authorized for everyone who references it later.&lt;/p&gt;

&lt;p&gt;I’ve worked extensively with backend systems, caching, and distributed architectures, and this is exactly the sort of edge case that can be overlooked when optimizing code.&lt;/p&gt;

&lt;p&gt;A cache hit feels harmless.&lt;/p&gt;

&lt;p&gt;Until it skips a security decision.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disclosure and official acknowledgement
&lt;/h3&gt;

&lt;p&gt;I reported this issue to Traefik, and the maintainers investigated and addressed it.&lt;/p&gt;

&lt;p&gt;The advisory was officially published on &lt;strong&gt;October 16, 2026&lt;/strong&gt; , under:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/traefik/traefik/security/advisories/GHSA-28hp-c82p-8vqj" rel="noopener noreferrer"&gt;GHSA-28hp-c82p-8vqj&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The affected versions were &lt;code&gt;v3.7.11&lt;/code&gt; through &lt;code&gt;v3.7.14&lt;/code&gt;, and the fix was released in &lt;strong&gt;Traefik v3.7.15&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The published advisory credits me as the reporter.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;CVE identifier has been requested and is currently pending assignment&lt;/strong&gt;. I’ll update this article once it’s assigned.&lt;/p&gt;

&lt;h2&gt;
  
  
  The interesting connection between these two findings
&lt;/h2&gt;

&lt;p&gt;After investigating both issues, something stood out to me.&lt;/p&gt;

&lt;p&gt;The vulnerabilities were technically different, but they shared a common theme.&lt;/p&gt;

&lt;p&gt;In the first finding, Traefik treated two different resources as if they had the same identity.&lt;/p&gt;

&lt;p&gt;In the second, Traefik reused an already-authorized configuration without checking whether the next resource was authorized to use it.&lt;/p&gt;

&lt;p&gt;One involved generated names.&lt;/p&gt;

&lt;p&gt;The other involved caching.&lt;/p&gt;

&lt;p&gt;Neither required some exotic exploitation technique.&lt;/p&gt;

&lt;p&gt;They came down to fairly ordinary backend implementation decisions.&lt;/p&gt;

&lt;p&gt;And that’s exactly why I think they’re worth studying.&lt;/p&gt;

&lt;p&gt;In a single-tenant application, these choices might not cause much trouble.&lt;/p&gt;

&lt;p&gt;But in a multi-tenant system, a small mistake in how objects are identified, stored, or reused can cross a boundary between customers or teams.&lt;/p&gt;

&lt;p&gt;That boundary needs to survive every layer of the implementation, not just the Kubernetes RBAC configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I’d look for in similar systems
&lt;/h2&gt;

&lt;p&gt;These discoveries reinforced a few things I now pay particular attention to when reviewing shared infrastructure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generated identifiers:&lt;/strong&gt; If a system builds unique keys by concatenating user-controlled values, can two different inputs produce the same key?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shared configuration maps:&lt;/strong&gt; Can one tenant’s resource silently overwrite another tenant’s entry?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Caching and authorization:&lt;/strong&gt; Does the authorization check still happen when the requested object comes from a cache?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security controls attached to generated resources:&lt;/strong&gt; What happens to authentication and rate limiting when a router or configuration object gets replaced?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-deterministic processing:&lt;/strong&gt; Could the order in which configuration is generated change the effective routing or security behavior?&lt;/p&gt;

&lt;p&gt;None of these questions is specific to Traefik.&lt;/p&gt;

&lt;p&gt;They’re equally relevant to API gateways, Kubernetes operators, service meshes, multi-tenant platforms, and ordinary backend applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclosure timeline and current status
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Discovery&lt;/th&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Router-name collision&lt;/td&gt;
&lt;td&gt;Reported privately, addressed as a regular bug, fix released October 28, 2026&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TLS-option authorization bypass&lt;/td&gt;
&lt;td&gt;Published as GHSA-28hp-c82p-8vqj on October 16, 2026; fixed in v3.7.15&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For clarity, my original 8.5 severity assessment belongs to the first report and does not represent an official Traefik security rating.&lt;/p&gt;

&lt;p&gt;The first security report was closed without a public advisory or CVE assignment.&lt;/p&gt;

&lt;p&gt;For the second, publicly acknowledged vulnerability, a CVE has been requested and is awaiting assignment.&lt;/p&gt;

&lt;p&gt;I appreciate the Traefik maintainers for reviewing the reports and addressing the underlying issues, even though the two findings went through different disclosure outcomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;One thing I like about security research is that you don’t always need to find a complicated vulnerability to uncover an important problem.&lt;/p&gt;

&lt;p&gt;Sometimes it’s a string concatenation.&lt;/p&gt;

&lt;p&gt;Sometimes it’s a cache lookup.&lt;/p&gt;

&lt;p&gt;Sometimes it’s a security check that exists in the code but doesn’t execute in the path you expected.&lt;/p&gt;

&lt;p&gt;The difficult part is often figuring out whether that small implementation detail actually changes the security boundary.&lt;/p&gt;

&lt;p&gt;For me, these two Traefik findings were a good reminder of something I’ve learned from building distributed systems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Isolation isn’t guaranteed just because you’ve separated resources at the infrastructure level. Every component that processes those resources has to maintain the separation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And sometimes, the best place to start looking is the most ordinary-looking code.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GHSA-vm53-8m79-wq7m&lt;/strong&gt; — Private router-name collision report; closed and addressed as a regular bug.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/traefik/traefik/security/advisories/GHSA-28hp-c82p-8vqj" rel="noopener noreferrer"&gt;GHSA-28hp-c82p-8vqj&lt;/a&gt;&lt;/strong&gt; — Official Traefik security advisory for the TLS-option authorization bypass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://github.com/traefik/traefik/releases/tag/v3.7.15" rel="noopener noreferrer"&gt;Traefik v3.7.15 release&lt;/a&gt;&lt;/strong&gt; — Patch for the published advisory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/traefik/traefik" rel="noopener noreferrer"&gt;Traefik GitHub repository&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  About the author
&lt;/h3&gt;

&lt;p&gt;I’m Lav Kumar Vishwakarma, a backend engineer and independent security researcher with over 10 years of experience building distributed systems. My research focuses on cloud infrastructure, application security, AI agents, and MCP security.&lt;/p&gt;

&lt;p&gt;You can find more of my engineering work and security research at &lt;a href="https://lavkumar.dev/" rel="noopener noreferrer"&gt;lavkumar.dev&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>kubernetessecurity</category>
      <category>traefik</category>
      <category>multitenancy</category>
      <category>vulnerabilityresearc</category>
    </item>
    <item>
      <title>The Server Was Up. Its Security Policy Wasn’t.</title>
      <dc:creator>Lav Kumar Vishwakarma</dc:creator>
      <pubDate>Thu, 13 Aug 2026 14:08:48 +0000</pubDate>
      <link>https://dev.to/lav_vishwakarma/the-server-was-up-its-security-policy-wasnt-2kej</link>
      <guid>https://dev.to/lav_vishwakarma/the-server-was-up-its-security-policy-wasnt-2kej</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwkg107t6gjoat44b5twc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwkg107t6gjoat44b5twc.png" alt="CVE-2026-16584" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What CVE-2026-16584 in the AWS API MCP Server taught me about MCP security, fail-open systems, and the controls we place between AI agents and real infrastructure.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;On July 23, 2026, AWS published a security advisory for a vulnerability I reported in the AWS API MCP Server. It was assigned &lt;strong&gt;CVE-2026-16584&lt;/strong&gt;, rated High, and given a CVSS v4.0 score of 7.3.&lt;/p&gt;

&lt;p&gt;My name appears in the acknowledgement as the independent researcher who reported it. That was a meaningful moment for me. I have spent much of my career building backend systems, and more recently I have been looking closely at the security boundaries around AI agents and MCP servers.&lt;/p&gt;

&lt;p&gt;Still, I do not want this post to be a victory lap. The interesting part is the failure itself because it is easy to understand, easy to underestimate, and relevant far beyond one open-source project.&lt;/p&gt;

&lt;p&gt;Here is the short version:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The server could start even when the data required to enforce its security policy had failed to load. Once that happened, the policy check could be skipped for the lifetime of the process.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The server was running. The security policy was not.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure note:&lt;/strong&gt; This article uses only information available in the public AWS security advisory. I am not publishing a proof of concept, step-by-step reproduction instructions, private communication, internal logs, or details that AWS has not made public.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What does the AWS API MCP Server do?
&lt;/h2&gt;

&lt;p&gt;The Model Context Protocol, or MCP, gives AI assistants a standard way to connect to tools and external systems. The AWS API MCP Server allows an assistant to interact with AWS services through AWS CLI commands.&lt;/p&gt;

&lt;p&gt;That is useful, but it also places the server on a sensitive boundary. A model is no longer only producing text. It can request an action against real cloud infrastructure.&lt;/p&gt;

&lt;p&gt;The server includes an optional, user-configured security policy. Administrators can use that policy to deny or gate selected AWS operations before they are executed.&lt;/p&gt;

&lt;p&gt;In normal operation, the flow is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The server loads the data needed to enforce the configured policy.&lt;/li&gt;
&lt;li&gt;A tool request arrives.&lt;/li&gt;
&lt;li&gt;The requested AWS operation is checked against the policy.&lt;/li&gt;
&lt;li&gt;The operation is allowed, denied, or sent through a gate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;CVE-2026-16584 affected the first step, which then changed what happened at the third.&lt;/p&gt;

&lt;h2&gt;
  
  
  What went wrong
&lt;/h2&gt;

&lt;p&gt;The AWS API MCP Server loaded its policy-enforcement data during startup. According to the advisory, if that initialization failed, the process could continue running without the enforcement data being available.&lt;/p&gt;

&lt;p&gt;When a request arrived later, the policy check could be skipped. When a security policy was configured without fail-closed modes enabled, configured deny and gate rules were not consulted. More importantly, this was not limited to a single request. The server could stay in that weaker state for the lifetime of the process.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;Expected behaviour&lt;/th&gt;
&lt;th&gt;Vulnerable behaviour&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Startup&lt;/td&gt;
&lt;td&gt;Policy data loads&lt;/td&gt;
&lt;td&gt;Policy data is unavailable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Readiness&lt;/td&gt;
&lt;td&gt;Server becomes ready after its controls are ready&lt;/td&gt;
&lt;td&gt;Server keeps running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request&lt;/td&gt;
&lt;td&gt;Policy evaluates the AWS operation&lt;/td&gt;
&lt;td&gt;Policy evaluation is skipped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Result&lt;/td&gt;
&lt;td&gt;Deny or gate rules apply&lt;/td&gt;
&lt;td&gt;That policy layer does not restrict the operation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Initialization failures happen in production. A dependency times out. A file is malformed. Permissions are wrong. Connectivity is degraded. None of that is unusual.&lt;/p&gt;

&lt;p&gt;The security question is what the application does after the failure.&lt;/p&gt;

&lt;p&gt;In this case, missing enforcement state could lead to permissive behaviour. That is a classic fail-open security problem: a control becomes unavailable, but the protected operation can continue.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The guard was not defeated during a request. It was missing before the request arrived.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why this matters for AI agent security
&lt;/h2&gt;

&lt;p&gt;When people discuss AI security, the conversation quickly moves to prompt injection, model manipulation, jailbreaks, and malicious tool descriptions. Those are real problems. But this vulnerability was not caused by the model doing something clever.&lt;/p&gt;

&lt;p&gt;It was a conventional backend security failure at an AI execution boundary.&lt;/p&gt;

&lt;p&gt;That distinction matters. MCP servers sit between an agent’s intent and an external action. If a permission check, approval gate, tenant boundary, tool allowlist, or sandbox is absent, the model does not need to break that control. The application may already be operating without it.&lt;/p&gt;

&lt;p&gt;This is why agentic AI security cannot be reduced to better prompts. The full execution path matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which credentials does the agent use?&lt;/li&gt;
&lt;li&gt;Which operations are exposed as tools?&lt;/li&gt;
&lt;li&gt;Where is authorization enforced?&lt;/li&gt;
&lt;li&gt;What happens when enforcement cannot initialize?&lt;/li&gt;
&lt;li&gt;Does the server remain healthy when a security dependency is unhealthy?&lt;/li&gt;
&lt;li&gt;Can the system distinguish “policy disabled” from “policy failed to load”?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are software architecture questions, not language-model questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the vulnerability did not bypass
&lt;/h2&gt;

&lt;p&gt;It is important to describe the impact accurately.&lt;/p&gt;

&lt;p&gt;CVE-2026-16584 bypassed the optional security-policy layer under the affected MCP server condition. It did not remove AWS IAM permissions from the credentials configured for the server.&lt;/p&gt;

&lt;p&gt;If those credentials allowed only read access to a small set of resources, IAM continued to enforce that boundary. If the credentials were broad, the missing MCP policy layer left a much larger set of actions available.&lt;/p&gt;

&lt;p&gt;The effective risk therefore depended heavily on credential scope.&lt;/p&gt;

&lt;p&gt;This is a practical example of why AWS IAM least privilege matters. Least privilege is not only about preventing an intended user from doing too much. It also limits the damage when another security layer fails in an unexpected way.&lt;/p&gt;

&lt;p&gt;An MCP policy can add useful context-specific restrictions, but it should not be the only boundary between an AI agent and a high-impact cloud operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The uncomfortable part: what does &lt;code&gt;None&lt;/code&gt; mean?
&lt;/h2&gt;

&lt;p&gt;The advisory maps the issue to &lt;a href="https://cwe.mitre.org/data/definitions/455.html" rel="noopener noreferrer"&gt;CWE-455: Non-exit on Failed Initialization&lt;/a&gt;. The name sounds dry, but the design problem behind it appears in many systems.&lt;/p&gt;

&lt;p&gt;Imagine a security component with three possible states:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The policy loaded successfully.&lt;/li&gt;
&lt;li&gt;The administrator intentionally disabled the policy.&lt;/li&gt;
&lt;li&gt;The administrator configured a policy, but it failed to load.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The second and third states must never be treated as equivalent.&lt;/p&gt;

&lt;p&gt;One is an explicit configuration decision. The other is a security failure. If both become the same empty, null, or false-like value in memory, request-handling code can easily interpret “not available” as “nothing to enforce.”&lt;/p&gt;

&lt;p&gt;That is not just an MCP concern. The same pattern can affect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authorization configuration;&lt;/li&gt;
&lt;li&gt;tenant context;&lt;/li&gt;
&lt;li&gt;policy caches;&lt;/li&gt;
&lt;li&gt;tool allowlists;&lt;/li&gt;
&lt;li&gt;approval workflows;&lt;/li&gt;
&lt;li&gt;audit pipelines;&lt;/li&gt;
&lt;li&gt;sandbox initialization; and&lt;/li&gt;
&lt;li&gt;secret and identity providers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A missing value is not neutral when that value decides what a system is allowed to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions I would now ask in every MCP security review
&lt;/h2&gt;

&lt;p&gt;This finding changed the way I think about reviewing agent infrastructure. I would not only test whether a deny rule works. I would also follow the control through its failure states.&lt;/p&gt;

&lt;p&gt;These are the questions I would ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the policy engine cannot initialize, can the server still report itself as ready?&lt;/li&gt;
&lt;li&gt;Is “disabled by configuration” represented differently from “failed to load”?&lt;/li&gt;
&lt;li&gt;Does the readiness check include security-critical dependencies?&lt;/li&gt;
&lt;li&gt;What happens if policy data becomes unavailable after startup?&lt;/li&gt;
&lt;li&gt;Are protected requests rejected while enforcement is degraded?&lt;/li&gt;
&lt;li&gt;Is a startup error visible only in logs, or does it actually stop unsafe operation?&lt;/li&gt;
&lt;li&gt;Do tests cover malformed configuration, timeouts, partial loading, and recovery?&lt;/li&gt;
&lt;li&gt;Does the underlying IAM role contain only the permissions required for this agent?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key test is not only:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does the security control block the operation?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is also:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can the application continue when the security control is unable to block anything?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Fix and recommended action
&lt;/h2&gt;

&lt;p&gt;AWS fixed the issue in &lt;code&gt;awslabs.aws-api-mcp-server&lt;/code&gt; version &lt;strong&gt;1.3.47&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Anyone using an affected version, from &lt;strong&gt;0.2.13 up to 1.3.46&lt;/strong&gt;, should upgrade to the latest version. Forks and derivative projects should confirm that they include the relevant fix rather than assuming their implementation is unaffected.&lt;/p&gt;

&lt;p&gt;The AWS advisory also lists two measures for users who cannot upgrade immediately:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the server with least-privilege IAM credentials scoped to the specific task.&lt;/li&gt;
&lt;li&gt;If the server started during degraded connectivity, restart it after connectivity is restored so the required policy data can load.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I would add one operational check: verify the version actually running in each environment. Updating a dependency declaration is not the same as confirming that every deployed instance has been replaced.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on responsible disclosure
&lt;/h2&gt;

&lt;p&gt;I reported the issue privately and worked with AWS through the coordinated vulnerability-disclosure process. The vulnerability was fixed before I wrote publicly about its design implications.&lt;/p&gt;

&lt;p&gt;Responsible disclosure is slower than posting a finding immediately, but the sequence matters. Users need a patch and clear mitigation guidance before a researcher turns a vulnerability into public content.&lt;/p&gt;

&lt;p&gt;For the same reason, I am keeping this discussion at the architectural level. There is enough information here for engineers to recognize and test the failure pattern without turning the post into an exploitation guide.&lt;/p&gt;

&lt;p&gt;I appreciate AWS for investigating the report, shipping the fix, publishing the advisory, and acknowledging my contribution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The lesson I am taking from CVE-2026-16584
&lt;/h2&gt;

&lt;p&gt;The most memorable security bugs are not always the most complicated ones.&lt;/p&gt;

&lt;p&gt;Many reviews focus on finding a clever way around a running control. CVE-2026-16584 points to a simpler question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What happens if the control never starts?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As MCP adoption grows, we will keep connecting AI agents to cloud platforms, databases, deployment systems, internal APIs, and other high-impact tools. The safety of those systems will depend on much more than model behaviour. It will depend on ordinary engineering details: initialization, state handling, readiness, credentials, error paths, and secure defaults.&lt;/p&gt;

&lt;p&gt;My main takeaway is one line:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If the policy is not ready, the server is not ready.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That principle applies to far more than this one AWS API MCP Server vulnerability.&lt;/p&gt;

&lt;p&gt;If you are building or reviewing an MCP server, check its startup failure paths. They may tell you more about its real security posture than the happy path does.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/security/security-bulletins/2026-063-aws/" rel="noopener noreferrer"&gt;AWS security bulletin: CVE-2026-16584 — AWS API MCP Server Security Policy Bypass via Startup Failure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nvd.nist.gov/vuln/detail/CVE-2026-16584" rel="noopener noreferrer"&gt;NVD entry for CVE-2026-16584&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cwe.mitre.org/data/definitions/455.html" rel="noopener noreferrer"&gt;CWE-455: Non-exit on Failed Initialization&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  About the author
&lt;/h2&gt;

&lt;p&gt;Lav Kumar Vishwakarma is a lead backend engineer and independent security researcher working on agentic AI security, MCP permission boundaries, secure tool execution, runtime isolation, and production AI systems. AWS credited him for responsibly reporting CVE-2026-16584.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>mcp</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
