default ALLOW

# =========================================================
# VNetArmor WAF Rules - v2 DSL only
# Order/SOP:
# 1000-990  health/ready/live allow only
# 989-800   security BLOCK rules, before any business ALLOW
# 799-700   sensitive body/header blocks/logs
# 699-600   admin/internal guards
# 599-500   observability/log-only watch rules
# 499-100   business ALLOW rules
# default   ALLOW/BLOCK per deployment
#
# Syntax:
# rule <id> <ALLOW|BLOCK|LOG|CHECK|DEFAULT> priority <number> [chain continue]
# when all|any|not
#   match <field> /regex/i
#   exists <field>
#   all|any|not ... end
# end
# end
# =========================================================

rule waf_health_allow ALLOW priority 1000
when any
  match http.path /^\/health$/
  match http.path /^\/ready$/
  match http.path /^\/live$/
end
end

# -------------------------
# Security blocks
# -------------------------

rule waf_bad_methods BLOCK priority 980
when any
  match http.method /^(TRACE|TRACK|CONNECT|PUT|DELETE|PATCH)$/i
end
end

rule waf_scanner_ua BLOCK priority 970
when any
  match http.header:User-Agent /sqlmap/i
  match http.header:User-Agent /nikto/i
  match http.header:User-Agent /acunetix/i
  match http.header:User-Agent /masscan/i
  match http.header:User-Agent /zgrab/i
  match http.header:User-Agent /nmap/i
end
end

rule waf_php_probe BLOCK priority 960
when any
  match http.path /\.php($|[/?])/i
  match http.target /\.php($|[/?])/i
  match http.raw_target /\.php($|[/?])/i
end
end

rule waf_common_probe_paths BLOCK priority 955
when any
  match http.path /wp-admin/i
  match http.path /wp-login/i
  match http.path /phpmyadmin/i
  match http.path /xmlrpc\.php/i
  match http.path /boaform/i
  match http.path /autodiscover/i
  match http.path /\.env/i
end
end

rule waf_sqli_union_select BLOCK priority 940
when any
  match http.query /union\s+select/i
  match http.target /union\s+select/i
  match http.raw_target /union(?:\s|\+|%20|%09|%0a|%0d|%0b|%0c)+select/i
  match http.decoded_query /union\s+select/i
  match http.decoded_target /union\s+select/i
end
end

rule waf_sqli_select_from BLOCK priority 939
when any
  match http.query /select(?:.|\n){0,120}from/i
  match http.target /select(?:.|\n){0,120}from/i
  match http.decoded_query /select(?:.|\n){0,120}from/i
  match http.decoded_target /select(?:.|\n){0,120}from/i
end
end

rule waf_sqli_boolean BLOCK priority 938
when any
  match http.query /(?:or|and)\s+['"]?1['"]?\s*=\s*['"]?1/i
  match http.target /(?:or|and)\s+['"]?1['"]?\s*=\s*['"]?1/i
  match http.decoded_query /(?:or|and)\s+['"]?1['"]?\s*=\s*['"]?1/i
  match http.decoded_target /(?:or|and)\s+['"]?1['"]?\s*=\s*['"]?1/i
end
end

rule waf_sqli_functions BLOCK priority 937
when any
  match http.query /sleep\s*\(/i
  match http.query /benchmark\s*\(/i
  match http.query /load_file\s*\(/i
  match http.query /concat\s*\(/i
  match http.target /sleep\s*\(/i
  match http.target /benchmark\s*\(/i
  match http.target /load_file\s*\(/i
  match http.target /concat\s*\(/i
  match http.decoded_target /sleep\s*\(/i
  match http.decoded_target /benchmark\s*\(/i
  match http.decoded_target /load_file\s*\(/i
  match http.decoded_target /concat\s*\(/i
end
end

rule waf_sqli_metadata_outfile BLOCK priority 936
when any
  match http.query /information_schema/i
  match http.query /into\s+outfile/i
  match http.target /information_schema/i
  match http.target /into\s+outfile/i
  match http.decoded_query /information_schema/i
  match http.decoded_query /into\s+outfile/i
  match http.decoded_target /information_schema/i
  match http.decoded_target /into\s+outfile/i
end
end

rule waf_sqli_comment_tail BLOCK priority 935
when any
  match http.query /--/
  match http.query /\/\*/
  match http.target /--/
  match http.target /\/\*/
  match http.decoded_query /--/
  match http.decoded_query /\/\*/
  match http.decoded_target /--/
  match http.decoded_target /\/\*/
end
end

rule waf_xss_basic BLOCK priority 930
when any
  match http.query /<script/i
  match http.query /javascript:/i
  match http.query /onerror\s*=/i
  match http.target /<script/i
  match http.target /javascript:/i
  match http.target /onerror\s*=/i
  match http.decoded_target /<script/i
  match http.decoded_target /javascript:/i
  match http.decoded_target /onerror\s*=/i
  match http.body /<script/i
  match http.body /javascript:/i
  match http.body /onerror\s*=/i
end
end

rule waf_path_traversal BLOCK priority 920
when any
  match http.path /\.\.\//
  match http.target /\.\.\//
  match http.raw_target /(?:\.\.|%2e%2e)(?:\/|%2f)/i
  match http.decoded_path /\.\.\//
  match http.decoded_target /\.\.\//
  match http.target /etc\/passwd/i
  match http.decoded_target /etc\/passwd/i
end
end

rule waf_cmd_injection BLOCK priority 910
when any
  match http.query /(?:;|\||&&|`|\$\()\s*(?:cat|sh|bash|curl|wget|nc|python|perl)\b/i
  match http.target /(?:;|\||&&|`|\$\()\s*(?:cat|sh|bash|curl|wget|nc|python|perl)\b/i
  match http.decoded_query /(?:;|\||&&|`|\$\()\s*(?:cat|sh|bash|curl|wget|nc|python|perl)\b/i
  match http.decoded_target /(?:;|\||&&|`|\$\()\s*(?:cat|sh|bash|curl|wget|nc|python|perl)\b/i
end
end

rule waf_bad_api_key_header BLOCK priority 900
when all
  exists http.header:X-API-Key
  match http.header:X-API-Key /BadSecret/i
end
end

# -------------------------
# Sensitive body/header checks
# -------------------------

rule waf_bad_token_exact BLOCK priority 790
when any
  match http.body /badtoken123/i
  match http.body /token\s*=\s*badtoken123/i
end
end

rule waf_sensitive_plaintext_body BLOCK priority 780
when all
  match http.content_type /text\/plain/i
  any
    match http.body /password\s*=\s*\S+/i
    match http.body /token\s*=\s*\S+/i
    match http.body /api_key\s*=\s*\S+/i
    match http.body /secret\s*=\s*\S+/i
  end
end
end

rule waf_sensitive_form_body LOG priority 770 chain continue
when all
  match http.content_type /application\/x-www-form-urlencoded/i
  any
    match http.body /password=/i
    match http.body /token=/i
    match http.body /api_key=/i
    match http.body /secret=/i
  end
end
end

# -------------------------
# Admin/internal guards
# -------------------------

rule waf_admin_allow_trusted ALLOW priority 690
when all
  any
    match http.path /^\/admin(\/|$)/
    match http.path /^\/internal(\/|$)/
  end
  any
    match net.true_ip /^45\.150\.145\.110$/
    match net.true_ip /^159\.69\.31\.16$/
  end
end
end

rule waf_admin_internal_guard BLOCK priority 680
when any
  match http.path /^\/admin(\/|$)/
  match http.path /^\/internal(\/|$)/
end
end

# -------------------------
# Observability
# -------------------------

rule waf_geo_watch LOG priority 550 chain continue
when any
  match http.geo_country /^CN$/i
  match http.geo_country /^RU$/i
  match http.geo_country /^KP$/i
end
end

# -------------------------
# Business allow rules LAST
# -------------------------

rule waf_home_allow ALLOW priority 490
when all
  match http.method /^(GET|HEAD)$/i
  match http.path /^\/$/
end
end

rule waf_static_allow ALLOW priority 480
when all
  match http.method /^(GET|HEAD)$/i
  any
    match http.path /\.(css|js|png|jpg|jpeg|gif|svg|ico|webp|woff|woff2|ttf|eot|map)$/i
    match http.path /^\/(assets|static|images|img|fonts)(\/|$)/
  end
end
end

rule waf_api_allow_basic ALLOW priority 470
when all
  match http.path /^\/api(\/|$)/
  match http.method /^(GET|POST|HEAD|OPTIONS)$/i
end
end

rule waf_support_allow ALLOW priority 460
when all
  match http.path /^\/support(\/|$)/
end
end
