Install any skill in seconds. Free to start, no credit card required.
Get Started Free →This skill covers deploying and tuning Web Application Firewall rules on AWS WAF, Azure WAF, and Cloudflare to protect cloud-hosted applications against OWASP Top 10 attacks. It details configuring managed rule sets, creating custom rules for business logic protection, implementing rate limiting, deploying bot management, and reducing false positives through rule tuning and logging analysis.
.claude/skills/implementing-cloud-waf-rules/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-21 | ✗→✓ | ▲ Improved | — | — |
| case-09 | ✗→✓ | ▲ Improved | — | — |
| case-05 | ✗→✓ | ▲ Improved | — | — |
| case-12 | ✗→✓ | ▲ Improved | — | — |
| case-01 | ✗→✓ | ▲ Improved | — | — |
Do not use for network-level DDoS protection (use AWS Shield or Azure DDoS Protection), for API authentication design (see managing-cloud-identity-with-okta), or for application code-level security fixes (WAF is a compensating control, not a replacement for secure code).
Enable cloud provider managed rule sets that cover OWASP Top 10 vulnerabilities. Start in Count (detection) mode before switching to Block (prevention) mode.
bash# AWS WAF: Create Web ACL with AWS Managed Rules aws wafv2 create-web-acl \ --name production-waf \ --scope REGIONAL \ --default-action '{"Allow": {}}' \ --visibility-config '{ "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "production-waf" }' \ --rules '[ { "Name": "AWSManagedRulesCommonRuleSet", "Priority": 1, "Statement": { "ManagedRuleGroupStatement": { "VendorName": "AWS", "Name": "AWSManagedRulesCommonRuleSet" } }, "OverrideAction": {"Count": {}}, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "CommonRuleSet" } }, { "Name": "AWSManagedRulesSQLiRuleSet", "Priority": 2, "Statement": { "ManagedRuleGroupStatement": { "VendorName": "AWS", "Name": "AWSManagedRulesSQLiRuleSet" } }, "OverrideAction": {"Count": {}}, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "SQLiRuleSet" } }, { "Name": "AWSManagedRulesKnownBadInputsRuleSet", "Priority": 3, "Statement": { "ManagedRuleGroupStatement": { "VendorName": "AWS", "Name": "AWSManagedRulesKnownBadInputsRuleSet" } }, "OverrideAction": {"Count": {}}, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "KnownBadInputs" } } ]'
Deploy rate-based rules to protect login endpoints against brute force and credential stuffing attacks.
bash# Rate limiting rule for login endpoint (100 requests per 5 minutes per IP) aws wafv2 update-web-acl \ --name production-waf \ --scope REGIONAL \ --id <web-acl-id> \ --lock-token <lock-token> \ --default-action '{"Allow": {}}' \ --rules '[ { "Name": "RateLimitLogin", "Priority": 0, "Statement": { "RateBasedStatement": { "Limit": 100, "AggregateKeyType": "IP", "ScopeDownStatement": { "ByteMatchStatement": { "FieldToMatch": {"UriPath": {}}, "PositionalConstraint": "STARTS_WITH", "SearchString": "/api/auth/login", "TextTransformations": [{"Priority": 0, "Type": "LOWERCASE"}] } } } }, "Action": {"Block": {"CustomResponse": {"ResponseCode": 429}}}, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "RateLimitLogin" } } ]'
Block traffic from countries where the application has no legitimate users and leverage IP reputation lists to block known malicious sources.
bash# AWS WAF: Geo-blocking rule # Block countries not in the allowed list aws wafv2 create-ip-set \ --name blocked-ips \ --scope REGIONAL \ --ip-address-version IPV4 \ --addresses "198.51.100.0/24" "203.0.113.0/24" # Add Amazon IP Reputation rule # AWSManagedRulesAmazonIpReputationList blocks IPs flagged by AWS threat intelligence
Analyze WAF logs in Count mode to identify legitimate requests being flagged. Create rule exceptions for specific URI paths or request patterns.
bash# Enable WAF logging to S3 aws wafv2 put-logging-configuration \ --logging-configuration '{ "ResourceArn": "arn:aws:wafv2:us-east-1:123456789012:regional/webacl/production-waf/id", "LogDestinationConfigs": ["arn:aws:s3:::waf-logs-bucket"], "RedactedFields": [{"SingleHeader": {"Name": "authorization"}}] }' # Query WAF logs with Athena to find false positives # Find rules triggered most frequently for legitimate traffic cat << 'EOF' > waf-analysis.sql SELECT terminatingRuleId, httpRequest.uri, httpRequest.httpMethod, COUNT(*) as block_count FROM waf_logs WHERE action = 'BLOCK' AND timestamp > date_add('day', -7, now()) GROUP BY terminatingRuleId, httpRequest.uri, httpRequest.httpMethod ORDER BY block_count DESC LIMIT 20 EOF
bash# Exclude specific rule from managed rule set that causes false positives # Example: Exclude SizeRestrictions_BODY for file upload endpoint aws wafv2 update-web-acl \ --name production-waf \ --scope REGIONAL \ --id <web-acl-id> \ --lock-token <lock-token> \ --rules '[{ "Name": "AWSManagedRulesCommonRuleSet", "Priority": 1, "Statement": { "ManagedRuleGroupStatement": { "VendorName": "AWS", "Name": "AWSManagedRulesCommonRuleSet", "ExcludedRules": [{"Name": "SizeRestrictions_BODY"}] } }, "OverrideAction": {"None": {}}, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": true, "MetricName": "CommonRuleSet" } }]'
After 7-14 days of Count mode with acceptable false positive rates, switch managed rules to Block mode for active protection.
bash# Change OverrideAction from Count to None (use rule group's default Block action) # Update each managed rule group from {"Count": {}} to {"None": {}} # Monitor CloudWatch metrics for sudden changes in blocked request volume
| Term | Definition | |------|------------| | Web ACL | Web Access Control List defining the set of rules evaluated against every HTTP request to a protected resource | | Managed Rule Group | Pre-configured rule set maintained by the cloud provider or third-party vendor covering common attack patterns | | Rate-Based Rule | WAF rule that tracks request rates per IP address and blocks IPs exceeding the threshold within a time window | | Count Mode | WAF action that logs matching requests without blocking them, used for rule validation before enforcement | | Rule Priority | Numerical ordering determining which rules are evaluated first; lower numbers have higher priority | | Custom Response | WAF capability to return specific HTTP status codes and headers when blocking requests | | Scope-Down Statement | Condition that narrows a rate-based rule to specific URI paths, methods, or headers | | False Positive | Legitimate request incorrectly blocked by a WAF rule, requiring rule tuning or exclusion |
Context: An e-commerce application experiences 50,000 login attempts per hour from a botnet using stolen credential lists. The attacker rotates source IPs every few minutes to evade simple IP-based blocking.
Approach:
Pitfalls: Setting rate limits too aggressively blocks legitimate users behind shared NAT IPs. Blocking by User-Agent alone is easily bypassed by rotating agent strings.
textCloud WAF Configuration Report ================================ Web ACL: production-waf Scope: Regional (us-east-1) Protected Resources: ALB (arn:aws:elasticloadbalancing:...) Report Date: 2025-02-23 RULE CONFIGURATION: [P0] RateLimitLogin - BLOCK (100 req/5min/IP) [P1] AWSManagedRulesCommon - BLOCK (1 exclusion: SizeRestrictions_BODY) [P2] AWSManagedRulesSQLi - BLOCK [P3] AWSManagedRulesKnownBad - BLOCK [P4] AWSManagedRulesBotControl - COUNT (evaluation phase) [P5] GeoBlockRule - BLOCK (12 countries blocked) TRAFFIC ANALYSIS (Last 7 Days): Total Requests: 2,847,293 Allowed: 2,791,456 (98.0%) Blocked: 51,234 (1.8%) Counted: 4,603 (0.2%) TOP BLOCKED RULES: RateLimitLogin: 23,456 blocks (45.8%) SQLi Detection: 8,234 blocks (16.1%) CommonRuleSet (XSS): 7,891 blocks (15.4%) GeoBlockRule: 6,543 blocks (12.8%) KnownBadInputs: 5,110 blocks (10.0%) FALSE POSITIVE ANALYSIS: Reported False Positives: 3 Confirmed False Positives: 1 (SizeRestrictions_BODY for /api/upload) Action Taken: Rule exclusion applied
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-21 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +55 percentage points is the difference between those two pass rates over the 22 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.