
Security advisory: Azure APIM Developer Portal allows cross-tenant account registration by bypassing UI signup restrictions. Reported to MSRC twice - closed as "by design".
Status (01.12.2025): This vulnerability is still live and exploitable. Microsoft has not patched this issue and considers it "by design."
A security vulnerability in Azure API Management (APIM) Developer Portal allows attackers to register accounts on any APIM instance that has Basic Authentication enabled, even when administrators have disabled user signup in the portal UI.
This bypass enables cross-tenant account creation, potentially allowing unauthorized access to API documentation, subscription keys, and other resources exposed through the Developer Portal.
| Date | Action |
|---|---|
| 2025-09-30 | Vulnerability discovered |
| 2025-09-30 | Initial report submitted to MSRC |
| 2025-10-30 | MSRC response: Closed as "not a vulnerability" |
| 2025-11-01 | Second report submitted to MSRC with additional details |
| 2025-11-20 | MSRC response: Closed as "by design" |
| 2025-11-20 | Reported to CERT-FI |
| 2025-11-26 | Public disclosure |
| 2025-11-27 | CVE requested from MITRE |
| 2026-07-09 | CVE-2025-66390 assigned by MITRE TL-Root/CNA-LR |
When Azure APIM is configured with Basic Authentication for the Developer Portal, administrators can disable user registration through the Azure Portal UI. However, this only hides the signup form in the portal interface.
The underlying signup API endpoint remains active and accepts registration requests directly, bypassing the UI restriction entirely.
Two issues combine to create this vulnerability:
The attack requires two APIM instances:
Steps:
Host header from their instance to the target instanceKey technical detail: The cross-tenant bypass works by manipulating the Host header in the signup POST request. The /signup endpoint processes requests based on the Host header without validating tenant boundaries.
Example request manipulation:
POST /signup HTTP/1.1
Host: target-apim.developer.azure-api.net <-- Changed from attacker's instance
Origin: https://attacker-apim.developer.azure-api.net
Content-Type: application/json
{"challenge":{...},"signupData":{"email":"[email protected]",...}}
The core issue: disabling signup in the UI does not disable the underlying API. The API endpoint accepts cross-tenant requests based on the Host header.
Your APIM instance is vulnerable if:
Your APIM instance is NOT vulnerable if:
Key point: Disabling signup in the Azure Portal UI is NOT sufficient. The Basic Authentication identity provider must be completely removed to prevent cross-tenant signup bypass.
Use these property values to identify vulnerable APIM instances via Azure Resource Graph, ARM templates, or Azure Policy.
| Property Path | Vulnerable Value | Description |
|---|---|---|
properties.developerPortalStatus | Enabled | Developer Portal is accessible |
sku.name | Developer, Basic, Standard, Premium | Non-Consumption tiers (Consumption tier has limited portal features) |
The Basic Authentication identity provider is a separate resource under the APIM instance:
Resource Type: Microsoft.ApiManagement/service/identityProviders
Name: basic
Vulnerable if exists: The presence of a basic identity provider resource indicates Basic Authentication is configured.
Resource Type: Microsoft.ApiManagement/service/portalsettings/signup
Property: properties.enabled
| Property | Value | Meaning |
|---|---|---|
properties.enabled | true | Signup visible in UI |
properties.enabled | false | Signup hidden in UI (API still works if Basic Auth exists!) |
Use this query to find potentially vulnerable APIM instances:
resources
| where type == "microsoft.apimanagement/service"
| where properties.developerPortalStatus == "Enabled"
| where sku.name != "Consumption"
| project name, resourceGroup, subscriptionId, location, sku.name, properties.developerPortalStatus
To check for Basic Auth identity providers:
resources
| where type == "microsoft.apimanagement/service/identityproviders"
| where name endswith "/basic"
| project apimInstance=tostring(split(id, "/providers/Microsoft.ApiManagement/service/")[1]), resourceGroup, subscriptionId
Check Developer Portal status:
az apim show --name <apim-name> --resource-group <rg-name> --query "{name:name, portalStatus:developerPortalStatus, sku:sku.name}"
List identity providers (check for 'basic'):
az apim identity-provider list --resource-group <rg-name> --service-name <apim-name> --query "[].name"
Check signup settings:
az rest --method get --url "https://management.azure.com/subscriptions/<sub-id>/resourceGroups/<rg-name>/providers/Microsoft.ApiManagement/service/<apim-name>/portalsettings/signup?api-version=2022-08-01" --query "properties.enabled"
| Condition | Property/Resource | Vulnerable Value |
|---|---|---|
| Portal enabled | properties.developerPortalStatus | == 'Enabled' |
| Non-Consumption SKU | sku.name | != 'Consumption' |
| Basic Auth exists | identityProviders/basic resource | Resource exists |
| Signup hidden (bypass possible) | portalsettings/signup.properties.enabled | == false (with Basic Auth) |