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

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
OriginandAccess-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
- PortSwigger: Exploiting CORS misconfigurations for Bitcoins and bounties
- HackerOne report 430249
- Identity-Aware Proxy misconfiguration in Google Cloud
- From discovery to exploit: a beginner's guide to CORS bugs
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.
More articles

HTTP2Shell: the Brotli flaw reaches far beyond Node.js
HTTP2Shell is not a new flaw but CVE-2026-111497 in any software with a Brotli decoder. Who is affected, and why the version number misleads.
- 5 min read

Node2Shell: why patching Node alone is not enough
Node2Shell exploits a flaw in the Brotli decoder that Node.js bundles. The fix ships in Node 22.23.4, 24.22.1 and 26.12.1 – and in Brotli itself.
- 5 min read

Fortinet hardening release: patching without an advisory
Fortinet shipped critical fixes for FortiOS, FortiManager and FortiAnalyzer on 22 October 2026. The advisories with CVE ids only follow on 10 November.
- 5 min read
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