scoring-rules.json

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "description": "M365 Security Assessment Score - Scoring Rules Configuration",
  "baseScore": 100,
  "rules": [
    {
      "id": "sensitivity-labels",
      "name": "Missing Sensitivity Labels",
      "description": "Sites without information protection labels applied",
      "enabled": true,
      "maxPenalty": 15,
      "calculation": "percentage-based",
      "threshold": 50,
      "message": "Missing sensitivity labels on {percentage}% of sites: -{deduction} points",
      "notes": "Penalty scales from 0 to 15 points. Full penalty applied when >50% of sites are missing labels."
    },
    {
      "id": "anonymous-sharing",
      "name": "Anonymous Sharing Enabled",
      "description": "Sites that allow anonymous access (anyone with link, no sign-in required)",
      "enabled": true,
      "maxPenalty": 20,
      "calculation": "flat",
      "threshold": 1,
      "message": "Sites with anonymous sharing enabled ({count}): -{deduction} points",
      "notes": "CRITICAL RISK: Full 20 point penalty if ANY site allows anonymous access.",
      "severity": "critical"
    },
    {
      "id": "anonymous-links",
      "name": "Active Anonymous Sharing Links",
      "description": "Sites with active anonymous sharing links created",
      "enabled": true,
      "maxPenalty": 15,
      "calculation": "flat",
      "threshold": 1,
      "message": "Sites with active anonymous links ({count}): -{deduction} points",
      "notes": "CRITICAL RISK: Full 15 point penalty if ANY site has active anonymous links.",
      "severity": "critical"
    },
    {
      "id": "external-users",
      "name": "External Users (Guests)",
      "description": "Sites with external users who have been granted access",
      "enabled": true,
      "maxPenalty": 15,
      "calculation": "prevalence-based",
      "threshold": 100,
      "message": "Sites with external users ({count}): -{deduction} points",
      "notes": "Penalty scales based on how many sites with external sharing actually have guest users. 100% prevalence = full penalty.",
      "severity": "high"
    },
    {
      "id": "adhoc-permissions",
      "name": "Ad-Hoc Permissions",
      "description": "Sites where users have direct permissions (not via SharePoint groups)",
      "enabled": true,
      "maxPenalty": 10,
      "calculation": "percentage-based",
      "threshold": 20,
      "message": "Sites with ad-hoc permissions ({count}): -{deduction} points",
      "notes": "Penalty scales from 0 to 10 points. Full penalty when >20% of sites have ad-hoc permissions.",
      "severity": "medium"
    },
    {
      "id": "external-access-prevalence",
      "name": "High External Access Prevalence",
      "description": "Too many sites have external sharing enabled",
      "enabled": true,
      "maxPenalty": 10,
      "calculation": "percentage-above-threshold",
      "threshold": 75,
      "message": "High external access prevalence ({percentage}%): -{deduction} points",
      "notes": "Penalty starts at 75% threshold. Full penalty when 100% of sites have external access enabled.",
      "severity": "medium"
    },
    {
      "id": "disabled-users-licenses",
      "name": "Disabled Users with Licenses",
      "description": "Inactive users still consuming paid licenses (cost optimization)",
      "enabled": true,
      "maxPenalty": 10,
      "calculation": "percentage-based",
      "threshold": 50,
      "message": "Disabled users with licenses ({count}): -{deduction} points",
      "notes": "Penalty scales from 0 to 10 points. Full penalty when >50% of disabled users still have licenses.",
      "severity": "low"
    },
    {
      "id": "app-secrets-expiring",
      "name": "App Registrations with Expired/Expiring Secrets",
      "description": "Applications that have expired secrets or secrets expiring in the next 30 days",
      "enabled": true,
      "maxPenalty": 15,
      "calculation": "flat",
      "threshold": 1,
      "message": "Apps with expired or soon-to-expire secrets ({count}): -{deduction} points",
      "notes": "SECURITY RISK: Full penalty if any app has an expired secret or a secret expiring within 30 days.",
      "severity": "high"
    },
    {
      "id": "unused-app-registrations",
      "name": "Unused App Registrations",
      "description": "Applications with no sign-in activity in the last 30 days (for apps where usage data is available)",
      "enabled": true,
      "maxPenalty": 10,
      "calculation": "flat",
      "threshold": 1,
      "message": "Unused app registrations ({count}): -{deduction} points",
      "notes": "Security hygiene risk: stale app registrations should be reviewed or removed.",
      "severity": "medium"
    },
    {
      "id": "sensitive-app-registrations",
      "name": "Sensitive App Registrations",
      "description": "Applications with elevated, write-capable, or privilege-granting permissions",
      "enabled": true,
      "maxPenalty": 15,
      "calculation": "flat",
      "threshold": 1,
      "message": "Sensitive app registrations ({count}): -{deduction} points",
      "notes": "Apps are marked sensitive by privileged-permission detection patterns in this file.",
      "severity": "high"
    },
    {
      "id": "group-owner-governance",
      "name": "Group Owner Governance Violations",
      "description": "Groups with owner count outside allowed range or group principals as owners",
      "enabled": true,
      "maxPenalty": 10,
      "calculation": "flat",
      "threshold": 1,
      "message": "Group owner governance violations ({count}): -{deduction} points",
      "notes": "Applies when owner count is below minOwners or above maxOwners, or owner is a group when flagGroupOwners=true.",
      "severity": "medium"
    },
    {
      "id": "site-owner-governance",
      "name": "Site Owner Governance Violations",
      "description": "Sites with owner/admin count outside allowed range or group principals with full control",
      "enabled": true,
      "maxPenalty": 15,
      "calculation": "flat",
      "threshold": 1,
      "message": "Site owner governance violations ({count}): -{deduction} points",
      "notes": "For group-connected sites, group owner metrics are reused.",
      "severity": "high"
    }
  ],
  "ownerGovernance": {
    "enabled": true,
    "minOwners": 2,
    "maxOwners": 5,
    "flagGroupOwners": true
  },
  "privilegedPermissionDetection": {
    "enabled": true,
    "minPrivilegedPermissionCount": 3,
    "excludePermissionPatterns": [
      "^openid$",
      "^profile$",
      "^email$",
      "^offline_access$",
      "^User\\.Read$"
    ],
    "alwaysSensitivePermissionPatterns": [
      "^Directory\\.AccessAsUser\\.All$",
      "^AppRoleAssignment\\.ReadWrite\\.All$",
      "^DelegatedPermissionGrant\\.ReadWrite\\.All$",
      "^RoleManagement\\.ReadWrite\\..*$",
      "^RoleAssignmentSchedule\\.ReadWrite\\..*$",
      "^RoleEligibilitySchedule\\.ReadWrite\\..*$",
      "^Application\\.ReadWrite\\..*$",
      "^Directory\\.ReadWrite\\.All$",
      "^Sites\\.FullControl\\.All$",
      "^Sites\\.Manage\\.All$",
      "^Exchange\\.ManageAsApp$",
      "^GroupMember\\.ReadWrite\\.All$",
      "^Group\\.ReadWrite\\.All$",
      "^User\\.ReadWrite\\.All$",
      "^RoleManagement\\.ReadWrite\\.Directory$"
    ],
    "privilegedPermissionPatterns": [
      "\\b(ReadWrite|Write|Manage|FullControl|Delete|Create|Update|Send|AccessAsUser|PrivilegedOperations|ReadWrite\\.All|ReadWrite\\.OwnedBy)\\b",
      "^(RoleManagement|RoleAssignmentSchedule|RoleEligibilitySchedule|Policy\\.ReadWrite|AppRoleAssignment\\.ReadWrite|DelegatedPermissionGrant\\.ReadWrite|Directory\\.ReadWrite|Application\\.ReadWrite|Sites\\.(Manage|FullControl)|GroupMember\\.ReadWrite|Group\\.ReadWrite|User\\.ReadWrite).*"
    ]
  },
  "grades": [
    {
      "grade": "Excellent",
      "minScore": 90,
      "maxScore": 100,
      "color": "green",
      "description": "Strong security posture with minimal risks"
    },
    {
      "grade": "Good",
      "minScore": 80,
      "maxScore": 89,
      "color": "green",
      "description": "Good security with minor improvements recommended"
    },
    {
      "grade": "Fair",
      "minScore": 70,
      "maxScore": 79,
      "color": "yellow",
      "description": "Address identified security concerns"
    },
    {
      "grade": "Poor",
      "minScore": 60,
      "maxScore": 69,
      "color": "yellow",
      "description": "Significant security risks present"
    },
    {
      "grade": "Critical",
      "minScore": 0,
      "maxScore": 59,
      "color": "red",
      "description": "Immediate remediation required"
    }
  ],
  "exclusions": {
    "description": "Sites to exclude from all analyses",
    "patterns": [
      "*-my.sharepoint.com/personal/*",
      "*/search"
    ],
    "notes": "OneDrive sites and the search center are excluded from site counts and scoring."
  },
  "calculationMethods": {
    "flat": "Fixed penalty if threshold is met (count >= threshold)",
    "percentage-based": "Penalty scales linearly from 0 to maxPenalty based on percentage (100% = maxPenalty when percentage >= threshold)",
    "prevalence-based": "Penalty scales based on prevalence among a subset (e.g., external users among external-enabled sites)",
    "percentage-above-threshold": "Penalty only applies above threshold, scales from threshold to 100%"
  }
}