@@ -24,7 +24,7 @@ function Test-Assessment-26884 {
2424 SfiPillar = ' Protect networks' ,
2525 TenantType = (' Workforce' ),
2626 TestId = 26884 ,
27- Title = ' Bot protection ruleset is enabled and assigned in Azure Front Door WAF' ,
27+ Title = ' Bot protection rule set is enabled and assigned in Azure Front Door WAF' ,
2828 UserImpact = ' Low'
2929 )]
3030 [CmdletBinding ()]
@@ -131,6 +131,7 @@ resources
131131 PolicyName=name,
132132 SkuName=tostring(sku.name),
133133 EnabledState=tostring(properties.policySettings.enabledState),
134+ Mode=tostring(properties.policySettings.mode),
134135 ManagedRuleSets=properties.managedRules.managedRuleSets,
135136 SecurityPolicyLinks=properties.securityPolicyLinks,
136137 SubscriptionId=subscriptionId
@@ -183,13 +184,23 @@ resources
183184 $domainsProtected = 0
184185 $securityPolicyConfigured = ' No'
185186 $wafEnabled = ' N/A'
187+ $wafMode = ' N/A'
188+ $wafIsPremium = $false
189+ $hasEnabledRule = $false
186190
187191 if ($securityPolicies.Count -gt 0 ) {
188192 $securityPolicyConfigured = ' Yes'
189193
190194 foreach ($secPolicy in $securityPolicies ) {
191195 # Reset domain count for each security policy to avoid accumulation
192196 $currentPolicyDomainCount = 0
197+
198+ # Reset Bot Manager-related fields for each security policy to avoid stale values
199+ $botManagerEnabled = ' No'
200+ $ruleSetVersion = ' N/A'
201+ $ruleSetAction = ' N/A'
202+ $hasEnabledRule = $false
203+
193204 $wafPolicyRef = $secPolicy.properties.parameters.wafPolicy.id
194205
195206 if ($wafPolicyRef ) {
@@ -210,6 +221,7 @@ resources
210221 $wafPolicy = $wafPolicyLookup [$associatedWafPolicyId ]
211222 $associatedWafPolicyName = $wafPolicy.PolicyName
212223 $wafEnabled = $wafPolicy.EnabledState
224+ $wafMode = $wafPolicy.Mode
213225 $wafIsPremium = $wafPolicy.SkuName -eq ' Premium_AzureFrontDoor'
214226
215227 # Check for Bot Manager rule set
@@ -226,8 +238,37 @@ resources
226238 $ruleSetAction = ' Per-rule defaults'
227239 }
228240
229- # Check if WAF policy is enabled and Bot Manager is present
230- if ($wafIsPremium -and $wafEnabled -eq ' Enabled' ) {
241+ # Check if at least one rule is enabled in the Bot Manager rule set
242+ # Rules are enabled by default unless explicitly disabled. Azure WAF managed rule
243+ # overrides typically list only changed rules; non-overridden rules remain enabled
244+ # by default. To avoid false negatives, we assume there is at least one enabled
245+ # rule unless we have conclusive evidence that the entire ruleset is disabled.
246+ $hasEnabledRule = $true
247+ if ($ruleSet.ruleGroupOverrides ) {
248+ # We intentionally do not flip $hasEnabledRule to $false when all *overridden*
249+ # rules are disabled, because there may still be non-overridden (and thus
250+ # enabled) rules in the Bot Manager ruleset. Missing or empty overrides are
251+ # treated as default-enabled.
252+ foreach ($override in $ruleSet.ruleGroupOverrides ) {
253+ if ($override.rules ) {
254+ foreach ($rule in $override.rules ) {
255+ if ($rule.enabledState -ne ' Disabled' ) {
256+ # At least one explicitly enabled/non-disabled rule found.
257+ # Keep $hasEnabledRule = $true and break out early.
258+ break
259+ }
260+ }
261+ }
262+ else {
263+ # No explicit rule overrides for this group: cannot conclude all rules
264+ # are disabled; non-overridden rules remain enabled by default.
265+ break
266+ }
267+ }
268+ }
269+
270+ # Check if WAF policy is enabled, in Prevention mode, and Bot Manager is present with at least one rule enabled
271+ if ($wafIsPremium -and $wafEnabled -eq ' Enabled' -and $wafMode -eq ' Prevention' -and $hasEnabledRule ) {
231272 $hasValidBotProtection = $true
232273 # Only count domains from security policy with valid bot protection
233274 $domainsProtected = $currentPolicyDomainCount
@@ -255,9 +296,12 @@ resources
255296 ProfileId = $profileId
256297 SkuName = $fdProfile.SkuName
257298 WAFPolicyName = $associatedWafPolicyName
299+ WAFPolicyId = $associatedWafPolicyId
258300 WAFEnabled = $wafEnabled
301+ WAFMode = $wafMode
259302 SecurityPolicyConfigured = $securityPolicyConfigured
260303 BotManagerEnabled = $botManagerEnabled
304+ HasEnabledRule = $hasEnabledRule
261305 RuleSetVersion = $ruleSetVersion
262306 RuleSetAction = $ruleSetAction
263307 DomainsProtected = $domainsProtected
@@ -295,10 +339,10 @@ resources
295339 $passed = ($failedItems.Count -eq 0 ) -and ($passedItems.Count -gt 0 )
296340
297341 if ($passed ) {
298- $testResultMarkdown = " ✅ Bot protection ruleset is enabled and assigned to Azure Front Door WAF , providing protection against malicious bot traffic.`n`n %TestResult%"
342+ $testResultMarkdown = " ✅ All Azure Front Door WAF policies attached to Azure Front Door are enabled, running in Prevention mode, and have the Bot Manager rule set (Microsoft_BotManagerRuleSet) with at least one rule enabled , providing protection against malicious bot traffic.`n`n %TestResult%"
299343 }
300344 else {
301- $testResultMarkdown = " ❌ Bot protection ruleset is not enabled or not assigned to Azure Front Door WAF , leaving web applications vulnerable to automated attacks and malicious bots.`n`n %TestResult%"
345+ $testResultMarkdown = " ❌ One or more Azure Front Door WAF policies attached to Azure Front Door are disabled, running in Detection mode, do not have the Bot Manager rule set configured, or have all Bot Manager rules disabled , leaving web applications vulnerable to automated attacks and malicious bots.`n`n %TestResult%"
302346 }
303347
304348 # endregion Assessment Logic
@@ -316,8 +360,8 @@ resources
316360 if ($evaluationResults.Count -gt 0 ) {
317361 $tableRows = " "
318362 $formatTemplate = @'
319- | Subscription | Profile name | SKU | WAF policy | Bot protection enabled | Rule set version | Rule set action | Domains protected | Status |
320- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
363+ | Subscription | Profile name | SKU | WAF policy | WAF mode | Bot protection enabled | Enabled state | Rule set version | Rule set action | Domains protected | Status |
364+ | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
321365{0}
322366
323367'@
@@ -326,8 +370,17 @@ resources
326370 $subscriptionLink = " [$ ( Get-SafeMarkdown $result.SubscriptionName ) ]($portalSubscriptionBaseLink /$ ( $result.SubscriptionId ) /overview)"
327371 $profileLink = " [$ ( Get-SafeMarkdown $result.ProfileName ) ]($portalResourceBaseLink $ ( $result.ProfileId ) /securityPolicies)"
328372 $statusText = if ($result.Status -eq ' Pass' ) { ' ✅ Pass' } else { ' ❌ Fail' }
373+ $wafModeDisplay = if ($result.WAFMode -eq ' Prevention' ) { ' ✅ Prevention' } else { " ⚠️ $ ( $result.WAFMode ) " }
374+ $enabledStateDisplay = if ($result.WAFEnabled -eq ' Enabled' ) { ' ✅ Enabled' } else { ' ❌ Disabled' }
375+
376+ # Create WAF policy link if policy exists
377+ $wafPolicyDisplay = if ($result.WAFPolicyId ) {
378+ " [$ ( Get-SafeMarkdown $result.WAFPolicyName ) ]($portalResourceBaseLink $ ( $result.WAFPolicyId ) /overview)"
379+ } else {
380+ $ (Get-SafeMarkdown $result.WAFPolicyName )
381+ }
329382
330- $tableRows += " | $subscriptionLink | $profileLink | $ ( $result.SkuName ) | $ ( Get-SafeMarkdown $result .WAFPolicyName ) | $ ( $result.BotManagerEnabled ) | $ ( $result.RuleSetVersion ) | $ ( $result.RuleSetAction ) | $ ( $result.DomainsProtected ) | $statusText |`n "
383+ $tableRows += " | $subscriptionLink | $profileLink | $ ( $result.SkuName ) | $wafPolicyDisplay | $wafModeDisplay | $ ( $result.BotManagerEnabled ) | $enabledStateDisplay | $ ( $result.RuleSetVersion ) | $ ( $result.RuleSetAction ) | $ ( $result.DomainsProtected ) | $statusText |`n "
331384 }
332385
333386 $mdInfo += $formatTemplate -f $tableRows
@@ -369,7 +422,7 @@ resources
369422
370423 $params = @ {
371424 TestId = ' 26884'
372- Title = ' Bot protection ruleset is enabled and assigned in Azure Front Door WAF'
425+ Title = ' Bot protection rule set is enabled and assigned in Azure Front Door WAF'
373426 Status = $passed
374427 Result = $testResultMarkdown
375428 }
0 commit comments