Skip to main content

Policy overrides

Policy overrides suppress false-positive detections from WAAP default rules for a defined scope of traffic. When a legitimate request is incorrectly flagged by a detector, a policy override prevents matching requests from being blocked and excludes them from attack counts, while the underlying rule continues to protect all other traffic outside that scope.

Overrides are created from the Events page and are listed under WAAP > Custom Rules > Policy overriding.

Policy override creation

Policy overrides are created from the Events page. When WAAP incorrectly flags a legitimate request, you can suppress that detection for a defined traffic scope without disabling the underlying rule. You can only create overrides for events triggered by WAAP default rules.

  1. 1

    Open the Events page

    In the CDB Technical Web Portal, navigate to WAAP > Events.

    WAAP Events page showing a list of SQL injection events with date, action, source, domain, request, and response columns
  2. 2

    Select Mark as False Positive

    On the event row you want to suppress, click the gear (⚙) icon and select Mark as False Positive.

    Gear icon dropdown on an event row showing options: Edit Rule, Create custom rule, Add IP to Deny list, Add IP to Allow list, Mark as False Positive
  3. 3

    Fill in the override form

    The Mark as False Positive page opens with the Policy Overriding rule type pre-selected. The Define rule section is auto-populated with the conditions from the triggering event: the domain, source IP, country, HTTP method, URL, and user agent.

    Mark as False Positive form showing Rule name field, Policy Overriding rule type, and auto-filled conditions including IP, Country, HTTP method, URL, User Agent, and an Ignore detector action

    In the Rule name field, enter a display name for the override. An optional Description field is available for notes.

  4. 4

    Adjust the conditions (optional)

    Review the auto-populated conditions. Remove any that are too specific or not relevant to the false positive. To add a condition, click + And and select a condition type.

    ConditionDescription
    IPSingle IPv4 or IPv6 address
    IP rangeAddresses between a lower and upper bound
    CountryOne or more countries identified by ISO 3166-1 alpha-2 code
    OrganizationOriginating organization, determined by a WHOIS lookup of the requesting IP
    HeaderHTTP request header name and value
    Header existsWhether a named HTTP request header is present
    User AgentUser-agent string (Exact or Contains match)
    URLRequest URL path or query string (Exact, Contains, or Regex match)
    HTTP methodRequest method, such as GET or POST
    JA3 fingerprintTLS client fingerprint
    JA4 fingerprintExtended TLS client fingerprint
    Condition type dropdown showing all available options: IP, IP range, Country, Organization, Header, Header exists, User Agent, URL, HTTP method, JA3, JA4

    The Then action is pre-set to Ignore detector, which suppresses the specific detector that triggered the event. Select Ignore rule instead to suppress the entire default rule.

  5. 5

    Save the override

    Click Save. The override becomes active immediately and appears in WAAP > Custom Rules > Policy overriding.

Effect of a policy override

When a policy override matches a request, the request is not blocked and is not counted as an attack. The effect on the underlying default rule depends on the action selected when the override was created:

  • Ignore detector: Only the specific detector is suppressed for matching traffic. Other detectors in the same rule remain active and continue to evaluate requests within the override scope.
  • Ignore rule: The entire default rule is suppressed for matching traffic. Its detectors do not remain active for requests that match the override scope.

Outside the override scope, the underlying rule and all its detectors continue to protect all other traffic.

If the linked detector or rule is deleted, disabled, or otherwise becomes invalid, the override becomes stale and stops suppressing traffic. A stale override has no effect until its target is updated to a valid target.

Policy override management

All policy overrides for a domain are listed on WAAP > Custom Rules > Policy overriding. Each entry shows the override name, action, targets, conditions, and enabled status.

Policy overriding tab in WAAP Custom Rules showing the list table with Name, Action, Targets, Conditions, and Status columns

To edit an override, click its name or use the row actions menu and select Edit. To disable an override without deleting it, toggle the Status switch. To remove an override permanently, select Delete from the row actions menu.

Policy overrides created by CDB Support on behalf of a customer are displayed with a user ID instead of a name. All override creation and modification actions are recorded in the audit log with the user identity, timestamp, and override scope.

The Policy Overrides endpoints create, retrieve, update, and delete domain-level suppressions for WAAP default rule detectors or rules.

An API token is required, along with the ID of a WAAP-protected domain. Install the Python or Go SDK to run the SDK examples.

export GCORE_API_KEY="{YOUR_API_KEY}"
export WAAP_DOMAIN_ID="{YOUR_DOMAIN_ID}"

List policy overrides

Retrieve all policy overrides configured for a domain, including their current enabled state, targets, and conditions.

import gcore
import os

client = gcore.CDB()
domain_id = int(os.environ["WAAP_DOMAIN_ID"])

overrides = client.waap.domains.default_rule_overrides.list(domain_id)
for override in overrides:
    status = "enabled" if override.enabled else "disabled"
    stale = " [stale]" if override.stale else ""
    print(f"{override.id}: {override.name} [{status}]{stale}")
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/waap"
)

func main() {
    client := gcore.NewClient()
    domainID, err := strconv.ParseInt(os.Getenv("WAAP_DOMAIN_ID"), 10, 64)
    if err != nil {
        panic("WAAP_DOMAIN_ID must be a valid integer: " + err.Error())
    }

    overrides, err := client.Waap.Domains.DefaultRuleOverrides.List(
        context.Background(), domainID,
        waap.DomainDefaultRuleOverrideListParams{},
    )
    if err != nil {
        panic(err.Error())
    }
    for _, o := range overrides.Results {
        status := "disabled"
        if o.Enabled {
            status = "enabled"
        }
        stale := ""
        if o.Stale {
            stale = " [stale]"
        }
        fmt.Printf("%d: %s [%s]%s\n", o.ID, o.Name, status, stale)
    }
}
curl -X GET "https://api.cdb-staging.cdn.orange.com/waap/v1/domains/${WAAP_DOMAIN_ID}/default-rule-overrides" \
  -H "Authorization: apikey ${GCORE_API_KEY}"

The API returns a paginated list of overrides:

{
  "limit": 100,
  "offset": 0,
  "count": 1,
  "results": [
    {
      "id": 101,
      "domain_id": 14043,
      "name": "Allow monitoring tool",
      "target_type": "detector",
      "targets": [
        {
          "id": 1,
          "ref": "sqli",
          "snapshot": { "name": "SQL injection" }
        }
      ],
      "conditions": [
        { "organization": { "organization": "UptimeRobot s.r.o" } }
      ],
      "enabled": true,
      "stale": false,
      "created_at": "2026-09-01T10:00:00Z",
      "updated_at": "2026-09-01T10:00:00Z"
    }
  ]
}

Available override targets

When target_type is detector, retrieve the list of WAAP detectors that can be used as policy override targets. Each result includes the detector's id and name, which are the values to pass in target_ids when creating an override.

Each result also includes an optional policy object. When target_type is rule, pass the numeric policy.id value in target_ids instead. This targets the entire parent rule rather than an individual detector.

import gcore
import os

client = gcore.CDB()
domain_id = int(os.environ["WAAP_DOMAIN_ID"])

targets = client.waap.domains.default_rule_overrides.list_owasp_targets(domain_id)
for t in targets:
    policy_info = f"  (rule target: policy.id={t.policy.id})" if t.policy else ""
    print(f"detector id={t.id}: {t.name}{policy_info}")
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
)

func main() {
    client := gcore.NewClient()
    domainID, err := strconv.ParseInt(os.Getenv("WAAP_DOMAIN_ID"), 10, 64)
    if err != nil {
        panic("WAAP_DOMAIN_ID must be a valid integer: " + err.Error())
    }

    targets, err := client.Waap.Domains.DefaultRuleOverrides.ListOWASPTargets(
        context.Background(), domainID,
    )
    if err != nil {
        panic(err.Error())
    }
    for _, t := range targets.Results {
        policyInfo := ""
        if t.Policy != nil {
            policyInfo = fmt.Sprintf("  (rule target: policy.id=%d)", t.Policy.ID)
        }
        fmt.Printf("detector id=%d: %s%s\n", t.ID, t.Name, policyInfo)
    }
}
curl -X GET "https://api.cdb-staging.cdn.orange.com/waap/v1/domains/${WAAP_DOMAIN_ID}/policy-override-targets/owasp-top-threats" \
  -H "Authorization: apikey ${GCORE_API_KEY}"

Create a policy override

Create a policy override by specifying the target to suppress, the conditions under which the suppression applies, and whether the override is immediately active.

The following fields are accepted in the request body:

FieldRequiredDescription
nameYesDisplay name, up to 100 characters
target_typeYesdetector or rule — whether target_ids refers to detector IDs or rule IDs
target_idsYesArray of detector or rule IDs to suppress. Retrieve valid IDs using the Available override targets section in this article
enabledYestrue to activate the override immediately; false to create it disabled
descriptionNoExplanatory note, up to 1,000 characters
conditionsNoUp to five conditions; all must match. Omit to suppress the target on all traffic for the domain
request_idNoID of the event request that prompted this override, in the format {32-char hex}-{6 digits}. Associates the override with the source event for audit purposes; has no effect on override behavior

Each object in the conditions array contains exactly one condition type. The table below lists all supported types and their required fields:

Condition typeJSON keyRequired fieldsNotes
IP addressipip_addressSingle IPv4 or IPv6 address
IP rangeip_rangelower_bound, upper_boundBoth bounds are IPv4 or IPv6
Countrycountrycountry_codeOne ISO 3166-1 alpha-2 code per condition, such as "CN"
OrganizationorganizationorganizationOrganization name from WHOIS
Headerheaderheader, value, match_typematch_type: Exact or Contains (default)
Header existsheader_existsheaderMatches when the named header is present
User-Agentuser_agentuser_agent, match_typematch_type: Exact or Contains (default)
URLurlurl, match_typematch_type: Exact, Contains (default), or Regex
HTTP methodhttp_methodhttp_methodRequest method, such as GET or POST
JA3 fingerprintja3ja3_fingerprintsArray of up to 10 JA3 TLS client fingerprint strings
JA4 fingerprintja4ja4_fingerprintsArray of up to 10 JA4 TLS client fingerprint strings

Every condition type supports an optional negation boolean (default false). Set "negation": true to invert the match — the override applies when the condition does NOT match.

The example below suppresses the SQL injection detector for requests originating from a monitoring organization:

import gcore
import os

client = gcore.CDB()
domain_id = int(os.environ["WAAP_DOMAIN_ID"])
detector_id = int(os.environ["DETECTOR_ID"])

override = client.waap.domains.default_rule_overrides.create(
    domain_id,
    name="Allow monitoring tool",
    target_type="detector",
    target_ids=[detector_id],
    enabled=True,
    conditions=[
        {"organization": {"organization": "UptimeRobot s.r.o"}}
    ],
)
print(f"Created override {override.id}: {override.name}")
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/waap"
)

func main() {
    client := gcore.NewClient()
    domainID, err := strconv.ParseInt(os.Getenv("WAAP_DOMAIN_ID"), 10, 64)
    if err != nil {
        panic("WAAP_DOMAIN_ID must be a valid integer: " + err.Error())
    }
    detectorID, err := strconv.ParseInt(os.Getenv("DETECTOR_ID"), 10, 64)
    if err != nil {
        panic("DETECTOR_ID must be a valid integer: " + err.Error())
    }

    override, err := client.Waap.Domains.DefaultRuleOverrides.Create(
        context.Background(), domainID,
        waap.DomainDefaultRuleOverrideCreateParams{
            Name:       "Allow monitoring tool",
            TargetType: waap.PolicyOverrideTargetTypeDetector,
            TargetIDs:  []int64{detectorID},
            Enabled:    true,
            Conditions: []waap.PolicyOverrideCondition{
                {Organization: &waap.OrganizationCondition{Organization: "UptimeRobot s.r.o"}},
            },
        },
    )
    if err != nil {
        panic(err.Error())
    }
    fmt.Printf("Created override %d: %s\n", override.ID, override.Name)
}
export DETECTOR_ID="{DETECTOR_ID}"

curl -X POST "https://api.cdb-staging.cdn.orange.com/waap/v1/domains/${WAAP_DOMAIN_ID}/default-rule-overrides" \
  -H "Authorization: apikey ${GCORE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Allow monitoring tool",
    "target_type": "detector",
    "target_ids": ['"${DETECTOR_ID}"'],
    "enabled": true,
    "conditions": [
      { "organization": { "organization": "UptimeRobot s.r.o" } }
    ]
  }'

The API returns 201 with the created override:

{
  "id": 101,
  "domain_id": 14043,
  "name": "Allow monitoring tool",
  "target_type": "detector",
  "targets": [
    {
      "id": 1,
      "ref": "sqli",
      "snapshot": { "name": "SQL injection" }
    }
  ],
  "conditions": [
    { "organization": { "organization": "UptimeRobot s.r.o" } }
  ],
  "enabled": true,
  "stale": false,
  "created_at": "2026-09-17T10:00:00Z",
  "updated_at": "2026-09-17T10:00:00Z"
}

Update a policy override

Update a policy override using a partial request — only the fields included in the request body are changed. Use this to rename an override, swap its target detector or rule, add or remove conditions, or enable or disable it without deleting it.

import gcore
import os

client = gcore.CDB()
domain_id = int(os.environ["WAAP_DOMAIN_ID"])
override_id = int(os.environ["OVERRIDE_ID"])

updated = client.waap.domains.default_rule_overrides.update(
    domain_id,
    override_id,
    enabled=False,
)
print(f"Override {updated.id} is now {'enabled' if updated.enabled else 'disabled'}")
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
    "github.com/G-Core/gcore-go/waap"
)

func main() {
    client := gcore.NewClient()
    domainID, err := strconv.ParseInt(os.Getenv("WAAP_DOMAIN_ID"), 10, 64)
    if err != nil {
        panic("WAAP_DOMAIN_ID must be a valid integer: " + err.Error())
    }
    overrideID, err := strconv.ParseInt(os.Getenv("OVERRIDE_ID"), 10, 64)
    if err != nil {
        panic("OVERRIDE_ID must be a valid integer: " + err.Error())
    }

    enabled := false
    updated, err := client.Waap.Domains.DefaultRuleOverrides.Update(
        context.Background(), domainID, overrideID,
        waap.DomainDefaultRuleOverrideUpdateParams{
            Enabled: &enabled,
        },
    )
    if err != nil {
        panic(err.Error())
    }
    status := "disabled"
    if updated.Enabled {
        status = "enabled"
    }
    fmt.Printf("Override %d is now %s\n", updated.ID, status)
}
export OVERRIDE_ID="{OVERRIDE_ID}"

curl -X PATCH "https://api.cdb-staging.cdn.orange.com/waap/v1/domains/${WAAP_DOMAIN_ID}/default-rule-overrides/${OVERRIDE_ID}" \
  -H "Authorization: apikey ${GCORE_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"enabled": false}'

The API returns 200 with the full updated override object.

Delete a policy override

Remove a policy override permanently. The linked detector or rule continues to apply to all traffic after deletion.

import gcore
import os

client = gcore.CDB()
domain_id = int(os.environ["WAAP_DOMAIN_ID"])
override_id = int(os.environ["OVERRIDE_ID"])

client.waap.domains.default_rule_overrides.delete(domain_id, override_id)
print(f"Override {override_id} deleted")
package main

import (
    "context"
    "fmt"
    "os"
    "strconv"

    gcore "github.com/G-Core/gcore-go"
)

func main() {
    client := gcore.NewClient()
    domainID, err := strconv.ParseInt(os.Getenv("WAAP_DOMAIN_ID"), 10, 64)
    if err != nil {
        panic("WAAP_DOMAIN_ID must be a valid integer: " + err.Error())
    }
    overrideID, err := strconv.ParseInt(os.Getenv("OVERRIDE_ID"), 10, 64)
    if err != nil {
        panic("OVERRIDE_ID must be a valid integer: " + err.Error())
    }

    err = client.Waap.Domains.DefaultRuleOverrides.Delete(
        context.Background(), domainID, overrideID,
    )
    if err != nil {
        panic(err.Error())
    }
    fmt.Printf("Override %d deleted\n", overrideID)
}
export OVERRIDE_ID="{OVERRIDE_ID}"

curl -X DELETE "https://api.cdb-staging.cdn.orange.com/waap/v1/domains/${WAAP_DOMAIN_ID}/default-rule-overrides/${OVERRIDE_ID}" \
  -H "Authorization: apikey ${GCORE_API_KEY}"

The API returns 204 with an empty body on success.