Azure / Azure/azure-cli

Security Issue: "az ad sp create-for-rbac" destroys existing integrations and assigns permissions to the wrong identity!

Open
#32,299 5 comments 0 reactions 1 assignee Claimed by @jiasli View on GitHub
act-identity-squad Auto-Assign Auto-Resolve Azure CLI Team bug Graph Security-Issue
Dominant language
Python
Stars
4.6k
Forks
3.5k
Avg merge
3d 2h
Merged PRs (30d)
60

Description

### Describe the bug

This command (and likely the other variations) performs object lookups in graph by display name. This is fundamentally inappropriate especially for a security-focused command that is meant to create a new identity and permission. Instead, this command attempts to find any existing one, and remove its existing credentials, set new ones, and assign RBAC to whatever it found.

Display name is not unique for applications or service principals, can be edited at any time, and can be different between them. Yet these commands treat display name like a durable identifier and attempt make arbitrary credential and rbac modifications to resolved identities.

### Related command

az ad sp create-for-rbac

### Errors

n/a

### Issue script & Debug output

Take a look at this sequence of calls (I have edited the values of IDs etc for the purposes of this comment):

```shell
az ad sp create-for-rbac -n $appDisplayName --role 'Azure Service Bus Data Owner' --scopes /subscriptions/$($SubscriptionId) --debug
```

This command begins by trying to find ANY existing service principal with that display name:

```shell
GET /v1.0/servicePrincipals?$filter=displayName%20eq%20%27MessagingTestApp%27

{"@odata.context":https://graph.microsoft.com/v1.0/$metadata#servicePrincipals,"value":[]}
```

This is already a huge problem, there can be many service principals already existing. This command is meant to create a new application, not find some arbitrary identity in the customer directory and start messing with its configuration and potentially grant it new permissions!

In our case, no service principal was found with this displayname, so the command next proceeds to try and find ANY application with that display name:

```shell
GET /v1.0/applications?$filter=startswith%28displayName%2C%27MessagingTestApp%27%29 HTTP/1.1

{"@odata.context":https://graph.microsoft.com/v1.0/$metadata#applications,"value":[{
"id":"cfbf39d0-df91-4ea9-95f3-f6931f6d282a","createdDateTime":"2025-10-16T23:50:48.7381945Z","deletedDateTime":null,"appId":"2f1
5aec7-a6e3-43f9-b802-94627dc4e511","description":null,"displayName":"MessagingTestApp","identifierUris":[],"notes":null,"signInA
udience":null,"tags":[],"additionalData":[],"api":{"requestedAccessTokenVersion":null},"appRoles":[],"info":{"logoUrl":null,"mar
ketingUrl":null,"privacyStatementUrl":null,"supportUrl":null,"termsOfServiceUrl":null},"keyCredentials":[],"passwordCredentials"
:[{"customKeyIdentifier":"","displayName":"rbac","endDateTime":"2026-10-16T23:53:17Z","hint":"Q2O","keyId":"6dd17918-2845-4121-8
fd4-35c0ffc7e235","secretText":null,"startDateTime":"2025-10-16T23:53:17Z"}],"publicClient":{"redirectUris":[]},"spa":{"redirect
Uris":[]},"web":{"homePageUrl":null,"logoutUrl":null,"redirectUris":[],"implicitGrantSettings":{"enableIdTokenIssuance":false,"e
nableAccessTokenIssuance":false}}}]}
```

In our case, it has found an already-existing application, that someone else could've created for a completely different application / test environment! It then proceeds to patch the display name on this application for no reason, since it just looked this up by display name:

```shell
PATCH /v1.0/applications/cfbf39d0-df91-4ea9-95f3-f6931f6d282a HTTP/1.1
{"displayName": "MessagingTestApp"}
```

Next, it does another GET request for the same application it already found (why?):

```shell
GET /v1.0/applications/cfbf39d0-df91-4ea9-95f3-f6931f6d282a HTTP/1.1

{"@odata.context":https://graph.microsoft.com/v1.0/$metadata#applications/$entity,"i
d":"cfbf39d0-df91-4ea9-95f3-f6931f6d282a","createdDateTime":"2025-10-16T23:50:48.7381945Z","deletedDateTime":null,"appId":"2f15a
ec7-a6e3-43f9-b802-94627dc4e511","description":null,"displayName":"MessagingTestApp","identifierUris":[],"notes":null,"signInAud
ience":null,"tags":[],"additionalData":[],"api":{"requestedAccessTokenVersion":null},"appRoles":[],"info":{"logoUrl":null,"marke
tingUrl":null,"privacyStatementUrl":null,"supportUrl":null,"termsOfServiceUrl":null},"keyCredentials":[],"passwordCredentials":[
{"customKeyIdentifier":"","displayName":"rbac","endDateTime":"2026-10-16T23:53:17Z","hint":"Q2O","keyId":"6dd17918-2845-4121-8fd
4-35c0ffc7e235","secretText":null,"startDateTime":"2025-10-16T23:53:17Z"}],"publicClient":{"redirectUris":[]},"spa":{"redirectUr
is":[]},"web":{"homePageUrl":null,"logoutUrl":null,"redirectUris":[],"implicitGrantSettings":{"enableIdTokenIssuance":false,"ena
bleAccessTokenIssuance":false}}}
```

Then, it proceeds to just remove the password credentials from this application completely! This breaks whatever was actually using that!!

```shell
POST /v1.0/applications/cfbf39d0-df91-4ea9-95f3-f6931f6d282a/removePassword HTTP/1.1
```

It then places a new one on the application:

```shell
POST /v1.0/applications/cfbf39d0-df91-4ea9-95f3-f6931f6d282a/addPassword HTTP/1.1
{"passwordCredential": {"displayName": "rbac", "endDateTime": "2026-10-16T23:53:49Z",
"startDateTime": "2025-10-16T23:53:49Z"}}

{"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#microsoft.graph.password
Credential","customKeyIdentifier":null,"displayName":"rbac","endDateTime":"2026-10-16T23:53:49Z","hint":"65x","keyId":"29fadcbe-
70e1-4a45-8fc3-e97c093b701a","secretText":"[redacted]","startDateTime":"2025-10-16T23:53:49Z"}
```

Lasty, it attempts to create a service principal for this application, but one already exists, so it fails:

```shell
POST /v1.0/servicePrincipals HTTP/1.1
{"appId": "2f15aec7-a6e3-43f9-b802-94627dc4e511", "accountEnabled": true}

{"error":{"code":"Request_MultipleObjectsWithSameKeyValue","message":"Another object with the
same value for property servicePrincipalNames already exists.","details":[{"code":"ObjectConflict","message":"The service
principal cannot be created, updated, or restored because the service principal name 2f15aec7-a6e3-43f9-b802-94627dc4e511 is
already in use.","target":"servicePrincipalNames"}]}}
```

### Expected behavior

This command should NEVER assume modification for an existing application or service principal, and none of these commands should ever do lookups based on display name. Let the customer grep by display name in a separate call and be responsible to pass-in the specific and discrete appId or objectId for an existing identity to modify, otherwise, this command and its counterpart(s) should ONLY create net-new identities.

### Environment Summary

azure-cli 2.67.0 *

### Additional context

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.