Skip to content

DNS Security

DNS Security provides DNS-level threat prevention for your managed fleet by integrating with third-party DNS filtering providers and enforcing allowlist/blocklist policies. The system ingests DNS security events from connected providers, categorizes threats, logs blocked queries, and gives you aggregated statistics to understand threat exposure across your organization.

Integrations connect Breeze to your existing DNS filtering infrastructure. Each integration is scoped to an organization and stores encrypted API credentials for the target provider. Once connected, Breeze periodically syncs DNS security events from the provider and stores them in the dns_security_events table, where they can be queried, filtered, and analyzed. Policies define domain-level allowlists and blocklists that are pushed back to the provider through a BullMQ sync pipeline.


  1. Connect a DNS filter provider by creating an integration with the provider’s API credentials. Breeze encrypts all secrets at rest.

  2. Breeze syncs events from the provider on a configurable interval. Each DNS query event is stored with its action (allowed, blocked, redirected), threat category, source device, and domain.

  3. Create policies to define allowlists and blocklists. Policies are linked to a specific integration and contain domain entries with optional reasons.

  4. Policies sync to the provider through BullMQ. When you add or remove domains, a sync job is enqueued to push changes upstream to the DNS provider.

  5. Analyze threat data using the stats, top-blocked, and events endpoints. Breeze automatically aggregates data for efficient querying over long time ranges.

ActionDescription
allowedDNS query was resolved normally
blockedDNS query was blocked by the provider’s filtering rules
redirectedDNS query was redirected to a different address (e.g., a block page or sinkhole)
CategoryDescription
malwareDomain associated with malware distribution or command-and-control infrastructure
phishingDomain used in phishing campaigns to harvest credentials or personal data
botnetDomain linked to botnet command-and-control networks
cryptominingDomain associated with unauthorized cryptocurrency mining
ransomwareDomain used in ransomware delivery or payment infrastructure
spamDomain associated with spam campaigns
adwareDomain serving intrusive advertising or adware payloads
adult_contentDomain hosting adult or explicit content
gamblingDomain hosting online gambling services
social_mediaSocial media platform (typically used for content filtering policies)
streamingStreaming media platform (typically used for bandwidth management policies)
unknownCategory not determined by the provider

Breeze supports the following DNS filter providers:

ProviderEnum ValueRequired Config
Cisco UmbrellaumbrellaapiKey, apiSecret, config.organizationId
Cloudflare GatewaycloudflareapiKey, config.accountId
DNSFilterdnsfilterapiKey
Pi-holepiholeapiKey, config.apiEndpoint
OpenDNSopendnsapiKey
Quad9quad9apiKey
Terminal window
POST /dns-security/integrations
Content-Type: application/json
Authorization: Bearer <token>
{
"orgId": "uuid",
"provider": "umbrella",
"name": "Contoso Umbrella",
"description": "Cisco Umbrella for Contoso HQ",
"apiKey": "your-api-key",
"apiSecret": "your-api-secret",
"config": {
"organizationId": "umbrella-org-id",
"syncInterval": 60,
"retentionDays": 90,
"categories": ["malware", "phishing", "botnet"]
},
"isActive": true
}
FieldTypeDescription
orgIdUUIDOrganization ID. Auto-resolved for org-scoped tokens
providerstringDNS provider: umbrella, cloudflare, dnsfilter, pihole, opendns, quad9
namestringHuman-readable name (max 200 chars)
descriptionstringOptional description (max 2,000 chars)
apiKeystringProvider API key (required, max 5,000 chars)
apiSecretstringProvider API secret (required for Cisco Umbrella)
config.organizationIdstringProvider’s organization ID (required for Cisco Umbrella)
config.accountIdstringProvider’s account ID (required for Cloudflare Gateway)
config.apiEndpointstringCustom API endpoint URL (required for Pi-hole)
config.syncIntervalintegerEvent sync interval in minutes (5-1440, default varies by provider)
config.retentionDaysintegerEvent retention period in days (1-365)
config.categoriesstring[]Threat categories to sync (max 100 entries)
config.blocklistIdstringProvider-specific blocklist identifier for policy sync
config.allowlistIdstringProvider-specific allowlist identifier for policy sync
isActivebooleanWhether the integration is active (default true)

To immediately sync events from a provider instead of waiting for the next scheduled interval:

Terminal window
POST /dns-security/integrations/:id/sync

The response includes a jobId for tracking the sync task in BullMQ.

Terminal window
DELETE /dns-security/integrations/:id

Policies define domain-level allowlists and blocklists that are enforced through the connected DNS provider. Each policy is tied to a specific integration and organization.

Terminal window
POST /dns-security/policies
Content-Type: application/json
Authorization: Bearer <token>
{
"orgId": "uuid",
"integrationId": "uuid",
"name": "Malware Blocklist",
"description": "Block known malicious domains",
"type": "blocklist",
"domains": [
{ "domain": "malware-example.com", "reason": "Known C2 domain" },
{ "domain": "phishing-site.net", "reason": "Reported phishing" }
],
"categories": ["malware", "phishing", "botnet"],
"isActive": true
}
FieldTypeRequiredDescription
orgIdUUIDNoOrganization ID. Auto-resolved for org-scoped tokens
integrationIdUUIDYesThe DNS filter integration this policy applies to
namestringYesHuman-readable name (max 200 chars)
descriptionstringNoOptional description (max 2,000 chars)
typestringYesblocklist or allowlist
domainsarrayNoDomain entries (max 500). Each with domain (required) and reason (optional)
categoriesstring[]NoThreat categories to include in this policy (max 50)
isActivebooleanNoWhether the policy is active (default true)

When a policy is created or updated, its syncStatus is set to pending. A BullMQ job is enqueued to push the changes to the DNS provider. The status progresses as follows:

StatusMeaning
pendingChanges queued, waiting for sync to the provider
syncedPolicy successfully pushed to the provider
errorSync failed. Check syncError for details

Add or remove domains from an existing policy without replacing the entire domain list:

Terminal window
PATCH /dns-security/policies/:id/domains
Content-Type: application/json
{
"add": [
{ "domain": "new-bad-domain.com", "reason": "Reported by threat intel feed" }
],
"remove": ["old-domain.net"]
}

At least one domain must be provided in add or remove. Domains are normalized to lowercase with trailing dots stripped. Duplicate domains are silently ignored. The response includes the updated domain count and lists of successfully added and removed domains.


DNS security events are the individual records of DNS queries processed by your DNS filter provider. Each event captures the queried domain, the action taken, the threat category (if applicable), and the source device.

Terminal window
GET /dns-security/events?start=2026-02-01T00:00:00Z&end=2026-02-15T00:00:00Z&action=blocked&category=malware&limit=50
ParameterTypeDescription
startISO 8601Start of time window (inclusive)
endISO 8601End of time window (inclusive)
actionstringFilter by action: allowed, blocked, redirected
categorystringFilter by threat category
domainstringPartial domain match (case-insensitive)
deviceIdUUIDFilter events for a specific device
integrationIdUUIDFilter events from a specific integration
limitintegerResults per page (1-500, default 100)
offsetintegerPagination offset (default 0)

Each event in the response includes:

FieldTypeDescription
idUUIDUnique event identifier
orgIdUUIDOrganization ID
integrationIdUUIDSource integration
deviceIdUUIDLinked device (nullable if device not matched)
deviceHostnamestringHostname of the linked device (from join)
timestampISO 8601When the DNS query occurred
domainstringQueried domain name
queryTypestringDNS query type (e.g., A, AAAA, CNAME)
actionstringallowed, blocked, or redirected
categorystringThreat category (nullable)
threatTypestringProvider-specific threat classification
sourceIpstringIP address of the querying device
sourceHostnamestringHostname of the querying device (from provider)
providerEventIdstringUnique event ID from the DNS provider
metadataobjectAdditional provider-specific data

Get aggregated DNS security statistics including total queries, blocked rates, top blocked domains, top categories, and top offending devices:

Terminal window
GET /dns-security/stats?start=2026-02-01T00:00:00Z&end=2026-02-15T00:00:00Z&topN=20
ParameterTypeDescription
startISO 8601Start of time window
endISO 8601End of time window
integrationIdUUIDFilter by integration
deviceIdUUIDFilter by device
actionstringFilter by action type
categorystringFilter by threat category
topNintegerNumber of top entries to return (1-100, default 10)

The response includes:

{
"summary": {
"totalQueries": 125000,
"blockedQueries": 3200,
"allowedQueries": 121500,
"redirectedQueries": 300,
"blockedRate": 2.56
},
"topBlockedDomains": [...],
"topCategories": [...],
"topDevices": [...],
"source": "aggregated"
}

Get a ranked list of the most frequently blocked domains:

Terminal window
GET /dns-security/top-blocked?start=2026-02-01T00:00:00Z&end=2026-02-15T00:00:00Z&limit=20

Each entry includes the domain, its threat category, the block count, and the number of distinct devices that attempted to reach it.


MethodPathDescription
GET/dns-security/integrationsList all integrations for the organization
POST/dns-security/integrationsCreate a new DNS filter integration (requires MFA, orgs:write)
DELETE/dns-security/integrations/:idDelete integration and all associated data (requires MFA, orgs:write)
POST/dns-security/integrations/:id/syncTrigger immediate event sync from the provider
MethodPathDescription
GET/dns-security/eventsList DNS security events with filtering and pagination
MethodPathDescription
GET/dns-security/statsAggregated statistics: totals, block rates, top domains/categories/devices
GET/dns-security/top-blockedRanked list of most frequently blocked domains
MethodPathDescription
GET/dns-security/policiesList all DNS policies for the organization
POST/dns-security/policiesCreate a new allowlist or blocklist policy (requires orgs:write)
PATCH/dns-security/policies/:id/domainsAdd or remove domains from a policy (requires orgs:write)

Integration created but events are not appearing. After creating an integration, an initial sync job is enqueued via BullMQ. If the sync scheduling fails, the creation response includes a warning field explaining the issue. Verify that Redis and BullMQ workers are running. Check the integration’s lastSyncStatus and lastSyncError fields via GET /dns-security/integrations to see if the sync completed or encountered an error. Also confirm that the API key and provider configuration are correct.

Policy sync stuck in pending status. Policy syncs are dispatched through BullMQ. If BullMQ is down or backlogged, the sync will remain in pending state. Restart the DNS sync worker and check the syncError field on the policy for specific error details. If the provider API returns an authentication error, verify the integration’s API credentials.

Stats endpoint returning unexpected results. For time windows longer than 7 days, statistics are sourced from the dns_event_aggregations table rather than raw events. Aggregations are computed periodically and may lag behind real-time data. The source field in the response (raw or aggregated) indicates which data source was used. For the most current data over short periods, use a time window of 7 days or less.

Time range query rejected with 400 error. The maximum query window for events and statistics is 90 days. If your start-to-end range exceeds this limit, narrow the time range. Also verify that both start and end are valid ISO 8601 timestamps and that start is before end.

Domains not blocking after adding to a blocklist policy. After adding domains to a policy, verify the syncStatus is synced (not pending or error). If the sync failed, check the syncError field. Domains are normalized to lowercase with trailing dots removed before storage and sync. If the provider requires a specific domain format, verify it matches the normalized form. Note that DNS caching at the client or resolver level may delay enforcement of new rules.

MFA required error when creating or deleting integrations. Creating and deleting DNS filter integrations require MFA verification. Ensure the authenticated user has completed MFA for the current session. The requireMfa() middleware returns a 403 if MFA has not been verified.