Application Security Lab Guides
Combined interactive edition for the four Application Security classes: Cloudflare Setup (AppSec 1), Build and Tune Effective Security Rules (AppSec 2), Bot and Abuse Mitigation (AppSec 3), and Stop Attacks in Real Time (AppSec 4).
These labs run against your assigned Cloudflare-managed lab zone on cftraining.app. Every task is performed in the Cloudflare dashboard or from a terminal against your assigned domain. Fill in your lab slug in the form below before you start, so every command and address in this guide is ready to copy and run.
Typographical Conventions
This guide uses the following conventions to distinguish between user input, system output, and explanatory notes.
| Convention | Meaning | Example |
|---|---|---|
| Bold | Names of selectable items in the interface | Click Save to apply the change. |
Monospace | Text that you enter and code examples | Enter the command: whoami |
| Result text | Step results, explanations, expected output | Operation completed successfully. |
| Italics | Contextual notes explaining "why" a task is necessary | This keeps the service from restarting mid-test. |
<in angle brackets> | A per-student variable, filled in by the reader. | Run dig A <lab-slug>.cftraining.app and press Enter. |
How to Use This Guide
This combined guide contains all four Application Security classes: Part 1 (Cloudflare Setup), Part 2 (Build and Tune Effective Security Rules), Part 3 (Bot and Abuse Mitigation), and Part 4 (Stop Attacks in Real Time). Before each class, verify the assigned environment against that class's starting-state checklist. Work the activities in order because later activities use evidence, settings, or rules created earlier in the same class.
This is the most important box in the guide. Enter the slug for your assigned lab domain. Your full domain is <lab-slug>.cftraining.app, so if your domain is happy-balancer.cftraining.app you enter happy-balancer. Every matching placeholder across the guide, including inside the copy blocks, is substituted with your value, so when you click Copy you get a real, ready-to-run command instead of a <placeholder>. This value saves to your browser only; nothing is sent anywhere.
Why These Labs
AppSec 1 - Cloudflare Setup: From Start to Best Practices
Starting-State Check
Prerequisites
- Your assigned lab slug, which forms
<lab-slug>.cftraining.app. - Access to the Cloudflare dashboard and the account containing your assigned zone.
- A terminal with
digandcurl, or the documented browser fallback for the DNS comparison.
| Control | Required starting state |
|---|---|
| Apex CNAME record | Points to the assigned pod origin and is working and Proxied |
www CNAME record | Points to the assigned pod origin and is DNS Only, exposing the origin addresses |
| SSL/TLS encryption mode | Full |
| Cloudflare Managed Ruleset | Off |
| OWASP Core | Off |
| Test route | /.git/config is available for the managed-rules verification request |
Lab 1: DNS Investigation & Configuration
In this lab, you will diagnose and fix a DNS configuration that exposes an origin server and bypasses Cloudflare's security and performance services.
1.1 Investigate with dig
Open a terminal and run both commands to compare the IPv4 response for www with the response for the root domain. Both names are configured as CNAME records to the pod load balancer, but dig A asks DNS for the resulting IPv4 addresses:
dig A www.<lab-slug>.cftraining.app
dig A <lab-slug>.cftraining.app
The www lookup may show a CNAME first and then return more than one A address. For this comparison, record one returned A address and the query time for each name. You can record every returned A address if you want, but one address is enough.
Record your DNS baseline. Enter at least one A address from each lookup, not the CNAME hostname. If you enter more than one address, separate the addresses with commas.
www CNAME is intentionally configured as DNS Only, so it resolves through the load balancer to origin addresses instead of Cloudflare addresses. That is why it is slow and shows a privacy warning: traffic is going straight to the origin and bypassing Cloudflare.1.2 Fix the Exposed DNS Record
Open the Cloudflare dashboard and select your assigned account.
Go to Domains > Overview, then select your assigned lab domain.
In the domain's left sidebar, select DNS > Records.
Find the www record.
Change Proxy status from DNS Only to Proxied.
Return to the terminal and run the two lookups again. Compare www with your saved baseline of <WWW_INITIAL_IPS> at <WWW_INITIAL_QUERY_TIME>, and compare the root domain with <APEX_INITIAL_IPS> at <APEX_INITIAL_QUERY_TIME>. DNS resolvers across the Internet need time to receive the change, and cached responses can continue returning the previous address until they expire. If www still returns the origin address, wait a few minutes and run the lookup again. Continue after www returns Cloudflare addresses.
dig A www.<lab-slug>.cftraining.app returns Cloudflare anycast addresses (the same kind the root domain returns), not the origin IP, and the privacy warning is gone.Lab 2: SSL/TLS Configuration
In this lab, you will observe how Full (Strict) protects the connection to the origin, then restore the lab's required state.
2.1 Induce the SSL Error
Open the Cloudflare dashboard.
Select your assigned account.
Go to Domains > Overview, then select your assigned lab domain.
In the domain's left sidebar, select SSL/TLS > Overview.
On the SSL/TLS overview, select Configure in the top-right.
On Encryption mode and origin connection settings, select Full (Strict).
Select Save at the bottom of the Encryption mode card.
Leave the dashboard open. In a new browser tab, open https://<lab-slug>.cftraining.app/ to test the site's HTTPS connection with the stricter origin mode.
Record the Cloudflare error code displayed on that page. The published lab currently expects 525: SSL handshake failed.
If the test does not produce 525 or 526, ask your instructor to verify the origin TLS fixture before continuing to Lab 3.
2.2 Restore the Lab State
Return to the dashboard tab. If needed, select SSL/TLS in the breadcrumb, then select Configure in the top-right.
On Encryption mode and origin connection settings, select Full.
Select Save at the bottom of the Encryption mode card.
Return to https://<lab-slug>.cftraining.app/, refresh the page, and confirm that the site loads.
Lab 3: Verifying Traffic in Analytics
3.1 Find the Error in Analytics
From the selected domain's left sidebar, select Analytics > HTTP Traffic.
Add an Edge status code filter for <SSL_ERROR_CODE>, the code you recorded in Lab 2. The published scenario expects 525; use 526 if that is what your lab origin produced.
Confirm that you can find the error generated in Lab 2.
Adjust the time range if the request is not immediately visible.
<SSL_ERROR_CODE>.Lab 4: Enabling the Web Application Firewall (WAF)
4.1 Enable and Verify the Cloudflare Managed Ruleset
From the selected domain's left sidebar, select Security > Settings.
Filter the settings for Web application exploits.
In the Cloudflare managed ruleset row, select the toggle in the Status column. This opens Deploy managed ruleset.
Under Execution configuration, confirm that the execution scope is All incoming requests to your lab domain.
Under Ruleset configuration, leave Ruleset action set to Default and Ruleset status set to Default.
At the bottom of the page, select Deploy. Do not select Save as Draft.
Cloudflare returns you to Security > Security rules. In the Managed rules card, confirm that Cloudflare Managed Ruleset shows Action = Execute and Status = Active.
From a terminal, send a request that the Cloudflare Managed Ruleset is designed to block:
curl -i "https://<lab-slug>.cftraining.app/.git/config"
Confirm that the request returns 403 Forbidden, then record the Cloudflare Ray ID shown near the bottom of the response. This request creates the event you will inspect; you do not need to wait for background scanner traffic.
In the domain's left sidebar, select Security > Analytics, select the Events tab, and set the time range to Last 30 minutes.
Select Add filter, add Service equals Managed rules, add Action equals Block, then apply the filters.
Scroll to Sampled logs. If needed, select Edit columns and add ASN and User agent. Find the fresh GET /.git/config event by its timestamp or Ray ID, then expand it with the caret at the left of the row. Do not use existing Custom rules or Rate limiting rules events as proof that the managed ruleset worked.
Under Matched service, confirm Service = Managed rules, Action taken = Block, Ruleset = Cloudflare Managed Ruleset, and Rule = Version Control - Information Disclosure. Under Request details, confirm Method = GET and Path = /.git/config, then inspect the IP address, country, ASN, user agent, WAF attack scores, and bot score that describe the request.
GET /.git/config event shows Cloudflare Managed Ruleset, Version Control - Information Disclosure, and Block. If you cannot find a fresh event, run the command from step 4.1.8 again, wait briefly, and refresh Sampled logs.If the repeated request does not return 403 or produce the matching fresh event, ask your instructor to verify the managed-rules fixture. Do not use an older or unrelated event as evidence.
4.2 Deploy OWASP Safely
In the domain's left sidebar, return to Security > Settings. Under Filter by groups, select Web application exploits.
In the OWASP Core row, select the toggle in the Status column. This opens Deploy managed ruleset for the Cloudflare OWASP Core Ruleset.
Under Execution configuration, confirm that the execution scope is All incoming requests to your lab domain.
Under Cloudflare OWASP Core Ruleset configuration, leave OWASP Anomaly Score Threshold set to Medium - 40 and higher and leave OWASP Paranoia Level set to PL1.
Change OWASP Action from Block to Log.
At the bottom of the page, select Deploy. Do not select Save as Draft.
4.3 Test the Logging Rule
Open a Linux terminal and run this request against your assigned domain:
curl --http1.0 -i -X DELETE -H "Accept;" -H "Content-Type: text/invalid" -H "Connection: keep-alive, close" "https://<lab-slug>.cftraining.app/owasp-test?file=http%3A%2F%2F127.0.0.1%2Fshell.php%3F&PHPSESSID=test&x=%0D%0ASet-Cookie%3Atest"
This request deliberately combines an unsupported method, conflicting and unusual headers, remote-file-inclusion input, header-injection input, and a session identifier. Nine PL1 OWASP rules contribute to a cumulative score of 40, which reaches the configured Medium - 40 and higher threshold. The Cloudflare Managed Ruleset above OWASP does not terminate this request first.
Confirm that curl shows 405 Method Not Allowed. That response comes from the lab origin because Log allows the request to continue. It does not mean the OWASP test failed.
Return to the dashboard. From the selected domain's left sidebar, select Security > Analytics, then select the Events tab. Select Clear all to remove the filters from section 4.1. Select Add filter, add Service equals Managed rules, add Action equals Log, then apply the filters.
Set the time range to Last 30 minutes.
In Sampled logs, expand the fresh event for path /owasp-test. Under Matched service, confirm Ruleset = Cloudflare OWASP Core Ruleset, Action taken = Log, the rule name includes Inbound Anomaly Score Exceeded, and OWASP score = 40.
Select Additional logs (9) to inspect the individual PL1 rules that contributed to the score. Under Request details, confirm Method = DELETE and Path = /owasp-test.
DELETE /owasp-test event shows Cloudflare OWASP Core Ruleset, Inbound Anomaly Score Exceeded, OWASP score = 40, and Action taken = Log. Leave the OWASP action set to Log.If the origin does not return 405 or the fresh event does not show all four required values, ask your instructor to verify the test fixture. Do not change OWASP to Block.
Final Retained State
| Control | Required retained state |
|---|---|
| Apex CNAME record | Points to the assigned pod origin and is Proxied |
www CNAME record | Points to the assigned pod origin and is Proxied |
| SSL/TLS encryption mode | Full for this lab environment |
| Cloudflare Managed Ruleset | Active, action Execute |
| OWASP Core | Active, PL1, threshold Medium - 40 and higher, action Log |
| Required evidence | Fresh managed-rules Block event and fresh OWASP score-40 Log event |
Appendix: Lab Command Reference
The dig commands used in this class, for quick reference:
dig A www.<lab-slug>.cftraining.app
dig A <lab-slug>.cftraining.app
AppSec 2 - Build and Tune Effective Security Rules
You are a security engineer for Single Origin. In this lab, you will investigate scraping, build and test a precise mitigation, tune false positives, repair inherited rule hygiene, and protect the product API without disrupting legitimate users.
Use the Assess, Build, Test, Tune cycle throughout the lab.
| Activity | Mode | Duration |
|---|---|---|
| 1. Investigate scraping and correct a Skip-order conflict | Solo | 18 minutes |
| 2. Tune two false positives | Solo | 16 minutes |
| 3. Repair inherited rule hygiene | Synchronous | 6 minutes |
| 4. Add product-API rate limiting | Solo | 10 minutes |
Starting-State Check
The class starts with exactly these five inherited Custom rules in this order:
| Position | Rule | Expression | Action |
|---|---|---|---|
| 1 | BYPASS - Site Monitor IP | ip.src in $site_monitor_ips | Skip all remaining Custom rules; Log matching requests enabled |
| 2 | BLOCK - DE or Android 5 | ip.src.country eq "DE" or http.user_agent contains "Android 5" | Block |
| 3 | BLOCK - Site Monitor curl | http.user_agent contains "curl" | Block |
| 4 | BYPASS - Main Customer Geo | ip.src.country eq "US" | Skip all remaining Custom rules; Log matching requests enabled |
| 5 | BLOCK - bot UA | http.user_agent contains "bot" | Block |
| Signal | Lifecycle and rate | Required identity and result |
|---|---|---|
SEC2-HUMAN | Continuous; four GET /shop and two GET /api/v1/products requests per minute | Current browser user agent; US residential or equivalent browser source; 200 |
SEC2-SCRAPER | Continuous; forty GET /api/v1/products requests per minute | python-requests/2.31.0; US source; static source IP and ASN |
SEC2-VPN | Continuous; four GET /checkout requests per minute | Current browser user agent; same ASN as the scraper from a different IP; 200 after tuning |
SEC2-MONITOR | Continuous; two GET /api/v1/products requests per minute | python-requests/2.31.0; same ASN as the scraper; static allowlisted IP; 200 through the first Skip |
SEC2-API-BURST | Recurring preconfigured schedule; fifteen GET /api/v1/products requests inside 60 seconds per run | Current browser user agent; non-US source and ASN; crosses the learner-created threshold |
Activity 1 (SEC2-1): Investigate scraping and correct a Skip-order conflict
/api/v1/products, and the five inherited Custom rules are in their baseline order.1.1 Investigate Scraping
Open the Cloudflare dashboard and select your assigned account.
Go to Domains > Overview, then select <lab-slug>.cftraining.app.
In the domain's left sidebar, select Security > Analytics, select the Traffic tab, and set the time range to Last 30 minutes.
Select Add filter, create a filter where Path equals /api/v1/products, apply it, and find a fresh scraper request by its timestamp, source ASN, rate, and python-requests/2.31.0 user agent.
In Sampled logs, select the timestamp for that scraper request. Under Request details, record the value next to ASN as <SCRAPER_ASN>.
1.2 Create and Place the Log Rule
Select Security > Security rules.
Select Create rule, then select Custom rules. Enter LOG - Scraping ASN as the rule name, select Edit expression, and paste the copied expression:
ip.src.asnum eq <SCRAPER_ASN>
Under Then take action, set Choose action to Log. Under Execution order, leave Select order set to Last. At the bottom of the page, select Deploy, then select Deploy in the Deploy rule to production? confirmation dialog.
On the Custom rules list, select the linked event count in the Events column for BYPASS - Main Customer Geo.
In the filtered Events view, set the time range to Last 30 minutes.
In Sampled logs, start with the first row and select its timestamp. In the expanded Request details, check for Path /api/v1/products, User agent python-requests/2.31.0, and ASN AS<SCRAPER_ASN>. If that row does not have all three values, select the next timestamp and check again.
In the matching event's Matched service section, confirm that Action taken is Skip. The Rule ID filter came from BYPASS - Main Customer Geo, so this shows that the higher Skip handles the scraper request before the new last-place Log rule can evaluate it.
Select Security > Security rules. In the Custom rules table, select LOG - Scraping ASN to edit it.
Under Execution order, set Select order to Custom. Set Select which rule this will fire after to BLOCK - Site Monitor curl; this places the Log rule immediately above BYPASS - Main Customer Geo. Select Save.
Verify
Select Security > Analytics, then select the Events tab and set Last 30 minutes.
Select Add filter for each filter, create and apply Action equals Log, then Service equals Custom rules, then Path equals /api/v1/products.
In Sampled logs, select the timestamp of a fresh event. Under Matched service, confirm that Action taken is Log. Confirm that the event timestamp is after you saved the rule's new position.
Keep the rule in Log and check the numeric ASN and placement with your instructor before Activity 2.
Activity 2 (SEC2-2): Tune two false positives
LOG - Scraping ASN is above BYPASS - Main Customer Geo. The scraper and legitimate VPN traffic share <SCRAPER_ASN>, while the scraper and monitor share python-requests/2.31.0.2.1 Test the Broad Block
Select Security > Security rules.
Open Show all rule types and select Custom rules.
In the Custom rules table, select LOG - Scraping ASN to edit it.
Change its action to Block, then select Save.
In the domain's left sidebar, select Security > Analytics, select the Events tab, set Last 30 minutes, and apply Action equals Block, Service equals Custom rules, and Path equals /checkout.
In Sampled logs, select the timestamp of a fresh blocked legitimate VPN request.
Under Request details, confirm that ASN is AS<SCRAPER_ASN>, then enter User agent as <VPN_USER_AGENT> in the field below.
2.2 Refine and Verify the Rule
Select Security > Security rules.
Open Show all rule types and select Custom rules.
In the Custom rules table, select LOG - Scraping ASN to edit it.
In the expression editor, replace the current expression by pasting the copied expression:
ip.src.asnum eq <SCRAPER_ASN> and http.user_agent eq "python-requests/2.31.0"
Rename the scraper rule BLOCK - Scraping ASN+UA, then select Save.
Scroll to the bottom of the page, and on the left select Manage account > Configurations, open the Lists tab, select site_monitor_ips, and enter its listed monitor IP as <SITE_MONITOR_IP> in the field below.
Return to Overview, then select Security > Security rules.
Open Show all rule types and select Custom rules.
In the Custom rules table, confirm that BYPASS - Site Monitor IP remains the first rule.
Select Security > Analytics, then select the Events tab.
Set Last 30 minutes, then apply Source IP equals <SITE_MONITOR_IP>.
Under Top events by source > Custom rules, confirm that BYPASS - Site Monitor IP appears.
In Sampled logs, select the timestamp of a fresh event from the monitor IP.
Under Matched service, confirm that Action taken is Skip.
Under Request details, confirm that Source IP matches the monitor IP, ASN is AS<SCRAPER_ASN>, and User agent is exactly python-requests/2.31.0.
At the top of the domain sidebar, select Back to Domains, then in the account sidebar expand Investigate under the Observe heading, select Trace, and select Begin Trace.
In URL, enter https://<lab-slug>.cftraining.app/checkout.
Confirm that HTTP Method is set to GET.
Under User Agent and Request Headers, select Add setting.
Enter User-Agent for Header key, then paste the copied value into Value:
<VPN_USER_AGENT>
Select Send Trace to simulate how the active Cloudflare configuration handles the tuned VPN checkout request.
In Trace Results, confirm that Match type is All configurations so rules that did not match remain visible.
Expand WAF Custom Rules.
Find BLOCK - Scraping ASN+UA and confirm that it shows No match.
Select View rule detail, confirm that "matched" is false, and confirm that the expression checks for http.user_agent eq "python-requests/2.31.0".
Close Rule detail, then under Request JSON confirm that User-Agent matches <VPN_USER_AGENT>.
Under TRACE END, confirm that HTTP Status Code is 200 OK.
Verify
Select Overview, then select Security > Analytics.
Select the Events tab and set the time range to Last 30 minutes.
Apply Action equals Block, Service equals Custom rules, and Path equals /api/v1/products.
Under Top events by source > Custom rules, confirm that BLOCK - Scraping ASN+UA appears, then in Sampled logs select a fresh event and confirm that Action taken is Block, ASN is AS<SCRAPER_ASN>, and User agent is python-requests/2.31.0.
Select the Traffic tab and set the time range to Last 30 minutes.
Apply Source IP equals <SITE_MONITOR_IP> and Edge status code equals 200, then select a fresh request and confirm that Path is /api/v1/products, Source IP is <SITE_MONITOR_IP>, and User agent is python-requests/2.31.0.
Remove all filters, apply Path equals /shop and Edge status code equals 200 OK by selecting 200 OK in the status-code dropdown, then in Sampled logs select the newest /shop timestamp and under Edge response confirm Edge status code: 200 - OK and Origin status code: 200 - OK and under Request details confirm Method: GET, Path: /shop, and a browser User agent.
Remove all filters, apply Path equals /checkout, Source ASN equals <SCRAPER_ASN>, Source user agent equals <VPN_USER_AGENT>, and Edge status code equals 200, then select a fresh request and confirm that its details match all four filters.
Select the Events tab, remove all filters, apply Source IP equals <SITE_MONITOR_IP>, confirm under Top events by source > Custom rules that BYPASS - Site Monitor IP appears, then select a fresh event and confirm that Action taken is Skip.
Confirm that the blocked VPN Event showed ASN AS<SCRAPER_ASN> and User agent <VPN_USER_AGENT>, the fresh /checkout Traffic request with ASN AS<SCRAPER_ASN> and User agent <VPN_USER_AGENT> returned 200, Trace showed BLOCK - Scraping ASN+UA as No match for <VPN_USER_AGENT>, the blocked scraper Event showed ASN AS<SCRAPER_ASN> and User agent python-requests/2.31.0, and the monitor Event from <SITE_MONITOR_IP> showed Action taken Skip; this confirms that the tuned rule blocks the scraper signature while preserving the VPN and monitor.
If scraper traffic is not blocked or VPN, monitor, or human traffic does not return 200, keep the rule available for correction before continuing.
Activity 3 (SEC2-3): Repair inherited rule hygiene
This activity depends on delivery-provided DE Android 5, DE without Android 5, and non-DE Android 5 requests. The guide does not provide or invent a trigger. Confirm that your instructor has identified fresh validation traffic before changing the rule. If it is unavailable, stop and leave the inherited rules unchanged.
3.1 Repair the Inherited Rules
Select Security > Security rules, open Show all rule types, select Custom rules, and in the Custom rules table select BLOCK - DE or Android 5 to edit it.
Select Edit expression, then replace the current expression by pasting the copied expression:
ip.src.country eq "DE" and http.user_agent contains "Android 5"
In Rule name, enter this exact value:
BLOCK - DE Android 5
Select Save, then on the Custom rules list select BLOCK - Site Monitor curl to edit it, under Status select Disabled, select Save, and confirm that the rule shows Disabled on the list.
On the Custom rules list, confirm that the rules appear in this exact order with these statuses:
| Position | Rule | Status |
|---|---|---|
| 1 | BYPASS - Site Monitor IP | Active |
| 2 | BLOCK - DE Android 5 | Active |
| 3 | BLOCK - Site Monitor curl | Disabled |
| 4 | BLOCK - Scraping ASN+UA | Active |
| 5 | BYPASS - Main Customer Geo | Active |
| 6 | BLOCK - bot UA | Active |
Select Security > Analytics.
Select the Traffic tab and set the time range to Last 30 minutes.
Select Clear all if any filters remain from an earlier task.
Select Show more top statistics, then under Source user agents select the four-arrow Expand to see more and search button, enter Android 5.0.2 in Search, hover over the single result, and select the Filter icon at the right.
Under Countries, hover over Germany, then select Filter.
Above, under Number of requests mitigated and served by Cloudflare, confirm that all filtered requests were blocked or challenged by Cloudflare's security tools by confirming that Mitigated by Cloudflare equals Total.
Under Edge status codes, confirm that all filtered requests are 403 Forbidden.
In Sampled logs, select a fresh timestamp, then under Edge response confirm that Mitigation is Block by Custom rules and Edge status code is 403 - Forbidden.
Under Request details, confirm that Country is Germany and User agent contains Android 5.0.2.
Scroll up and select Clear all under the filters, then under Source user agents replace any current Search value with Chrome/133.0.0.0, hover over the single result, and select the Filter icon at the right.
Under Countries, hover over Germany, then select Filter.
Above, under Number of requests mitigated and served by Cloudflare, confirm that all filtered requests were served by the origin by confirming that Served by origin equals Total.
Under Edge status codes, confirm that all filtered requests are 200 OK.
In Sampled logs, select a fresh timestamp, then confirm that Mitigation is Not mitigated, Edge status code is 200 - OK, Country is Germany, and User agent contains Chrome/133.0.0.0.
Select Clear all, then under Source user agents replace any current Search value with Android 5.0.2, hover over the single result, and select the Filter icon at the right.
Under Countries, hover over United States, then select Filter.
Above, under Number of requests mitigated and served by Cloudflare, confirm that all filtered requests were served by the origin by confirming that Served by origin equals Total.
Under Edge status codes, confirm that all filtered requests are 200 OK.
In Sampled logs, select a fresh timestamp, then confirm that Mitigation is Not mitigated, Edge status code is 200 - OK, Country is United States, and User agent contains Android 5.0.2.
Activity 4 (SEC2-4): Add product-API rate limiting
4.1 Rate-Limit the Product API
Select Security > Security rules.
On the Rate limiting rules card, select Create rule, enter RATE-LIMIT - Product API as the rule name, select Edit expression, and paste the copied expression:
http.request.uri.path eq "/api/v1/products"
Under With the same characteristics, leave Field set to IP so Cloudflare counts requests separately for each source IP.
Under When rate exceeds, enter 10 for Requests and select 2 minutes for Period.
Under Then take action, select Non-Interactive Challenge.
Under With the following behavior, leave Non-Interactive Challenge for the selected duration selected and choose 5 minutes for Duration.
Under Status, leave Active selected.
Select Deploy, select Deploy in the Deploy rule to production? confirmation dialog, then wait for the next scheduled SEC2-API-BURST run against https://<lab-slug>.cftraining.app/api/v1/products while the ordinary, VPN, monitor, and scraper traffic continues.
Return to Security > Analytics, select the Events tab, set Last 30 minutes, and apply Service equals Rate limiting rules and Path equals /api/v1/products.
In Sampled logs, select the timestamp of a fresh event from the latest scheduled burst, under Matched service confirm that Service is Rate limiting rules and Action taken is Non-Interactive Challenge, and under Request details confirm that Path is /api/v1/products, which distinguishes this event from existing Custom-rule Block events.
BLOCK - Scraping ASN+UA; and Security Events distinguishes the Custom-rule Block from the rate-limit action. Keep the learner-created rules active for the class recap.Final Retained State
BLOCK - Scraping ASN+UA, the corrected BLOCK - DE Android 5, and RATE-LIMIT - Product API remain active; BYPASS - Site Monitor IP remains first; and BLOCK - Site Monitor curl is disabled. Keep the learner-created rules through recap. The AppSec 2 class reset restores the five inherited rules in their original order, $site_monitor_ips membership, route data, and absence of learner-created rules. It preserves labeled traffic visibility, all four continuous actors, and the recurring SEC2-API-BURST schedule without depending on an actor restart.AppSec 3 - Bot and Abuse Mitigation
You are protecting Single Origin's specialty-coffee services from automated abuse. In this lab, you will establish bot protections, manage AI crawler treatment, protect a browser login, investigate credential stuffing, and create two JA4-based rate limits while checking that the mobile clients keep working.
| Activity | Mode | Duration |
|---|---|---|
| 1. Establish Baseline Bot Protections | Synchronous | 6 minutes |
| 2. Manage AI Crawler Treatment | Synchronous | 8 minutes |
| 3. Apply Maximize Security to the Login Page | Synchronous | 5 minutes |
| 4. Investigate, Mitigate, and Tune Credential Stuffing | Synchronous | 27 minutes |
| 5. Rate-Limit Leaked Credentials for a Saved JA4 | Synchronous | 12 minutes |
| 6. Protect the Orders API | Synchronous | 12 minutes |
Activity 1 (SEC3-1): Establish Baseline Bot Protections
1.1 Inspect the Generator Signals
Open the Cloudflare dashboard and select your assigned account.
Go to Domains > Overview, then select <lab-slug>.cftraining.app.
In the selected domain's left sidebar, select Security > Analytics, select the Traffic tab at the top, and set the time range to Last 30 minutes.
Above the request chart, select Clear all if filters from earlier work are displayed.
Add the following Traffic filters.
| Field | Operator | Value |
|---|---|---|
| Path | equals | /admin |
Scroll down to Sampled logs, then select the caret at the left of the newest sampled log row to expand it.
In the expanded row's Request analyses section, verify the displayed Bot score classification and verify that JA4 fingerprint has a fingerprint value.
In the same row's Request details section, verify that Method is POST, Path is /admin, and Edge status code is 401.
Scroll back to the filter row above the request chart, select the existing Path equals /admin filter, replace its Value with /api/v1/orders, and select Apply.
Scroll down to Top statistics and select Show more top statistics if the Source user agents card is not displayed.
In the Source user agents card, select the four-arrow Expand to see more and search control.
In Search, enter curl/8.10.1 and locate the exact curl/8.10.1 result.
Replace the Search value with SingleOrigin-Mobile/3.1.0 (iOS 18.2; iPhone15,3) and locate that exact result.
Compare the two result counts: curl/8.10.1 should have about ten times as many requests as the mobile user agent because the scraper sends twenty requests per minute and the mobile client sends two.
Replace the Search value with curl/8.10.1, hover over the exact result, and select the Filter icon at the right.
After the curl/8.10.1 filter is applied, verify in Edge status codes that the filtered scraper traffic returns 401.
Scroll down to Sampled logs, then select the caret at the left of the newest sampled log row to expand it.
Under Request analyses, record the orders scraper's JA4 fingerprint in the saved field below and verify that Bot score is Automated.
Under Request details, verify that User agent is exactly curl/8.10.1 and Path is /api/v1/orders.
Scroll back to the filter row and select the existing Source user agent equals curl/8.10.1 filter.
Replace its Value with SingleOrigin-Mobile/3.1.0 (iOS 18.2; iPhone15,3), then select Apply.
After the mobile user-agent filter is applied, verify in Edge status codes that the filtered mobile traffic returns 200.
Scroll down to Sampled logs, then select the caret at the left of the newest sampled log row to expand it.
Under Request analyses, verify that Bot score is Likely automated and JA4 fingerprint is <ORDERS_SCRAPER_JA4>.
Under Request details, verify that User agent is SingleOrigin-Mobile/3.1.0 (iOS 18.2; iPhone15,3), Path is /api/v1/orders, and Edge status code is 200.
1.2 Enable Precursor
In the selected domain's left sidebar, select Security > Settings.
In Filter by groups, select Fraud.
In the Leaked credentials detection row, verify that Status is On.
In Filter by groups, select Precursor.
In the Precursor row, turn on the Status switch if it is off.
Select the Precursor row to open its configuration. Under Precursor Mode, select Minimize Friction, then select Save.
Activity 2 (SEC3-2): Manage AI Crawler Treatment
2.1 Allow and Block AI Crawlers
In the selected domain's left sidebar, expand AI Crawl Control and select Security.
Above the crawler table, select Show inactive crawlers if it is not already selected.
In the crawler table, scroll to the row whose crawler name is exactly PerplexityBot.
In that row's Block Crawler column, turn the switch off if it is on.
Verify that the PerplexityBot Block Crawler switch is off, which means this AI Search crawler is allowed.
In the same crawler table, scroll to the row whose crawler name is exactly GPTBot.
In that row's Block Crawler column, turn the switch on if it is off.
Verify that the GPTBot Block Crawler switch is on, which means this model-training crawler is blocked.
Do not change any other crawler row.
PerplexityBot and on for GPTBot. If either crawler or switch is unavailable, record the observed mismatch, continue to the next exercise, and include it in the end-of-lab results.Activity 3 (SEC3-3): Apply Maximize Security to the Login Page
3.1 Create the Maximize Login Rule
In the selected domain's left sidebar, select Security > Settings.
In Filter by groups, select Precursor.
In the Precursor row, select the Configurable Rules: <number> rules link, where <number> is the displayed count.
On the Precursor Rules page, select Create rule.
In Rule name, enter MAXIMIZE - Login.
Select Edit expression and paste the copied expression:
http.request.uri.path eq "/login"
In Precursor mode, select Maximize Security.
Under Status, leave Active selected.
Select Deploy.
If the dashboard displays Deploy rule to production?, select Deploy in that dialog.
Open a new private or incognito browser window.
In the private session, open https://<lab-slug>.cftraining.app/login.
Return to the dashboard tab and select Security > Analytics in the selected domain's left sidebar.
At the top of Security Analytics, select the Events tab.
Open the time-range menu in the upper-right and select Last 30 minutes.
Above the events chart, select Clear all if filters are displayed.
Add the following Events filters.
| Field | Operator | Value |
|---|---|---|
| Path | equals | /login |
| Action | equals | Precursor Interstitial Page Issued |
Scroll down to Sampled logs.
Select the caret at the left of the newest sampled log row to expand it.
In the expanded row's Matched service section, verify that Action taken is Precursor Interstitial Page Issued.
In the same row's Request details section, verify that Path is /login.
/api/mobile/login and /api/v1/orders remain outside the rule.MAXIMIZE - Login is active for exact /login, and a fresh event shows Precursor Interstitial Page Issued when matching traffic is available. If the event is absent, record the observed mismatch, continue to the next exercise, and include it in the end-of-lab results.Activity 4 (SEC3-4): Investigate, Mitigate, and Tune Credential Stuffing
4.1 Investigate Credential Stuffing
In the selected domain's left sidebar, select Security > Analytics.
At the top of Security Analytics, select the Traffic tab.
Open the time-range menu in the upper-right and select Last 30 minutes.
Above the request chart, select Clear all if filters are displayed.
Add the following Traffic filters.
| Field | Operator | Value |
|---|---|---|
| Path | equals | /admin |
| Edge status code | equals | 401 Unauthorized |
In Sampled logs, compare the Time values and verify that the repeating /admin failures occur about every 10 seconds, or about six times per minute, compared with the legitimate mobile-login signal's twice per minute.
Select the caret at the left of the newest sampled log row to expand it.
Under Request analyses, verify that Bot score is Automated and record the credential stuffer's JA4 fingerprint in the saved field below.
Under Request analyses > Other suspicious activity, verify whether the displayed value is Username & password leaked or None.
Under Request details, verify that Method is POST and Path is /admin, record the source IP in the saved field below, and note the timestamp.
Select the caret at the left of the next-newest sampled log row to expand it.
Compare Request analyses > JA4 fingerprint and Request details > IP with the first row: the JA4 should be <CREDENTIAL_STUFFER_JA4>, while the source IP should differ from <CREDENTIAL_STUFFER_FIRST_IP>.
<CREDENTIAL_STUFFER_JA4> connects the requests even while the attacker rotates source IPs. Traffic reaching another data center gets a separate count, and the other signals show that the pattern is credential stuffing rather than one unusual login.4.2 Mitigate and Test
In the selected domain's left sidebar, select Security > Security rules.
At the top of the Security rules page, select Create rule.
In the menu, select Custom rules.
In Rule name, enter CHALLENGE - Low Bot Score Login.
Select Edit expression and paste the copied expression:
cf.bot_management.score eq 1 and http.request.uri.path in {"/admin" "/api/mobile/login"}
Under Then take action, select Managed Challenge.
Under Execution order, leave Select order set to Last.
Under Status, leave Active selected.
Select Deploy.
If the dashboard displays Deploy rule to production?, select Deploy in that dialog.
In the selected domain's left sidebar, select Security > Analytics.
At the top of Security Analytics, select the Events tab.
Open the time-range menu in the upper-right and select Last 30 minutes.
Above the events chart, select Clear all if filters are displayed.
Add the following Events filters.
| Field | Operator | Value |
|---|---|---|
| Action | equals | Skip |
| Service | equals | Custom rules |
| Path | equals | /admin |
Scroll down to Sampled logs.
Select the caret at the left of the newest sampled log row to expand it.
Under Matched service, verify that Service is Custom rules, Action taken is Skip, and Rule is BYPASS - Main Customer Geo.
Under Request analyses, verify that Bot score matches the configured cf.bot_management.score eq 1 condition and JA4 fingerprint is <CREDENTIAL_STUFFER_JA4>.
Under Request details, verify that Path is /admin and note the source IP.
In the selected domain's left sidebar, select Security > Security rules.
On the Security rules page, select Show all rule types.
Select Custom rules.
In the Custom rules list, locate the row named exactly CHALLENGE - Low Bot Score Login and select the rule name.
In the rule editor's Execution order section, open Select order and select Custom.
Open Select which rule this will fire after and select BYPASS - Site Monitor IP.
Select Save.
In the selected domain's left sidebar, select Security > Analytics.
At the top of Security Analytics, select the Events tab.
Open the time-range menu in the upper-right and select Last 30 minutes.
Above the events chart, select Clear all if filters are displayed.
Add the following Events filters.
| Field | Operator | Value |
|---|---|---|
| Path | equals | /api/mobile/login |
| Service | equals | Custom rules |
| Action | equals | Managed Challenge |
Scroll down to Sampled logs.
Select the caret at the left of the newest sampled log row to expand it.
Under Matched service, verify that Service is Custom rules, Action taken is Managed Challenge, and Rule is CHALLENGE - Low Bot Score Login.
Under Request analyses, verify that Bot score matches the configured cf.bot_management.score eq 1 condition and the credential stuffer's JA4 fingerprint is <CREDENTIAL_STUFFER_JA4>.
Under Request details, verify that Path is /api/mobile/login and User agent is curl/8.10.1.
Treat this row as abusive API traffic, not as the legitimate mobile client.
At the top of Security Analytics, select the Traffic tab.
Open the time-range menu in the upper-right and select Last 30 minutes.
Above the request chart, select Clear all to remove the Events filters.
Add the following Traffic filters.
| Field | Operator | Value |
|---|---|---|
| Path | equals | /api/mobile/login |
| Source user agent | equals | SingleOrigin-Mobile/3.1.0 (iOS 18.2; iPhone15,3) |
| Edge status code | equals | 200 OK |
Scroll down to Sampled logs, then select the caret at the left of the newest sampled log row to expand it.
Under Request analyses, verify that Bot score is Likely automated.
Under Request details, verify the full mobile User agent, Path /api/mobile/login, and Edge status code 200.
4.3 Tune the Rule
In the selected domain's left sidebar, select Security > Security rules.
On the Security rules page, select Show all rule types.
Select Custom rules.
In the Custom rules list, locate the row named exactly CHALLENGE - Low Bot Score Login and select the rule name.
In the open expression editor under When incoming requests match…, replace the current expression with the copied expression:
cf.bot_management.score eq 1 and http.request.uri.path eq "/admin"
In Rule name, replace the current name with CHALLENGE - Admin Credential Stuffing.
Select Save.
In the selected domain's left sidebar, select Security > Analytics.
At the top of Security Analytics, select the Events tab.
Open the time-range menu in the upper-right and select Last 30 minutes.
Above the events chart, select Clear all if filters are displayed.
Add the following Events filters.
| Field | Operator | Value |
|---|---|---|
| Path | equals | /admin |
| Service | equals | Custom rules |
| Action | equals | Managed Challenge |
Scroll down to Sampled logs, then select the caret at the left of the newest sampled log row to expand it.
Under Matched service, verify that Rule is CHALLENGE - Admin Credential Stuffing and Action taken is Managed Challenge.
At the top of Security Analytics, select the Traffic tab.
Open the time-range menu in the upper-right and select Last 30 minutes.
Above the request chart, select Clear all to remove the Events filters.
Add the following Traffic filters.
| Field | Operator | Value |
|---|---|---|
| Path | equals | /api/mobile/login |
| Source user agent | equals | SingleOrigin-Mobile/3.1.0 (iOS 18.2; iPhone15,3) |
| Edge status code | equals | 200 OK |
Scroll down to Sampled logs, then select the caret at the left of the newest sampled log row to expand it.
Under Request analyses, verify that Bot score is Likely automated.
Under Request details, verify that User agent is SingleOrigin-Mobile/3.1.0 (iOS 18.2; iPhone15,3), Path is /api/mobile/login, and Edge status code is 200.
CHALLENGE - Admin Credential Stuffing challenges /admin, the earlier broad-rule event on /api/mobile/login belongs to curl/8.10.1, and Traffic shows the generated mobile login classified as Likely automated and returning 200. If any result is absent, record the observed mismatch, continue to the next exercise, and include it in the end-of-lab results.Activity 5 (SEC3-5): Rate-Limit Leaked Credentials for a Saved JA4
5.1 Create the Leaked-Credential Rate Limit
In the selected domain's left sidebar, select Security > Security rules.
At the top of the Security rules page, select Create rule.
In the menu, select Rate limiting rules.
In Rule name, enter ARL - Leaked Credential Attempts.
Under When incoming requests match…, select Edit expression and paste the copied expression:
(cf.waf.credential_check.username_and_password_leaked)
Under With the same characteristics, open the Field menu.
In the rendered Field options, select JA4 Fingerprint and verify that it replaces IP as the selected counting characteristic.
Leave Use custom counting expression unselected.
Under When rate exceeds…, leave Request based selected, enter 3 in Requests, and select 1 minute for Period.
Under Then take action…, select Block.
Leave With response type at Default Cloudflare rate limiting response and With response code at 429.
Under With the following behavior, select Throttle requests over the maximum configured rate.
Under Execution order, leave Select order set to Last.
Under Status, leave Active selected.
Select Deploy.
In the Deploy rule to production? dialog, select Deploy.
5.2 Verify the Stuffer Block and Mobile Login
On Security > Security rules, locate the Advanced rate limiting rules card and select the linked Events count in the ARL - Leaked Credential Attempts row.
On the opened Security Analytics > Events page, set the time range to Last 30 minutes.
Above the events chart, retain the rule filter added by the linked Events count.
Add the following Events filters.
| Field | Operator | Value |
|---|---|---|
| Path | equals | /api/mobile/login |
| Action | equals | Block |
In Sampled logs, select the left caret of the newest sampled log row recorded after the rule was deployed.
In Matched service, verify Service is Rate limiting rules, Rule is ARL - Leaked Credential Attempts, and Action taken is Block.
In Request analyses, verify JA4 fingerprint matches <CREDENTIAL_STUFFER_JA4>.
In Request details, verify Path is /api/mobile/login and User agent is curl/8.10.1, then compare its IP address with <CREDENTIAL_STUFFER_FIRST_IP>.
If the newest blocked source matches <CREDENTIAL_STUFFER_FIRST_IP>, expand another sampled Block row for this rule until you can compare a different source IP with the same JA4.
At the top of Security Analytics, select the Traffic tab, set Last 30 minutes, and select Clear all above the request chart.
Add the following Traffic filters.
| Field | Operator | Value |
|---|---|---|
| Path | equals | /api/mobile/login |
| Source user agent | equals | SingleOrigin-Mobile/3.1.0 (iOS 18.2; iPhone15,3) |
| Edge status code | equals | 200 OK |
In Sampled logs, select the left caret of the newest matching sampled log row.
Under Request analyses, verify Bot score is Likely automated.
Under Request details, verify User agent is SingleOrigin-Mobile/3.1.0 (iOS 18.2; iPhone15,3), Path is /api/mobile/login, and Edge status code is 200.
200. Sampled logs can omit a specific request; record missing evidence as a mismatch instead of inferring a complete count.Activity 6 (SEC3-6): Protect the Orders API
6.1 Create the Orders API Rate Limit
In the selected domain's left sidebar, select Security > Security rules.
At the top of Security rules, select Create rule and select Rate limiting rules in its menu.
In Rule name, enter ARL - API Scraping.
Under When incoming requests match…, select Edit expression and paste the copied expression:
(http.request.uri.path eq "/api/v1/orders" and cf.bot_management.score eq 1 and http.user_agent eq "curl/8.10.1")
Under With the same characteristics, open the Field menu and select the rendered JA4 Fingerprint option.
Verify that JA4 Fingerprint replaces IP as the selected counting characteristic and leave Use custom counting expression unselected.
Under When rate exceeds…, enter 10 in Requests and select 1 minute for Period.
Under Then take action…, select Block and leave the default Cloudflare rate-limiting response code at 429.
Under With the following behavior, select Throttle requests over the maximum configured rate.
Under Execution order, leave Select order at Last.
Under Status, leave Active selected.
Select Deploy, then select Deploy in the Deploy rule to production? dialog.
curl/8.10.1 user agent narrow which requests the rule counts. The mobile client must still pass the separate Traffic check.6.2 Verify Scraper Blocking and Mobile Orders
On Security > Security rules, locate the Advanced rate limiting rules card and select the linked Events count in the ARL - API Scraping row.
On Security Analytics > Events, set the time range to Last 30 minutes and retain the rule filter created by the linked count.
Add the following Events filters.
| Field | Operator | Value |
|---|---|---|
| Path | equals | /api/v1/orders |
| Action | equals | Block |
In Sampled logs, select the left caret of the newest sampled log row recorded after the rule was deployed.
Under Matched service, verify that Service is Rate limiting rules, Rule is ARL - API Scraping, and Action taken is Block.
Under Request analyses, verify that Bot score matches the rule expression's cf.bot_management.score eq 1 condition and JA4 fingerprint matches <ORDERS_SCRAPER_JA4>.
Under Request details, verify that Path is /api/v1/orders and User agent is curl/8.10.1.
At the top of Security Analytics, select Traffic, set Last 30 minutes, and select Clear all above the request chart.
Add the following Traffic filters.
| Field | Operator | Value |
|---|---|---|
| Path | equals | /api/v1/orders |
| Source user agent | equals | SingleOrigin-Mobile/3.1.0 (iOS 18.2; iPhone15,3) |
| Edge status code | equals | 200 OK |
In Sampled logs, select the left caret of the newest matching sampled log row.
Under Request analyses, verify Bot score is Likely automated and JA4 fingerprint matches <ORDERS_SCRAPER_JA4>.
Under Request details, verify Path is /api/v1/orders and User agent is SingleOrigin-Mobile/3.1.0 (iOS 18.2; iPhone15,3).
Under Edge response, verify Mitigation is Not mitigated, Edge status code is 200 - OK, and Origin status code is 200 - OK.
ARL - API Scraping on the scraper path, and a separate current Traffic row shows the legitimate mobile orders request at 200 even though it shares the scraper's JA4.6.3 Final Retained State
In the selected domain's left sidebar, select Security > Settings.
In Filter by groups, select Fraud, then verify that Leaked credentials detection shows On.
In Filter by groups, select Precursor, then verify that the Precursor row shows its switch On.
Select the Precursor row and verify that Minimize Friction is selected in the Precursor dialog.
Select Close in the Precursor dialog.
In the selected domain's left sidebar, expand AI Crawl Control and select Security.
In the crawler table, verify that PerplexityBot has Block Crawler off and GPTBot has Block Crawler on.
In the selected domain's left sidebar, select Security > Settings, then select Precursor under Filter by groups.
In the Precursor row, select the Configurable Rules: <number> rules link, where <number> is the displayed count.
On the Precursor Rules page, verify that MAXIMIZE - Login shows Active.
In the selected domain's left sidebar, select Security > Security rules.
Select Show all rule types, select Custom rules, and verify that CHALLENGE - Admin Credential Stuffing shows Active.
Select Show all rule types, select Advanced rate limiting rules, and verify that the inherited RATE-LIMIT - Product API shows Active.
On the same Advanced rate limiting rules list, verify that ARL - Leaked Credential Attempts and ARL - API Scraping both show Active.
7. End-of-Lab Results
Record each activity as Success, Blocked, or Mismatch observed based on its final verification.
For every mismatch, record the time range, filters, expected value, observed value, and affected rule or setting.
Include missing sampled evidence as a result rather than treating it as proof that the configuration failed.
Submit one end-of-lab results summary covering all six activities and retain the final settings and rules for the class recap.
AppSec 4 - Stop Attacks in Real Time
| Activity | Mode | Goal | Time |
|---|---|---|---|
| 1. Evaluate Under Attack Mode | Instructor-driven, optional follow-along | Observe the reach of a broad emergency control and return it to Off | 4 minutes |
| 2. Investigate the Search Incident | Solo | Correlate attack traffic, rate-limit responses, and application 503 responses | 18 minutes |
| 3. Derive and Deploy a Safer Rate Limit | Solo | Record a decision, then update the inherited rule | 18 minutes |
| 4. Evaluate the Mitigation and Close | Synchronous | Prove activation, recovery, attack suppression, and legitimate-client safety | 12 minutes |
Before You Begin
Prerequisites
- Your assigned lab slug, which forms
https://<lab-slug>.cftraining.app. - Proxied apex and www CNAME records that keep their complete pod-provided generated origin target unchanged.
- Access to the Cloudflare dashboard and the account containing your assigned domain.
- A normal browser window for the dashboard and a private or incognito window for visitor testing.
- The lab-provided shopper, health-monitor, attack, and
SEC4-TESTtraffic.
Dashboard orientation
- Open the Cloudflare dashboard.
- Select your assigned account.
- Select Domains, select Overview, and select
<lab-slug>.cftraining.app. - Use the selected domain's left navigation for the rest of the lab.
| Destination | Navigation | Purpose |
|---|---|---|
| Domain Overview | Overview | Briefly evaluate Under Attack Mode |
| Security Analytics | Security > Analytics > Traffic | Compare request paths, rates, sources, and response codes |
| Security Events | Security > Analytics > Events | Confirm which rule and action handled a request |
| Request rate analysis | Security > Analytics > Traffic, then Request rate analysis | Compare legitimate and attack source-IP rates |
| Rate limiting rules | Security > Security rules > Rate limiting rules | Inspect and edit the inherited rule |
Activity 1 (SEC4-1): Evaluate Under Attack Mode
1.1 Evaluate Under Attack Mode
On the domain Overview page, find the Under Attack Mode card and turn its switch On.
In the Enable Under Attack Mode dialog, select Enable.
Confirm the dashboard displays the Under Attack Mode is active alert. This alert remains on Overview while the switch is active.
Open a private browser session on the lab Linux desktop and visit https://<lab-slug>.cftraining.app/search.
You should get a Managed Challenge page where you might need to select the Verify you are human checkbox, or the security verification might happen for you automatically. That's the Cloudflare Managed Challenge behavior.
Confirm the browser proceeds to the normal Single Origin search page.
500 error instead of immediately showing the verification page. Refresh the browser once. Confirm the verification page now shows the intended destination in the address bar, such as /login; select Verify you are human if prompted; then confirm the intended page loads./search. It can be appropriate briefly during an emergency, but the proportionate response is a targeted /search rate-limit rule that suppresses abuse while preserving legitimate traffic.Go back to the Overview page and select the enabled Under Attack Mode switch to open the Disable Under Attack Mode dialog. Confirm the I'm under attack mode toggle is On, turn it Off, wait for the update, and select Close.
Return to the browser and reload /search. Confirm it loads the normal Single Origin search page directly without the verification page.
Activity 2 (SEC4-2): Investigate the Search Incident
2.1 Isolate the Affected Route
Go to Security > Analytics and select Traffic.
Set the time range to Last 24 hours.
Select Add filter, set Path equals /search, and select Apply.
In Edge status codes, confirm 200, 429, and 503 are present.
If Source user agents is not displayed, select Show more top statistics.
In Source user agents, confirm SingleOrigin-HealthMonitor/1.0 (+https://singleorigin.example/monitoring) is present.
Select Add filter, set Edge status code equals 503, and select Apply.
In Sampled logs, select the caret at the left of the newest matching row to expand it.
Under Request details, confirm Path is /search.
Under Request details, confirm the query string contains q=connect-load and complex=1, in either order.
Under Request details, record IP in the saved field below.
Remove only the Edge status code equals 503 filter.
2.2 Inspect the Inherited Rule
Go to Security > Security rules.
Select Show all rule types.
In Rate limiting rules, open Block high rate of requests.
Confirm the rule matches exact path /search.
Confirm With the same characteristics is IP.
Confirm Requests is 200 and Period is 1 minute.
Confirm Action is Block and the selected mitigation duration is 1 minute.
Leave the rule without changing it.
Return to the Block high rate of requests row and select its linked count in the Events column.
Set the time range above Events summary to include the current lab traffic.
Select Add filter, set Path equals /search, and select Apply.
In Sampled logs, select the caret at the left of the newest matching row to expand it.
Under Matched service, confirm Action taken is Block.
Activity 3 (SEC4-3): Derive and Deploy a Safer Rate Limit
3.1 Record Your Decision First
Go to Security > Analytics > Traffic and keep Path equals /search.
Select Request rate analysis.
In the source-IP results, locate the highest requests-per-minute value for each visible bucket.
Confirm the attack source is the clear outlier.
Record the highest non-attack source-IP bucket you observe in the saved field below.
Use that observed peak as the legitimate-traffic boundary for your decision.
Record the threshold, action, and mitigation timeout you would choose and why in the saved fields below.
Stop before the supplied target until all three choices are recorded.
3.2 Compare with the Scenario Target
| Setting | Target |
|---|---|
| Match and counter | Keep exact /search, source IP, and implicit per-data-center scope |
| Threshold | 60 requests per 60 seconds |
| Action | Managed Challenge |
| Mitigation timeout | 600 seconds |
3.3 Edit the Existing Rule
Return to Security > Analytics > Traffic.
Keep Path equals /search applied.
Select Add filter, set Source IP equals <ATTACK_SOURCE_IP>, and select Apply.
Set a time range that includes at least 15 minutes of the current attack traffic, and note the time zone shown in the time-range control.
In the request chart, record the newest completed time bucket and its Mitigated by Cloudflare and Served by origin values in the saved field below.
Go to Security > Security rules.
Select Show all rule types.
In Rate limiting rules, open Block high rate of requests.
Keep exact /search, the IP characteristic, the 1 minute period, and the existing position.
Change Requests from 200 to 60.
Change Action from Block to Managed Challenge.
Under With the following behavior, keep Managed Challenge for the selected duration selected.
Change the selected duration from 1 minute to 10 minutes.
Immediately before selecting Save, record the current date and time in the dashboard time zone in the saved field below. Then select Save and wait for the save to complete.
Reopen the rule and confirm every saved value.
/search and source-IP counting, with 60 requests per 60 seconds, Managed Challenge, and 600-second mitigation.Activity 4 (SEC4-4): Evaluate the Mitigation and Close
4.1 Prove Rule Activation
Go to Security > Analytics and select Events.
Select the time range above Events summary, then select Custom range.
The fields use the dashboard time zone. In From, enter <DEPLOYMENT_TIME>.
Set To to the current date and time, and select Apply.
Select Add filter, set Path equals /search, and select Apply.
Select Add filter, set Source user agent equals Connect-Threshold-Test/1.0, and select Apply.
Select Add filter, set Action equals Managed Challenge, and select Apply.
In Sampled logs, look for a matching row.
If no matching row appears, wait for the next scheduled run and allow time for Analytics to update.
After waiting, reopen the time range, update To to the current date and time, and select Apply.
If no matching row appears after Analytics updates, go to Security > Security rules, select Show all rule types, and open Block high rate of requests from Rate limiting rules.
If no matching row appears after Analytics updates, verify the saved threshold, action, duration, and status, close the editor without changing it, record blocked - no matching event in the saved field above, do not substitute a Managed Challenge Event from the attack source, and continue to 4.2 with the enforcement gate blocked.
If a matching row appears, confirm Managed Challenge has a non-zero total in Events summary.
In Rate limiting rules, confirm Block high rate of requests has a non-zero total.
In Sampled logs, select the caret at the left of the newest matching row to expand it.
In that row, under Matched service, confirm Action taken is Managed Challenge, not Block.
Record Date from the expanded row in Sampled logs.
Under Request details, record Ray ID in the saved field above; do not require one specific response status.
4.2 Prove Application Recovery
Return to Security > Analytics and select Traffic.
Keep the same time range used for the pre-deployment baseline and include at least 60 seconds after <DEPLOYMENT_TIME>.
Remove each existing filter.
Select Add filter, set Path equals /search, and select Apply.
Select Add filter, set Source IP equals <ATTACK_SOURCE_IP>, and select Apply.
In Sampled logs, select the caret at the left of the newest post-deployment row to expand it.
Under Request details, confirm the query string contains q=connect-load and complex=1, in either order.
Compare <PRE_DEPLOYMENT_BASELINE> with completed post-deployment buckets for Mitigated by Cloudflare and Served by origin.
Confirm the mitigated count grows while origin-served attack responses stop growing.
Select Add filter, set Edge status code equals 503, and select Apply.
In Sampled logs, confirm no 503 row has a Time in the 60-second post-deployment window.
Remove only the Edge status code equals 503 filter.
Record this as a sampled no-503 result, not proof that every application response succeeded.
Do not require total attack requests to drop because Cloudflare can continue receiving and mitigating them at the edge.
4.3 Protect Legitimate Clients
In Security > Analytics > Traffic, remove each existing filter.
Select Add filter, set Path equals /search, and select Apply.
Select Add filter, set Source IP does not equal <ATTACK_SOURCE_IP>, and select Apply.
Select Add filter, set Source user agent does not equal Connect-Threshold-Test/1.0, and select Apply.
Select Add filter, set Source user agent does not equal SingleOrigin-HealthMonitor/1.0 (+https://singleorigin.example/monitoring), and select Apply.
In Sampled logs, select the caret at the left of the newest remaining row to expand it.
Under Request details, confirm the query string contains q=espresso and complex=0, in either order.
Under Edge response, confirm Edge status code is 200.
Remove only the Source user agent does not equal SingleOrigin-HealthMonitor/1.0 (+https://singleorigin.example/monitoring) filter.
Select Add filter, set Source user agent equals SingleOrigin-HealthMonitor/1.0 (+https://singleorigin.example/monitoring), and select Apply.
In Edge status codes, confirm the monitor requests return 200.
In a private browser, open https://<lab-slug>.cftraining.app/search.
Confirm the ordinary browser search works normally.
Final Retained State
| Item | Required final state |
|---|---|
| Under Attack Mode | Off |
| Bot Fight Mode | Unchanged by the lab; Off when the control is exposed |
| Rule | Block high rate of requests, enabled |
| Match and counter | Exact /search, source IP, implicit per-data-center scope |
| Threshold | 60 requests per 60 seconds |
| Action | Managed Challenge |
| Mitigation timeout | 600 seconds |
SEC4-TEST schedules.Troubleshooting
| Symptom | What to check |
|---|---|
No /search Traffic | Confirm exact lowercase path, broaden the time range, and wait for supplied traffic |
| No Events | Confirm the inherited rule is enabled and inspect fresh requests |
| Request rate analysis is missing | Confirm you are on Security > Analytics > Traffic in the assigned Enterprise zone |
| Starting values differ | Stop and ask the instructor to restore the baseline |
| The threshold-test run is missing from Traffic | Confirm the time range and exact Connect-Threshold-Test/1.0 user-agent filter; do not create replacement traffic |
| Threshold-test Traffic appears but no matching Event appears | Verify the saved rule, record blocked - no matching event, and do not use attack-source Events as substitute proof |
| Managed Challenge returns an unexpected status | Use the Event action and client evidence; do not assume a universal status |
| Old 503 rows remain visible | Compare each row's Time with <DEPLOYMENT_TIME> and evaluate only the 60-second post-deployment window |
| Total attack requests continue after mitigation | Confirm the mitigated count grows while origin-served attack responses and 503 stop growing; edge mitigation does not require the sender to stop |
| A legitimate client fails | Stop at that gate and inspect the matching request before changing the rule |
Resources
Reference material for all four classes. External links open Cloudflare documentation in a new tab.
SSL/TLS Encryption Modes
Analytics and Logs
Security Rules
Bots and Abuse
Tools and Logs
End of Lab Guide.