Back to blog
AzureBest PracticesCloud SecurityNetworkingOperations & Compliance

Application Gateway WAF Not Enabled: Closing the Gap in Your Azure Edge

Learn why an Azure Application Gateway without WAF exposes your apps to OWASP attacks, and how to enable, tune, and enforce a WAF policy step by step.

TL;DR

This check flags Azure Application Gateways running without a Web Application Firewall (WAF), which leaves your backend apps exposed to OWASP Top 10 attacks like SQL injection and XSS. Fix it by upgrading the gateway to a WAF-enabled SKU and attaching a WAF policy in Prevention mode.

An Azure Application Gateway is a layer 7 load balancer. It terminates HTTP/HTTPS traffic, routes requests based on URL paths and host headers, and offloads SSL. That puts it directly in the path of every request hitting your web apps, which makes it the natural place to inspect and block malicious traffic. The trouble is, that inspection only happens when the Web Application Firewall is switched on, and plenty of gateways get deployed without it.

The appgateway_nowaf check looks at each Application Gateway in your subscription and reports any that are running on a non-WAF SKU or that have no WAF policy attached. If the gateway is forwarding traffic to your applications without any inspection layer, this check fires.


What this check detects

Azure Application Gateway comes in two flavors of SKU tier:

  • Standard / Standard_v2 — pure load balancing and routing, no traffic inspection.
  • WAF / WAF_v2 — everything Standard does, plus a Web Application Firewall that inspects requests against managed rule sets.

The check returns a failed result when a gateway is on a Standard tier (no WAF capability at all), or when it is on a WAF tier but has no firewall policy associated and no inline WAF configuration enabled. Either way, traffic is flowing through unfiltered.

Note: On the v2 SKUs, Azure has moved WAF configuration into a standalone WAF policy resource that you attach to the gateway. Older v1 gateways used inline WAF config on the gateway itself. New deployments should use WAF policies, and Microsoft has deprecated the v1 SKUs entirely.


Why it matters

An Application Gateway without a WAF is a fast, well-configured pipe that delivers attacker traffic straight to your application servers. The gateway will happily forward a malicious payload exactly as it forwards a legitimate request, because routing logic does not care what is inside the request body.

Here is what that exposure looks like in practice:

  • SQL injection. An unfiltered request like ?id=1' OR '1'='1 reaches your database layer. If any endpoint has a parameter that ends up in a query, you are relying entirely on your application code to catch it.
  • Cross-site scripting (XSS). Reflected or stored payloads pass through untouched, ready to execute in a victim's browser.
  • Path traversal and file inclusion. Requests like ../../etc/passwd are forwarded verbatim to vulnerable backends.
  • Bot and scanner traffic. Automated tools probe for known CVEs, exposed admin panels, and default credentials. A WAF with managed rules blocks a large share of this noise before it touches your app.
  • Zero-day window. When a new vulnerability drops (think Log4Shell), Microsoft's managed rule sets are often updated within hours. Without a WAF, your only protection is patching every backend yourself, which takes far longer.

The business impact runs from data breaches and defacement to compliance failures. PCI DSS, for example, explicitly calls for either a WAF or equivalent technical controls in front of public-facing web applications. If you are processing card data behind a gateway with no WAF, you have a finding waiting to happen on your next audit.

A WAF is not a replacement for secure code. It is a second layer that buys you time and catches the mistakes that slip through. Defense in depth means you do not bet everything on a single control.


How to fix it

The remediation depends on which SKU your gateway is currently running. The recommended path is to land on the WAF_v2 SKU with a dedicated WAF policy.

Step 1: Check the current SKU

az network application-gateway show \
  --resource-group myResourceGroup \
  --name myAppGateway \
  --query "sku" -o json

If the tier comes back as Standard_v2, you need to add WAF. If it is the old Standard (v1), plan a migration to v2 first, since v1 is on the path to retirement.

Step 2: Create a WAF policy

Create a managed-rule WAF policy. Start in Detection mode so you can review what it would block before flipping to enforcement.

az network application-gateway waf-policy create \
  --resource-group myResourceGroup \
  --name myWafPolicy

# Set it to Detection mode initially and attach the managed rule set
az network application-gateway waf-policy policy-setting update \
  --resource-group myResourceGroup \
  --policy-name myWafPolicy \
  --mode Detection \
  --state Enabled

az network application-gateway waf-policy managed-rule rule-set add \
  --resource-group myResourceGroup \
  --policy-name myWafPolicy \
  --type OWASP \
  --version 3.2

Step 3: Attach the policy to the gateway

Warning: The WAF_v2 SKU costs more than Standard_v2 because it bills for capacity units that include WAF processing. Review the pricing for your expected throughput before rolling this out across many gateways, and budget for the change.

# Upgrade the SKU to WAF_v2 if needed
az network application-gateway update \
  --resource-group myResourceGroup \
  --name myAppGateway \
  --sku WAF_v2

# Associate the WAF policy
az network application-gateway update \
  --resource-group myResourceGroup \
  --name myAppGateway \
  --set firewallPolicy.id=$(az network application-gateway waf-policy show \
    --resource-group myResourceGroup \
    --name myWafPolicy --query id -o tsv)

Step 4: Validate, then switch to Prevention mode

Let the policy run in Detection mode for a few days to a week. Review the WAF logs to find legitimate traffic that triggers rules (false positives are common with strict OWASP rules) and tune exclusions or custom rules. Once the noise is sorted, switch to enforcement:

az network application-gateway waf-policy policy-setting update \
  --resource-group myResourceGroup \
  --policy-name myWafPolicy \
  --mode Prevention \
  --state Enabled

Danger: Flipping straight to Prevention mode without a detection period can block legitimate users. Aggressive OWASP rules frequently flag normal traffic such as JSON bodies, file uploads, or special characters in form fields. Always tune first, then enforce, or you risk an outage that looks like a WAF bug.

Console steps (quick reference)

  1. Go to Application Gateways in the Azure portal and select your gateway.
  2. Under Configuration, change the tier to WAF V2 if it is on Standard.
  3. Open the Web application firewall blade and create or associate a WAF policy.
  4. Set the policy mode to Detection, assign the OWASP managed rule set, and save.
  5. After reviewing logs, change the mode to Prevention.

Infrastructure as code

If you manage gateways through Terraform, define the WAF policy and bind it directly so no gateway can be created without one. Here is a Terraform example using the AzureRM provider:

resource "azurerm_web_application_firewall_policy" "main" {
  name                = "myWafPolicy"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location

  policy_settings {
    enabled = true
    mode    = "Prevention"
  }

  managed_rules {
    managed_rule_set {
      type    = "OWASP"
      version = "3.2"
    }
  }
}

resource "azurerm_application_gateway" "main" {
  name                = "myAppGateway"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location

  sku {
    name     = "WAF_v2"
    tier     = "WAF_v2"
    capacity = 2
  }

  firewall_policy_id = azurerm_web_application_firewall_policy.main.id

  # ... gateway IP, frontend, backend, and listener config ...
}

The Bicep equivalent sets the sku.tier to WAF_v2 and references a Microsoft.Network/ApplicationGatewayWebApplicationFirewallPolicies resource through the gateway's firewallPolicy property.

Tip: Define one or two shared WAF policies per environment and reference them across gateways instead of writing inline rules each time. Centralizing the policy means a rule tweak or a new exclusion ships everywhere at once, and your IaC stays DRY.


How to prevent it from happening again

Fixing a single gateway is easy. Keeping every future gateway compliant is the real goal. A few layers help here.

Azure Policy

Use a built-in or custom Azure Policy to deny the creation of Application Gateways that are not on a WAF SKU, or that have no WAF policy attached. A deny policy stops the misconfiguration at deployment time rather than catching it after the fact.

{
  "if": {
    "allOf": [
      {
        "field": "type",
        "equals": "Microsoft.Network/applicationGateways"
      },
      {
        "field": "Microsoft.Network/applicationGateways/sku.tier",
        "notIn": [ "WAF", "WAF_v2" ]
      }
    ]
  },
  "then": {
    "effect": "deny"
  }
}

CI/CD gates

Scan your IaC before it merges. Tools like Checkov, tfsec, and Terrascan have rules that flag Application Gateways without WAF. Wire one into your pipeline so a pull request fails when someone drops in a Standard SKU.

# Run Checkov against your Terraform in CI
checkov -d ./infra --framework terraform \
  --check CKV_AZURE_120  # App Gateway WAF enabled

Continuous monitoring

Policies and pipeline checks cover new resources, but drift happens. Someone disables a policy during an incident, or a gateway gets re-created by hand. Continuous scanning with Lensix re-runs appgateway_nowaf across your subscriptions on a schedule, so a gateway that loses its WAF shows up on the next pass instead of waiting for an audit.


Best practices

  • Always run in Prevention mode in production. Detection mode logs attacks but blocks nothing. Use it only for tuning, then enforce.
  • Keep the managed rule set current. Use the latest OWASP Core Rule Set version your region supports, and enable the Microsoft bot protection rule set to cut down scanner traffic.
  • Send WAF logs somewhere useful. Stream diagnostic logs to Log Analytics or a SIEM so you can investigate blocked requests, spot attack campaigns, and refine exclusions.
  • Tune exclusions narrowly. When you hit a false positive, scope the exclusion to the specific rule and request attribute rather than disabling whole rule groups. Broad exclusions quietly recreate the gap the WAF was meant to close.
  • Pair the WAF with rate limiting and custom rules. Add custom rules for geo-blocking or IP allow-lists where it fits your threat model, and use rate limiting to blunt brute-force and credential-stuffing attempts.
  • Do not treat the WAF as your only defense. Keep patching backends, validating input in application code, and using managed identities. The WAF is one layer in a stack, not the whole stack.

An Application Gateway is a great place to add this protection because the traffic already passes through it. Turning on WAF is mostly a SKU choice and a policy attachment, and the payoff is a measurable drop in the attack surface of every app behind it. Get it enabled, tune it once, and let policy and continuous scanning keep it that way.