Back to Checks
m365

Application registrations should not use client secrets

entra_app_registration_client_secret_unused
Service: entraSeverity: medium
OfficialBuilt-inVerified
Categories:identity-accesse3
Resource Type:NotDefined

Microsoft Entra application registrations should not have any secret credentials configured. This check audits the current state of every application registration and reports those that hold one or more secrets. Both expired and active secrets are reported, since expired entries are credential clutter that should be cleaned up.

Risk

Secrets are bearer credentials that are easy to leak (committed to repositories, copied into CI variables, shared via chat). Once leaked, a secret can be used from anywhere on the internet until it is rotated. Both expired and active secrets increase the attack surface and represent credential clutter.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler m365 --checks entra_app_registration_client_secret_unused

Recommendation

Remove every secret from the affected application registrations so they no longer rely on long-lived shared secrets. Enable the default app management policy to block new secrets from being added.

Remediation

Other

1Navigate to Microsoft Entra admin center (https://entra.microsoft.com)
2Go to Applications > App registrations
3Select the flagged application
4Go to Certificates & secrets
5Delete all client secrets under the 'Client secrets' tab
6Add a certificate or configure federated identity credentials instead

Check Code

from prowler.lib.check.models import Check, CheckReportM365
from prowler.providers.m365.services.entra.entra_client import entra_client


class entra_app_registration_client_secret_unused(Check):
    """
    Ensure that application registrations do not use password credentials (client secrets).

    This check evaluates application registrations in Microsoft Entra ID to identify
    those with password credentials (client secrets). Applications should authenticate
    using certificates, federated identity credentials, or managed identities instead.
    Both expired and active password credentials are flagged, since expired entries are
    credential clutter that should be cleaned up.

    - PASS: The application has no password credentials.
    - FAIL: The application has one or more password credentials that should be removed.
    """

    def execute(self) -> list[CheckReportM365]:
        findings = []

        for app_id, app in entra_client.app_registrations.items():
            report = CheckReportM365(
                metadata=self.metadata(),
                resource=app,
                resource_name=app.name or app.app_id,
                resource_id=app_id,
            )

            num_secrets = len(app.password_credentials)
            if num_secrets > 0:
                report.status = "FAIL"
                secret_details = []
                for cred in app.password_credentials:
                    detail = cred.display_name or cred.key_id
                    if cred.end_date_time:
                        detail += f" (expires: {cred.end_date_time})"
                    secret_details.append(detail)

                if num_secrets > 5:
                    displayed = ", ".join(secret_details[:5])
                    displayed += f" (and {num_secrets - 5} more)"
                else:
                    displayed = ", ".join(secret_details)

                report.status_extended = (
                    f"App registration {app.name} has {num_secrets} "
                    f"password credential(s) (client secrets): {displayed}."
                )
            else:
                report.status = "PASS"
                report.status_extended = (
                    f"App registration {app.name} does not use password credentials."
                )

            findings.append(report)

        return findings