Skip to content
Analysis

Trust no Origin: the CORS mirage in Azure AKS ingress

A CORS flaw in the Azure Application Routing add-on for AKS accepts malicious origins when they appear before an allowed value in the Origin header.

  • by blacklens.io Team
  • Published
  • Updated
  • 6 min read
Illustration of a glowing padlock with circuit lines and the words "Access is allowed"

Note: this article describes a vulnerability that was still actively exploitable at the time of publication. The affected configuration was reproduced and the vulnerability verified together with a blacklens.io partner. The vulnerability was first reported to Microsoft (MSRC) through a responsible disclosure process, and Microsoft was given sufficient time to analyse it before publication.

It all started with a routine penetration test. After many other attack vectors had been examined and ruled out, one particular part of the infrastructure came into focus. What looked unremarkable at first led to the discovery of a vulnerability. There is no fix, and the product remains a widely used building block of internet infrastructure, running in countless organisations. Possibly for years to come.

What is CORS – and why does it matter?

CORS (Cross-Origin Resource Sharing) is a security mechanism that helps web servers allow or deny access to certain resources based on where a request comes from (the Origin header). These resources can include sensitive data such as tokens or other secrets.

The risk of a CORS vulnerability depends heavily on the implementation and architecture. It becomes particularly dangerous when CORS misconfigurations are combined with other vulnerabilities. That is often underestimated.

One basic principle should therefore always apply: security has to be designed in from the start. Relying blindly on individual security mechanisms is not good practice.

In an ideal world, this article could end here. Unfortunately, it cannot.

The vulnerability at a glance

The behaviour stems from the way the Azure Application Routing add-on for Azure Kubernetes Service (AKS) configures and uses the underlying ingress-nginx controller. Under certain conditions, it allows the CORS origin check to be bypassed. The cause is faulty validation of Origin headers by the managed NGINX ingress controller. Fortunately, modern browsers handle the resulting responses correctly, which reduces the severity considerably.

Azure Application Routing

Azure Application Routing provides a managed NGINX ingress controller for AKS. If CORS is enabled there through the standard ingress annotations, the controller checks incoming Origin headers to decide which sources are granted access.

The problem arises when the Origin header contains several values or is set more than once and the values come in the right order. In those cases the ingress does not validate correctly. Instead, it reflects malicious origins in the response as well.

First, the correct behaviour. An attacker can, for example, send a request with the following headers:

Malicious request – correct behaviour

The critical part: as mentioned, the order of the origins changes the behaviour. If a legitimate origin value is sent first, the ingress correctly rejects the request. But if the malicious origin is set first and an allowed one after it, the ingress accepts the entire header.

Malicious request – incorrect behaviour

This also works with two separately set headers. In both cases the ingress accepts the invalid CORS request and responds with the protected resource – in this example, a secret.

The result is a CORS response that contains several origins and does not comply with the W3C specification, so it is not "internet-compliant". This behaviour points to inconsistent validation logic in the managed ingress.

Real-world impact

In summary, the ingress shows the following incorrect behaviour:

  • Several origins are reflected, including injected ones.
  • A single embedded trusted origin is enough for App Routing to accept the whole list.
  • Credentialed CORS is possible (if enabled).
  • The system does not block access (in the reverse order, it behaves correctly).

So this is a flaw in server-side validation.

Modern browsers usually block such responses. In server-side trust models, microservice architectures or API gateways, however, the vulnerability can cause serious security problems if CORS is not checked again in a further layer or other security measures do not step in in time.

Known CORS cases show that in practice this leads to vulnerabilities such as:

  • Bypassing origin-based authentication
  • Bypassing cross-tenant or cross-application trust relationships
  • Unauthorised API access
  • Token theft in internal OAuth and OIDC login flows
  • Privilege escalation in microservice architectures
  • Incorrect routing or policy bypass in API gateways and service meshes
  • False trust assumptions within corporate infrastructure

A concrete Azure example shows where underestimating CORS can lead: the EmojiDeploy vulnerability resulted in remote code execution in Azure web services and earned a bounty of 30,000 US dollars.

Source: The Hacker News

What affected organisations can do

The underlying Ingress-NGINX stack is expected to reach end of life gradually from March 2026 (Kubernetes project announcement), and Azure support is currently planned only until 30 November 2026 (Azure update). Affected organisations should therefore check early whether migrating to an alternative, unaffected ingress stack or to the Gateway API makes sense.

Running existing deployments indefinitely without changes can carry considerable risk in the long term. In practice, though, many Kubernetes clusters stay pinned to older component versions for years. Implementation flaws then persist long after official support ends and turn into hidden risks.

Regardless of this specific vulnerability, one basic security rule applies: no single security mechanism should ever be the only safeguard.

Mechanisms such as CORS in particular are often overestimated or misused in practice. Complex cloud and microservice architectures should therefore always combine several layers of security, for example:

  • additional server-side validation of Origin and Access-Control-Allow-Origin
  • consistent authentication and authorisation that does not depend on HTTP headers
  • additional security controls at the API gateway or service mesh layer

Whether your own infrastructure or a third-party provider you use is affected by such implementation flaws can often only be established reliably through targeted penetration tests or security assessments.

Where blacklens.io comes in

With continuous scanning and optional Penetration Testing as a Service, the platform helps detect vulnerabilities in internal, external and cloud infrastructure early.

Whether it is Active Directory misconfigurations that enable lateral movement in the network, misconfigurations in Azure and other cloud environments, or vulnerabilities in externally reachable services and web applications: blacklens.io gives you an overview of your entire attack surface and helps you prioritise the most critical risks first.

"We consistently rely on zero trust and established DevSecOps methods in our software solutions. Even though this finding did not result in a critical vulnerability in our customer solutions, it shows us that despite the greatest care, external factors can always create attack surface, and that regular manual penetration tests are important to avoid blind spots."

– Mario te Best, WareTec IT Solutions GmbH (translated from German)

Technical details

Affected products and configuration:

  • Azure Kubernetes Service (AKS)
  • Azure App Routing add-on
  • Managed NGINX ingress controller
  • Ingress class webapprouting.kubernetes.azure.com
  • Default configuration, created as described below

Creating the cluster

az aks create `
  --resource-group $ResourceGroupName `
  --name $ClusterName `
  --location $Location `
  --enable-app-routing `
  --generate-ssh-keys

Minimal Kubernetes configuration

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: cors
  annotations:
    # Enable CORS
    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, PATCH, OPTIONS"
    nginx.ingress.kubernetes.io/cors-allow-origin: "http://trusted-example.com, http://127.0.0.1"
    nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
    nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"
    nginx.ingress.kubernetes.io/cors-expose-headers: "Content-Length,Content-Range"
    nginx.ingress.kubernetes.io/cors-max-age: "1728000"
    # Use custom response
    nginx.ingress.kubernetes.io/configuration-snippet: |
      default_type image/svg+xml;
      return 200 "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"200\" height=\"200\"><rect width=\"200\" height=\"200\" fill=\"blue\"/><text x=\"50%\" y=\"50%\" text-anchor=\"middle\" fill=\"white\" font-size=\"20\">CORS Test</text></svg>";
spec:
  ingressClassName: webapprouting.kubernetes.azure.com
  rules:
    - http:
        paths:
          - path: /
            pathType: ImplementationSpecific
            backend:
              service:
                name: does-not-exist
                port:
                  number: 3000

Example request

Origin: https://attacker.com, http://trusted-example.com

Or with two separately set headers:

Origin: https://attacker.com
Origin: http://trusted-example.com

Ingress response

Access-Control-Allow-Origin: https://attacker.com, http://trusted-example.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Headers: DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization
Access-Control-Expose-Headers: Content-Length,Content-Range
Access-Control-Max-Age: 1728000

Disclosure timeline with Microsoft

  • 2 December 2025: report submitted to MSRC
  • 3 December 2025: MSRC assigns case number VULN-167454, status changes to "Review/Repro"
  • 19 January 2026: request for a triage and status update
  • 21 January 2026: MSRC says its engineers are still reproducing the behaviour; request for information on the planned publication
  • 28 January 2026: MSRC informed about the draft article in progress
  • 2 February 2026: MSRC confirms and passes the information on to its engineers
  • 5 March 2026: article completed, MSRC informed
  • 9 March 2026: official public disclosure

References

Conclusion and outlook

The case shows how even small implementation details in widely used infrastructure components can cause security problems.

With the end of life of the Ingress-NGINX controller approaching, many existing deployments will stay in operation even though their technical basis is no longer actively developed. Vulnerabilities in ingress stacks deployed worldwide can therefore persist in production environments for years – just waiting to be found in a pentest or by an attacker.

In modern cloud architectures in particular, one simple rule applies: Trust no Origin.

Frequently asked questions

The CORS vulnerability in the Azure Application Routing add-on for AKS affects the managed NGINX ingress controller. If the Origin header contains several values and a malicious origin comes before an allowed one, the ingress accepts the whole list, reflects it in Access-Control-Allow-Origin and serves the protected resource. Modern browsers usually block such responses, but in server-side trust models, microservice architectures and API gateways the behaviour can lead to serious security problems.

Share

More articles

See your attack surface within 24 hours.

We set up your workspace and walk you through the first findings.

  • 14 days free, all features
  • No credit card required
  • We walk you through your first findings