Use an approved owned dev lab. Read health JSON; run plan, doctor, validate. Origin must stay 403 even with copied FDID. No extra app roles. Stop on ownership/HTTPS/origin failures.
Generate a bounded run
bash scripts/dojo.sh simulate --environment dev --yes
Five benign requests share a new UUIDv4; only the first carries dojoProbe=waf-marker. Save the run/UTC window. Detection: five HTTP 200s. No command, payload, arbitrary destination, or browser run control.
Expiry is not deletion; the log cap is not a budget.
STEP 2 OF 10
A stranger at the edge
Story order is not a detection or ingestion timetable.
Ghostpaw's move: Ghostpaw probes the public PHP entry point.
WITHOUT WORKLOAD DEFENDER / RAW CLUES
What the analyst can see
Triage request/WAF logs manually; these are not workload alerts.
92ad189c-9a88-4403-b773-52453963e4b8: 2026-10-24T16:33:41.463Z to 2026-10-24T16:33:43.454Z; collected 2026-10-24T16:36:07.232Z (UTC).
Baseline: five HTTP 200s / five synthetic records. Block/Detection is not enforced blocking. Defender: AppServices/CloudPosture/Containers Standard. The direct provider alert query succeeded and returned [] for the exact app/window. Four Healthy assessments are not four detections, not necessarily exclusive to paid CSPM.
Not a Defender-disabled control run. References are not fired alerts; missing alerts are not proof of safety.
Alerts and expected results
The alert queue is not the log stream
Expected outcomes, not live alert counts. Missing evidence is not proof of safety.
Profile
This safe replay
What not to expect
Without optional Defender/Sentinel
Delivered WAF/app logs; manual KQL.
No Defender or scheduled Sentinel alert.
With paid Defender CSPM
Actual supported posture/graph results.
No guaranteed CVE finding, attack path or shell alert.
Possible Informational synthetic correlation when logs match.
Not a Defender detection or automatic incident.
Defender for Cloud > Security alerts: filter asset/time; save IDs, titles, severity, evidence and status. Posture is separate; references never fill an empty queue.
Queries, timeline and hunting results
Build the evidence timeline
In workspace Logs, set RunIdFilter and UTC window. WAF records use AzureDiagnostics; PHP events use AppServiceConsoleLogs. Run detections/waf-requests.kql and correlation.kql, replacing __APP_RESOURCE_ID__.
Check rule/action, request/reference, resource/time, synthetic: true. No DeviceProcessEvents/DeviceNetworkEvents. Ingestion does not make fixtures real.
bash scripts/dojo.sh investigate --environment dev
Without paid Defender CSPM: configuration/recommendations. With paid Defender CSPM: actual graph/paths. Empty is not clearance; CVE keywords are not findings.
--enable-defender-cspm is billable subscription-wide Standard, not other plans. No recommendation export is configured.
Choose the right protection layer
Foundational CSPM: free recommendations. Paid CSPM: supported graph/paths. Serverless protection is separate; pricing is not scanning. App Service is not MDE. Verify plans/support in Environment settings; incident creation is disabled.
Defender and Sentinel status: not queried by this page. Omitted flags do not mean off; no extra app permissions are needed.
Optional Sentinel analytics
Correlation is not automatically an incident
Hunt manually without Sentinel. --enable-sentinel installs a disabled rule; --enable-analytics additionally enables evaluation. Review costs and plan/deploy flags.
CONFIGURED RULE / NOT AN OBSERVED ALERT
PHP to Proof - SYNTHETIC multi-signal training correlation
15-minute evaluation / one-hour window: WAF marker and at least two distinct synthetic app signals, same run, recent ingestion. Late data can miss; matches repeat. No timing guarantee. createIncident: false; no connector/playbook.
STEP 8 OF 10
Prevent the next request
Expected after an approved change in your own lab, not a captured after-state:
bash scripts/dojo.sh protect --environment dev --yes
bash scripts/dojo.sh simulate --environment dev --yes
Prevention: marker 403, four other signals 200. Normal traffic must work; origin stays403.
Official response and scripts: stage three request rules in Log first. Response rule99006001 has no WAF hits/logs. WAF mitigation is not a PHP patch.
STEP 9 OF 10
Resolve and verify
bash scripts/dojo.sh remediate --environment dev --yes
bash scripts/dojo.sh validate --environment dev
Fixed: five signals404 without the WAF marker; health200, origin403. Repair preserves fixed/Prevention/expiry. Fixture removal is not a PHP patch.
Resolution script and closure checks: verify running PHP8.4.27+, rebuild images, inspect findings. Approved window required; no after-state is claimed.
STEP 10 OF 10
Close the case
Save asset/run/UTC, WAF action, fixtures and real finding IDs. Verify isolation, unmarked fixed 404, ingestion and cleanup. Guide: docs/walkthrough.md.
Use Uninstall in the deployment wizard when finished. Expiry is not deletion.
Optional private container lab
A different lab, with real image evidence
docs/container-lab.md: private affected/fixed images, existing plans/sensors, verified findings. No exploit/public ingress/guaranteed alert. Separate costs/teardown.
Plain-language glossary
Logs, alerts and incidents
Log / alert / incident: record / detector conclusion / grouped case. Synthetic: fabricated, even if ingested.