Skip to content

Phase 3 — Mitigate

Phase 3 creates a before/after proof of CSD mitigation. Re-run the authorized simulation over HTTPS to establish a baseline, mitigate only script domains observed in that baseline and current telemetry, then repeat the same run. Phase 2 has one entry gate: DET-3 must PASS; DET-1 and DET-4 may remain PENDING.

Step 1: Confirm No Active Mitigations (Baseline)

Section titled “Step 1: Confirm No Active Mitigations (Baseline)”

Before capturing the “before” snapshot, use the Phase 1 CSD_API_SESSION_FILE, ledger_outcome, and ledger_record helpers in the same shell. Normalize the current API URL, derive its tenant identity, resolve the ledger path, and validate the exact API URL, tenant, namespace, and domain before any request:

Terminal window
case "${XCSH_API_URL:-}" in https://*) ;; *) exit 1 ;; esac
while [ "${XCSH_API_URL%/}" != "$XCSH_API_URL" ]; do
XCSH_API_URL=${XCSH_API_URL%/}
done
XCSH_TENANT_HOSTNAME=${XCSH_API_URL#https://}
case "$XCSH_TENANT_HOSTNAME" in ''|*/*|*:*|*[!A-Za-z0-9.-]*) exit 1 ;; esac
XCSH_TENANT_IDENTITY=${XCSH_TENANT_HOSTNAME%%.*}
[ -n "$XCSH_TENANT_IDENTITY" ] || exit 1
case "${CSD_API_SESSION_FILE:-.csd-api-session.json}" in
/*) CSD_API_SESSION_FILE=${CSD_API_SESSION_FILE:-.csd-api-session.json} ;;
*) CSD_API_SESSION_FILE="$PWD/${CSD_API_SESSION_FILE:-.csd-api-session.json}" ;;
esac
CSD_API_SESSION_DIR=$(dirname -- "$CSD_API_SESSION_FILE")
CSD_API_SESSION_NAME=$(basename -- "$CSD_API_SESSION_FILE")
[ -d "$CSD_API_SESSION_DIR" ] && [ "$CSD_API_SESSION_NAME" != . ] && [ "$CSD_API_SESSION_NAME" != .. ] || exit 1
CSD_API_SESSION_DIR=$(cd "$CSD_API_SESSION_DIR" && pwd -P) || exit 1
CSD_API_SESSION_FILE="$CSD_API_SESSION_DIR/$CSD_API_SESSION_NAME"
export CSD_API_SESSION_FILE CSD_API_SESSION_DIR XCSH_API_URL XCSH_TENANT_HOSTNAME XCSH_TENANT_IDENTITY
jq -e --arg api_url "$XCSH_API_URL" --arg tenant_hostname "$XCSH_TENANT_HOSTNAME" \
--arg tenant_identity "$XCSH_TENANT_IDENTITY" --arg ns "$XCSH_NAMESPACE" \
--arg domain "$XCSH_DOMAINNAME" --arg protected_name "$XCSH_LB_NAME" \
--arg pool_name "$XCSH_ORIGIN_POOL" --arg lb_name "$XCSH_LB_NAME" \
--arg hc_name "${XCSH_HC_NAME:-}" '
(keys | sort) == ["environment","outcomes","ownership_mode","resources","schema_version","session_id"] and
.schema_version == 1 and .ownership_mode == "api" and
(.session_id | type == "string" and test("^[0-9]{8}T[0-9]{6}Z$")) and
.environment == {
api_url: $api_url, tenant_hostname: $tenant_hostname, tenant_identity: $tenant_identity,
namespace: $ns, domain: $domain
} and
(.resources | type == "array") and
(all(.resources[];
(keys | sort) == ["kind","name","namespace","spec","status"] and
(.kind | IN("namespace","protected_domain","healthcheck","origin_pool","http_loadbalancer","mitigated_domain")) and
.namespace == $ns and
(.name | type == "string" and test("^[a-z]([a-z0-9-]{0,62}[a-z0-9])?$")) and
(.status | IN("created","pre-existing","unknown")) and
(
(.kind == "namespace" and .name == $ns) or
(.kind == "protected_domain" and .name == $protected_name) or
(.kind == "origin_pool" and .name == $pool_name) or
(.kind == "http_loadbalancer" and .name == $lb_name) or
(.kind == "healthcheck" and $hc_name != "" and .name == $hc_name) or
(.kind == "mitigated_domain")
) and
(.spec | type == "object")
)) and
([.resources[] | [.kind,.namespace,.name] | join("\u0000")] | length) ==
([.resources[] | [.kind,.namespace,.name] | join("\u0000")] | unique | length) and
([.resources[] | select(.status == "unknown")] | length == 0) and
(.outcomes | type == "array") and
(all(.outcomes[];
(keys | sort) == ["kind","name","namespace","operation","result"] and
(.operation | IN("GET","POST","PUT")) and
(.kind | IN("namespace","protected_domain","healthcheck","origin_pool","http_loadbalancer","mitigated_domain")) and
.namespace == $ns and
(.name | type == "string" and test("^[a-z]([a-z0-9-]{0,62}[a-z0-9])?$")) and
(
(.kind == "namespace" and .name == $ns) or
(.kind == "protected_domain" and .name == $protected_name) or
(.kind == "origin_pool" and .name == $pool_name) or
(.kind == "http_loadbalancer" and .name == $lb_name) or
(.kind == "healthcheck" and $hc_name != "" and .name == $hc_name) or
(.kind == "mitigated_domain")
) and
(.result | IN("match","absent","created","replaced","conflict","unknown"))
)) and
([.outcomes[] | select(.result == "unknown")] | length == 0)
' "$CSD_API_SESSION_FILE" >/dev/null || {
echo "STOP: mitigation ledger is corrupt, mismatched, duplicated, or has unknown ownership"
exit 1
}

List mitigated domains. If the count is not 0, stop and use Phase 4 to remove only mitigation entries recorded as created by their originating session. Baseline cleanup must never guess names or delete unrecorded resources.

Terminal window
curl -s \
-H "Authorization: APIToken xXCSH_API_TOKENx" \
"xXCSH_API_URLx/api/shape/csd/namespaces/xXCSH_NAMESPACEx/mitigated_domains" \
| jq '{count: (.items | length)}'
Terminal window
curl -s \
-H "Authorization: APIToken xXCSH_API_TOKENx" \
"xXCSH_API_URLx/api/shape/csd/namespaces/xXCSH_NAMESPACEx/detected_domains" \
| jq '{total_domains: .domain_summary.totalDomains.count, domains: [.domains_list[]? | {domain, category}]}'
CheckExpectedStatus
Mitigated domain count0 (clean baseline)PASS if 0; otherwise reconcile owned entries before continuing
DET-3At least one synthetic external destination from the Phase 2 run appears in /detected_domainsRequired to proceed
Slower checksDET-1 and DET-4PENDING is allowed

Re-run the combined simulation with no mitigations active to capture a fresh baseline. This is the “before” snapshot: a record of which candidate browser requests were observed before CSD mitigation was applied.

AI assistants with browser automation tools run the same Phase 2 simulation against the protected HTTPS application:

  1. Navigate with initScript — use a clean context, then navigate to https://$XCSH_DOMAINNAME/#/login with the Phase 2 initScript.
  2. Dismiss Welcome Banner — press Escape if it appears.
  3. Wait for completion — allow the candidate requests to settle; ten seconds is a common lab observation, not a product guarantee.
  4. Capture baseline evidence — record console completion and the browser Network results for every candidate script and fetch request. This observed set defines eligible mitigation targets.

Operators without browser automation tools run the simulation manually using the same procedure as Phase 2 — Step 8: Attack Simulation:

  1. Navigate to https://xXCSH_DOMAINNAMEx/#/login
  2. Enter synthetic markers in the Email and Password fields (do not submit)
  3. Open DevTools and select the Console and Network tabs
  4. Run the Combined Detection Script from Trigger Detection
  5. Record the script and fetch requests actually observed; do not assume all candidates completed
CheckExpected (Before Mitigation)Status
Protected applicationLoaded over HTTPSPASS / FAIL
HTTP redirecthttp://xXCSH_DOMAINNAMEx/ returns 301; do not execute the simulation over HTTPPASS / FAIL
Candidate script requestsRecord the observed subset and result for eachPASS / FAIL
Synthetic fetch requestsRecord the observed browser result for eachPASS / FAIL
Console output[CSD Demo] Simulation completePASS / FAIL

The browser Network record is the baseline execution evidence. Preserve the exact observed script-domain subset for Step 3.

Mitigate only script domains that satisfy both conditions: they were observed in the Step 2 browser Network baseline, and they appear in the current /detected_domains response. Do not require all four CDN candidates and do not add synthetic fetch destinations merely because the harness attempted them.

Prepare a reviewed tab-separated list containing only that intersection. Each resource name must be a DNS label and each hostname remains in spec.mitigated_domain:

Terminal window
cat >"$CSD_API_SESSION_DIR/observed-mitigation-targets.tsv" <<'TARGETS'
# Include only rows supported by this run's browser and API evidence.
# cdn-jsdelivr-net<TAB>cdn.jsdelivr.net
TARGETS

Review the file before continuing. An empty target list blocks mitigation because there is no observed script-domain baseline to compare.

For each reviewed pair, GET the exact DNS-label name first, then append exactly one ledger outcome before processing the next pair. A successful POST is created; an exact GET or 409 is pre-existing; timeout, malformed response, conflict, or ambiguous 5xx is unknown and stops the phase. A 409 is never evidence that this session created the object.

Terminal window
mitigate_domain() {
name=$1 domain=$2
base="$XCSH_API_URL/api/shape/csd/namespaces/$XCSH_NAMESPACE/mitigated_domains"
spec=$(jq -cn --arg domain "$domain" '{mitigated_domain:$domain}') || return 1
body=$(mktemp) || return 1
code=$(curl -sS -o "$body" -w '%{http_code}' \
-H "Authorization: APIToken xXCSH_API_TOKENx" \
"$base/$name") || code=000
case "$code" in
200)
if jq -e --arg name "$name" --arg ns "$XCSH_NAMESPACE" --arg domain "$domain" '
.metadata.name == $name and .metadata.namespace == $ns and
.spec.mitigated_domain == $domain
' "$body" >/dev/null; then
ledger_outcome GET mitigated_domain "$XCSH_NAMESPACE" "$name" match || return 1
ledger_record mitigated_domain "$XCSH_NAMESPACE" "$name" pre-existing "$spec" || return 1
else
ledger_outcome GET mitigated_domain "$XCSH_NAMESPACE" "$name" unknown || return 1
ledger_record mitigated_domain "$XCSH_NAMESPACE" "$name" unknown "$spec" || return 1
rm -f "$body"
return 1
fi
;;
404)
ledger_outcome GET mitigated_domain "$XCSH_NAMESPACE" "$name" absent || return 1
code=$(curl -sS -o "$body" -w '%{http_code}' -X POST \
-H "Authorization: APIToken xXCSH_API_TOKENx" \
-H "Content-Type: application/json" \
-d "$(jq -cn --arg name "$name" --arg ns "$XCSH_NAMESPACE" --arg domain "$domain" \
'{metadata:{name:$name,namespace:$ns},spec:{mitigated_domain:$domain}}')" \
"$base") || code=000
case "$code" in
200|201)
if jq -e --arg name "$name" --arg ns "$XCSH_NAMESPACE" --arg domain "$domain" '
.metadata.name == $name and .metadata.namespace == $ns and
.spec.mitigated_domain == $domain
' "$body" >/dev/null; then
ledger_outcome POST mitigated_domain "$XCSH_NAMESPACE" "$name" created || return 1
ledger_record mitigated_domain "$XCSH_NAMESPACE" "$name" created "$spec" || return 1
else
ledger_outcome POST mitigated_domain "$XCSH_NAMESPACE" "$name" unknown || return 1
ledger_record mitigated_domain "$XCSH_NAMESPACE" "$name" unknown "$spec" || return 1
rm -f "$body"
return 1
fi
;;
409)
ledger_outcome POST mitigated_domain "$XCSH_NAMESPACE" "$name" conflict || return 1
code=$(curl -sS -o "$body" -w '%{http_code}' \
-H "Authorization: APIToken xXCSH_API_TOKENx" \
"$base/$name") || code=000
if [ "$code" = 200 ] && jq -e --arg name "$name" --arg ns "$XCSH_NAMESPACE" \
--arg domain "$domain" '
.metadata.name == $name and .metadata.namespace == $ns and
.spec.mitigated_domain == $domain
' "$body" >/dev/null; then
ledger_outcome GET mitigated_domain "$XCSH_NAMESPACE" "$name" match || return 1
ledger_record mitigated_domain "$XCSH_NAMESPACE" "$name" pre-existing "$spec" || return 1
else
ledger_outcome GET mitigated_domain "$XCSH_NAMESPACE" "$name" unknown || return 1
ledger_record mitigated_domain "$XCSH_NAMESPACE" "$name" unknown "$spec" || return 1
rm -f "$body"
return 1
fi
;;
*)
ledger_outcome POST mitigated_domain "$XCSH_NAMESPACE" "$name" unknown || return 1
ledger_record mitigated_domain "$XCSH_NAMESPACE" "$name" unknown "$spec" || return 1
rm -f "$body"
return 1
;;
esac
;;
*)
ledger_outcome GET mitigated_domain "$XCSH_NAMESPACE" "$name" unknown || return 1
ledger_record mitigated_domain "$XCSH_NAMESPACE" "$name" unknown "$spec" || return 1
rm -f "$body"
return 1
;;
esac
rm -f "$body"
}
target_count=0
while IFS="$(printf '\t')" read -r name domain; do
case "$name" in ''|'#'*) continue ;; esac
[ -n "$domain" ] || { echo "STOP: malformed mitigation target"; exit 1; }
mitigate_domain "$name" "$domain" || exit 1
target_count=$((target_count + 1))
done <"$CSD_API_SESSION_DIR/observed-mitigation-targets.tsv"
[ "$target_count" -gt 0 ] || { echo "STOP: no observed mitigation targets"; exit 1; }

Do not retry a missing or failed item by POSTing blindly: the ledger’s uniqueness rule prevents rewriting ownership history. Resolve the unknown entry first and start a new reviewed session if necessary.

List all mitigated domains and reconcile the reviewed targets against the collection and ledger:

Terminal window
curl -s \
-H "Authorization: APIToken xXCSH_API_TOKENx" \
"xXCSH_API_URLx/api/shape/csd/namespaces/xXCSH_NAMESPACEx/mitigated_domains" \
| jq '{count: (.items | length), items: [.items[]? | {name: .metadata.name, domain: .spec.mitigated_domain}]}'
CheckExpectedStatus
Reviewed targetsExactly the non-empty observed intersection from Step 3PASS / FAIL
Ledger outcomesOne unique entry per reviewed target; each created or pre-existing; none unknownPASS / FAIL
Created ownershipOnly a 200/201 POST is created; every 409 is pre-existingPASS / FAIL

Re-run the exact same HTTPS simulation and compare browser Network behavior for the reviewed target domains. The simulation script is unchanged; only mitigation configuration differs.

  1. Use a clean browser context and navigate to https://$XCSH_DOMAINNAME/#/login with the Phase 2 initScript.
  2. Dismiss the Welcome Banner if present.
  3. Allow requests to settle using the same observation method as the baseline.
  4. Capture console completion and Network results for every reviewed target domain.
  1. Navigate to https://xXCSH_DOMAINNAMEx/#/login.
  2. Enter the same synthetic markers used in the baseline.
  3. Open DevTools and preserve the Network log.
  4. Run the same Combined Detection Script.
  5. Compare each reviewed target’s browser request with the Step 2 baseline.
CheckExpected (After Mitigation)Status
Reviewed script domainsAt least one browser-observed request outcome differs from its successful baseline in a way consistent with enforcementPASS / PENDING / FAIL
Unreviewed domainsNo mitigation claimINFO
Synthetic fetch requestsRecord observed results; they are not mitigation targets in this procedureINFO
API configurationReviewed domains appear in the mitigated-domain collection and ledgerPASS / FAIL
Console output[CSD Demo] Simulation completePASS / FAIL

Browser Network behavior is the enforcement proof. API counters and list membership are supporting configuration evidence only.

Compare only the reviewed domains observed in the Step 2 baseline:

SignalBefore MitigationAfter Mitigation
Reviewed script-domain requestRecord actual browser resultRecord actual browser result and whether enforcement is observable
Synthetic fetch requestRecord actual browser resultRecord actual browser result; informational only
Mitigated-domain APIBaseline stateReviewed targets present; configuration evidence only
Terminal window
curl -s \
-H "Authorization: APIToken xXCSH_API_TOKENx" \
"xXCSH_API_URLx/api/shape/csd/namespaces/xXCSH_NAMESPACEx/detected_domains" \
| jq '{summary: {total: .domain_summary.totalDomains.count, mitigated: .domain_summary.mitigatedDomains.count, action_needed: .domain_summary.actionNeededCount.count}, domains: [.domains_list[]? | {domain, status, category}]}'
Terminal window
NOW=$(date +%s)
START=$(( NOW - 86400 ))
curl -s -X POST \
-H "Authorization: APIToken xXCSH_API_TOKENx" \
-H "Content-Type: application/json" \
-d "{\"startTime\": \"$START\", \"endTime\": \"$NOW\"}" \
"xXCSH_API_URLx/api/shape/csd/namespaces/xXCSH_NAMESPACEx/scripts" \
| jq '{total: (.scripts | length), scripts: [.scripts[]? | {script_name, risk_level}]}'

These API results may lag and are informational after configuration is applied. They do not override browser enforcement evidence.

CheckExpectedStatus
Phase 2 entry gateDET-3 PASS; DET-1/DET-4 may be PENDINGPASS / FAIL
HTTPS baselineBrowser evidence captured for the actual observed domain subsetPASS / FAIL
Mitigations appliedOne ledgered result per reviewed observed targetPASS / FAIL
Configuration confirmedReviewed targets present in collection/API dataPASS / FAIL
Browser enforcementObservable before/after change for at least one reviewed script domainPASS / PENDING / FAIL
HTTP behaviorUsed only to verify 301 redirectPASS / FAIL

Phase 3 complete. Proceed to Phase 4 — Teardown when you are ready to remove all deployment objects.