{
  "id": "CB-M365-APPS-010",
  "standard": "m365",
  "version": "main",
  "url": "https://baselines.cirsec.org/b/m365/CB-M365-APPS-010",
  "json": "https://baselines.cirsec.org/b/m365/CB-M365-APPS-010.json",
  "yaml": "https://baselines.cirsec.org/b/m365/CB-M365-APPS-010.yml",
  "profiles_effective": [
    "hardened"
  ],
  "license": "Text CC BY 4.0, code Apache-2.0",
  "attribution": "CIRSEC Baselines, https://baselines.cirsec.org",
  "control": {
    "id": "CB-M365-APPS-010",
    "title": "Clean up and rotate existing application credentials",
    "finding": {
      "title": "Applications keep client secrets, expired credentials or certificates that are never rotated",
      "description": "Old secrets and long-lived certificates on applications and service principals remain usable by anyone who copied them, and nobody notices when they are abused."
    },
    "status": "active",
    "profiles": [
      "hardened"
    ],
    "risk": {
      "severity": "medium"
    },
    "assessment": "manual",
    "tags": [
      "applications",
      "workload-identities",
      "credentials",
      "client-secrets",
      "certificates",
      "hygiene"
    ],
    "description": "Existing credentials on application registrations and service principals are reviewed at least\nevery 90 days:\n\n- client secrets are replaced by certificates, federated identity credentials or managed\n  identities, and removed once unused;\n- expired credentials, and credentials not used for 30 days or more, are deleted;\n- credentials expiring within **{{ credential_expiry_warning_days }}** days are renewed or\n  removed by their owner;\n- no certificate is older than its rotation period (CB-M365-APPS-009);\n- no service principal holding a privileged directory role authenticates with a client secret;\n- Microsoft first-party service principals carry no credential added by the tenant.\n",
    "rationale": "The app management policy (CB-M365-APPS-006 to CB-M365-APPS-009) only governs new\ncredentials. The secrets and certificates created before it stay valid until they expire, and\nmany tenants have secrets valid for years on applications with broad permissions. Attackers who\ncompromise an administrator routinely add a credential to an existing privileged application or\nto a Microsoft service principal, because it is rarely reviewed.\n",
    "impact": "Each application owner must migrate or rotate credentials. Removing a credential still used by\nan integration breaks it: check the sign-in logs of the service principal first.\n",
    "parameters": [
      {
        "name": "credential_expiry_warning_days",
        "type": "integer",
        "description": "Number of days before expiry at which a credential must be renewed or removed.",
        "unit": "days",
        "default": 30,
        "minimum": 1
      }
    ],
    "audit": {
      "manual": "1. Sign in to the Microsoft Entra admin center (https://entra.microsoft.com) as at least a\n   Global Reader.\n2. Browse to **Entra ID** > **Overview** > **Recommendations** and open **Remove unused\n   credentials from applications**, **Renew expiring application credentials** and **Renew\n   expiring service principal credentials**. Note every active item.\n3. Browse to **Entra ID** > **Monitoring & health** > **Usage & insights** > **Application\n   credential activity** to see credentials and their last use.\n4. In Microsoft Graph PowerShell (scope `Application.Read.All`), list credentials:\n   `Get-MgApplication -All -Property displayName,appId,passwordCredentials,keyCredentials`\n   and `Get-MgServicePrincipal -All -Property displayName,appId,appOwnerOrganizationId,passwordCredentials,keyCredentials`.\n   Flag secrets, credentials with `endDateTime` in the past or within\n   {{ credential_expiry_warning_days }} days, certificates whose `startDateTime` is older than\n   the rotation period, and any credential on a service principal whose\n   `appOwnerOrganizationId` is Microsoft (`f8cdef31-a31e-4b4a-93e4-5f571e91255a`).\n5. Cross-check with **Entra ID** > **Roles & admins**: service principals assigned a privileged\n   role must not have a client secret.\n6. Fail if any flagged credential has no documented owner and plan, or if a privileged service\n   principal or a Microsoft service principal carries a secret.\n"
    },
    "remediation": {
      "manual": "1. For each flagged application, identify the owner and the workload that uses it (service\n   principal sign-in logs: **Entra ID** > **Monitoring & health** > **Sign-in logs** >\n   **Service principal sign-ins**).\n2. Replace secrets with a certificate stored in a key vault, a federated identity credential or\n   a managed identity, then remove the secret under **App registrations** > the application >\n   **Certificates & secrets**.\n3. Delete expired credentials and credentials unused for 30 days or more.\n4. Remove any credential found on a Microsoft first-party service principal and investigate how\n   it was added (audit log activity **Add service principal credentials**).\n5. Role required: Application Administrator or Cloud Application Administrator, or owner of the\n   application. Graph alternative: `Remove-MgApplicationPassword`, `Remove-MgServicePrincipalPassword`,\n   `Update-MgApplication -KeyCredentials`.\n",
      "rollback": "A deleted secret cannot be restored: create a new one, through an exception to\nCB-M365-APPS-006, and update the workload.\n"
    },
    "references": [
      {
        "title": "Remove unused credentials from apps recommendation",
        "url": "https://learn.microsoft.com/entra/identity/monitoring-health/recommendation-remove-unused-credential-from-apps",
        "publisher": "Microsoft",
        "kind": "vendor-doc",
        "accessed": "2026-10-24"
      },
      {
        "title": "Renew expiring application credentials recommendation",
        "url": "https://learn.microsoft.com/entra/identity/monitoring-health/recommendation-renew-expiring-application-credential",
        "publisher": "Microsoft",
        "kind": "vendor-doc",
        "accessed": "2026-10-24"
      },
      {
        "title": "Configure Microsoft Entra for increased security - protect identities and secrets",
        "url": "https://learn.microsoft.com/entra/fundamentals/zero-trust-protect-identities",
        "publisher": "Microsoft",
        "kind": "vendor-doc",
        "accessed": "2026-10-24"
      },
      {
        "title": "Maester test catalogue (MT.1027, MT.1057, MT.1199)",
        "url": "https://maester.dev/docs/tests/",
        "publisher": "Maester",
        "kind": "tool",
        "accessed": "2026-10-24"
      }
    ],
    "mappings": [
      {
        "framework": "nist-800-53r5",
        "framework_version": "5.1.1",
        "id": "IA-5",
        "relation": "related"
      },
      {
        "framework": "nist-800-53r5",
        "framework_version": "5.1.1",
        "id": "AC-2(3)",
        "relation": "related"
      }
    ],
    "threats": [
      {
        "framework": "mitre-attack",
        "id": "T1098.001"
      },
      {
        "framework": "mitre-attack",
        "id": "T1552.001"
      }
    ],
    "related_controls": [
      {
        "id": "CB-M365-APPS-006",
        "type": "related"
      },
      {
        "id": "CB-M365-APPS-009",
        "type": "related"
      },
      {
        "id": "CB-M365-APPS-016",
        "type": "related"
      }
    ],
    "authors": [
      {
        "name": "Alice",
        "github": "Sn0wAlice"
      }
    ],
    "introduced_in": "0.1.0",
    "created": "2026-10-24",
    "updated": "2026-10-24"
  }
}