Back to Checks
m365

Privileged users do not have credentials exposed on vulnerable endpoints

defenderxdr_endpoint_privileged_user_exposed_credentials
Service: defenderxdrSeverity: critical
OfficialBuilt-inVerified
Categories:secretsidentity-accesse5
Resource Type:NotDefined

Microsoft Defender XDR's Security Exposure Management detects when credentials from users with Entra ID privileged roles are present on vulnerable devices. Privileged users may have authentication artifacts (CLI secrets, cookies, tokens) exposed on endpoints with high risk scores.

Prowler logoProwlerprowler-provider-m365

Risk

Exposed credentials on vulnerable endpoints enable account takeover through stolen tokens or cookies, Conditional Access bypass via primary refresh tokens, lateral movement to sensitive resources, and persistence until tokens are explicitly revoked.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler m365 --checks defenderxdr_endpoint_privileged_user_exposed_credentials

Recommendation

Privileged users should only authenticate from secure, hardened devices with low exposure scores. Implement Privileged Access Workstations (PAWs) and enforce device compliance policies through Conditional Access to prevent credential exposure on vulnerable endpoints.

Remediation

Other

1Navigate to Microsoft Defender portal at https://security.microsoft.com
2Go to Exposure Management > Attack surface > Attack paths
3Review the exposed credential findings for privileged users
4For each affected device, review the risk and exposure score in Device Inventory
5Remediate endpoint vulnerabilities and improve device security posture
6Revoke affected user sessions and rotate credentials
7Consider implementing Privileged Access Workstations (PAWs) for privileged users

Check Code

"""Check for exposed credentials of privileged users in Defender XDR.

This check identifies privileged users whose authentication credentials
(CLI secrets, cookies, tokens) are exposed on vulnerable endpoints.
"""

from prowler.lib.check.models import Check, CheckReportM365
from prowler.providers.m365.services.defenderxdr.defenderxdr_client import (
    defenderxdr_client,
)


class defenderxdr_endpoint_privileged_user_exposed_credentials(Check):
    """Check if privileged users have exposed credentials on endpoints.

    This check queries Microsoft Defender XDR's ExposureGraphEdges
    table via the Advanced Hunting API to identify privileged users whose
    authentication artifacts (CLI secrets, user cookies, sensitive tokens)
    are exposed on endpoints with high risk or exposure scores.

    Prerequisites:
    1. ThreatHunting.Read.All permission granted
    2. Microsoft Defender for Endpoint (MDE) enabled and deployed on devices

    Results:
    - PASS: No exposed credentials found OR MDE enabled but no devices
    - FAIL: Exposed credentials detected OR MDE not enabled (blind spot)
    - MANUAL: Defender XDR could not be queried (missing permission or
      Security Exposure Management not available), so the check cannot
      be evaluated
    """

    def execute(self) -> list[CheckReportM365]:
        """Execute the check for exposed credentials of privileged users.

        Returns:
            List[CheckReportM365]: A list of reports with check results.
        """
        findings = []

        # Step 1: Check MDE status
        mde_status = defenderxdr_client.mde_status

        # API call failed - likely missing ThreatHunting.Read.All permission
        if mde_status is None:
            report = CheckReportM365(
                metadata=self.metadata(),
                resource={},
                resource_name="Defender XDR",
                resource_id="mdeStatus",
            )
            report.status = "MANUAL"
            report.status_extended = (
                "Cannot evaluate credential exposure for privileged users: "
                "unable to query Microsoft Defender XDR Advanced Hunting. "
                "Verify that the ThreatHunting.Read.All permission is granted "
                "to the scanning application."
            )
            findings.append(report)
            return findings

        # MDE not enabled - this is a security blind spot
        if mde_status == "not_enabled":
            report = CheckReportM365(
                metadata=self.metadata(),
                resource={},
                resource_name="Defender XDR",
                resource_id="mdeStatus",
            )
            report.status = "FAIL"
            report.status_extended = (
                "Microsoft Defender for Endpoint is not enabled. "
                "Without MDE there is no visibility into credential "
                "exposure on endpoints."
            )
            findings.append(report)
            return findings

        # MDE enabled but no devices - PASS (no endpoints to evaluate)
        if mde_status == "no_devices":
            report = CheckReportM365(
                metadata=self.metadata(),
                resource={},
                resource_name="Defender XDR",
                resource_id="mdeDevices",
            )
            report.status = "PASS"
            report.status_extended = (
                "Microsoft Defender for Endpoint is enabled but no devices "
                "are onboarded. No endpoints to evaluate for credential "
                "exposure."
            )
            findings.append(report)
            return findings

        # Step 2: MDE is active with devices - check for exposed credentials
        exposed_credentials = defenderxdr_client.exposed_credentials_privileged_users

        # API call failed for exposed credentials query
        if exposed_credentials is None:
            report = CheckReportM365(
                metadata=self.metadata(),
                resource={},
                resource_name="Defender XDR",
                resource_id="exposedCredentials",
            )
            report.status = "MANUAL"
            report.status_extended = (
                "Cannot evaluate credential exposure for privileged users: "
                "unable to query Security Exposure Management. Verify that "
                "Security Exposure Management is enabled in the tenant."
            )
            findings.append(report)
            return findings

        # Found exposed credentials - report each one
        if exposed_credentials:
            for exposed_user in exposed_credentials:
                report = CheckReportM365(
                    metadata=self.metadata(),
                    resource=exposed_user,
                    resource_name=exposed_user.target_node_name,
                    resource_id=(exposed_user.target_node_id or exposed_user.edge_id),
                )
                report.status = "FAIL"

                credential_info = (
                    f" ({exposed_user.credential_type})"
                    if exposed_user.credential_type
                    else ""
                )
                report.status_extended = (
                    f"Privileged user {exposed_user.target_node_name} has "
                    f"exposed credentials{credential_info} on device "
                    f"{exposed_user.source_node_name}."
                )
                findings.append(report)
        else:
            # No exposed credentials found - full visibility, no risk detected
            report = CheckReportM365(
                metadata=self.metadata(),
                resource={},
                resource_name="Defender XDR Exposure Management",
                resource_id="exposedCredentials",
            )
            report.status = "PASS"
            report.status_extended = (
                "No exposed credentials found for privileged users on "
                "vulnerable endpoints."
            )
            findings.append(report)

        return findings