DNS Canary Tokens¶
DNS canary tokens provide early warning when a payload is submitted to a sandbox, analyzed by a reverse engineer, or detonated in an environment outside the target network. Each generated payload can embed a unique DNS canary domain -- if the domain is resolved from an unexpected source IP, Stentor alerts all connected operators in real time via WebSocket.
The canary system has two sides: the operator API for registering canaries and viewing trip events, and the relay-accessible endpoint that the DNS C2 server calls when it observes a canary domain resolution.
How It Works¶
sequenceDiagram
participant Payload as Payload (Implant)
participant DNS as Relay DNS Server
participant API as Stentor API
participant DB as PostgreSQL
participant WS as Operator WebSocket
Note over Payload,WS: Payload Generation
API->>DB: Register canary (domain, payload_id, listener_id)
API->>Payload: Embed canary domain in payload
Note over Payload,WS: Canary Trip (sandbox/analyst)
Payload->>DNS: DNS query for canary domain
DNS->>API: POST /c2/canary/trip {domain, source_ip}
API->>DB: Look up canary by domain
API->>DB: Record trip event
API->>WS: Broadcast SIEM alert to all operators
API-->>DNS: {trip_id, status: "tripped"} When a payload is generated, Stentor registers a canary domain and associates it with the payload and listener IDs. The canary domain is embedded in the payload binary. On first execution, the implant resolves the canary domain via DNS. If the relay's DNS server receives this query, it forwards the domain and source IP to the Stentor API, which records the trip and broadcasts an alert.
Detection Logic
The canary trip itself does not determine whether the source IP belongs to the target network -- that assessment is left to the operator. The alert includes the source IP, payload ID, and listener ID so the operator can cross-reference against known target infrastructure.
Register a Canary¶
POST /api/v1/canary/register¶
Register a DNS canary domain. Typically called during payload generation to associate a unique domain with the payload. If the domain already exists, the payload_id is updated (upsert behavior via ON CONFLICT).
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
domain | string | Yes | The canary domain (e.g., a1b2c3d4.canary.example.com) |
payload_id | string | No | UUID of the associated payload |
listener_id | string | No | UUID of the associated listener |
curl -s -X POST https://stentor.app/api/v1/canary/register \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"domain": "f47ac10b.canary.ops.local",
"payload_id": "PAYLOAD_UUID",
"listener_id": "LISTENER_UUID"
}'
Response (201 Created):
Canary Trip Events¶
POST /api/v1/canary/trip (Authenticated)¶
Record a canary trip event. This endpoint is available on the authenticated API for manual trip recording or testing.
POST /api/v1/c2/canary/trip (Relay-accessible, no auth)¶
The relay's DNS server calls this endpoint when it observes a DNS query for a registered canary domain. This endpoint is on the C2 route group and does not require JWT authentication -- it is accessible from the relay's internal network.
Request body:
| Field | Type | Required | Description |
|---|---|---|---|
domain | string | Yes | The canary domain that was resolved |
source_ip | string | Yes | IP address that made the DNS query |
curl -s -X POST https://stentor.app/api/v1/canary/trip \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"domain": "f47ac10b.canary.ops.local",
"source_ip": "198.51.100.42"
}'
Response (200 OK):
{
"trip_id": "a1b2c3d4-...",
"canary_id": "c3d4e5f6-...",
"domain": "f47ac10b.canary.ops.local",
"source_ip": "198.51.100.42",
"status": "tripped"
}
WebSocket Alert¶
When a canary trips, a SIEM alert is broadcast to all connected operator WebSocket sessions. The alert payload contains:
| Field | Type | Description |
|---|---|---|
type | string | Always canary_trip |
domain | string | The tripped canary domain |
source_ip | string | DNS query source IP |
canary_id | string | UUID of the canary token |
payload_id | string | Associated payload UUID (or unknown) |
listener_id | string | Associated listener UUID (or unknown) |
tripped_at | string | ISO 8601 timestamp |
message | string | Human-readable alert text |
Unknown Domain
If a DNS query arrives for a domain that is not registered as a canary, the API returns 404 Not Found and logs a warning. This can happen if the canary was deleted or if the domain belongs to a different system.
List Canaries¶
GET /api/v1/canary/list¶
List all registered canary tokens with their trip status. Canaries are returned in reverse chronological order (newest first).
Response fields:
| Field | Type | Description |
|---|---|---|
id | string | Canary token UUID |
domain | string | Registered canary domain |
payload_id | string | Associated payload UUID (empty if not set) |
listener_id | string | Associated listener UUID (empty if not set) |
created_at | string | ISO 8601 registration timestamp |
tripped | bool | Whether the canary has been tripped at least once |
trip_count | int | Total number of trip events |
Example response:
[
{
"id": "c3d4e5f6-...",
"domain": "f47ac10b.canary.ops.local",
"payload_id": "PAYLOAD_UUID",
"listener_id": "LISTENER_UUID",
"created_at": "2026-02-20T14:30:00Z",
"tripped": true,
"trip_count": 3
}
]
List Trip Events¶
GET /api/v1/canary/trips¶
List all canary trip events across all canaries. Events are returned in reverse chronological order (most recent first).
Response fields:
| Field | Type | Description |
|---|---|---|
id | string | Trip event UUID |
canary_id | string | UUID of the tripped canary |
domain | string | The canary domain that was resolved |
source_ip | string | IP address that made the DNS query |
tripped_at | string | ISO 8601 timestamp of the trip |
Example response:
[
{
"id": "a1b2c3d4-...",
"canary_id": "c3d4e5f6-...",
"domain": "f47ac10b.canary.ops.local",
"source_ip": "198.51.100.42",
"tripped_at": "2026-02-21T09:15:30Z"
}
]
OPSEC Value¶
DNS canaries address a critical operational concern: detecting when your payload has been captured and analyzed outside the target environment.
| Scenario | Canary Behavior |
|---|---|
| Payload detonated on target network | DNS query from expected IP range -- no alert (or informational only) |
| Payload submitted to VirusTotal | DNS query from sandbox IP -- canary trips, operator alerted |
| Payload analyzed by incident responder | DNS query from analyst workstation -- canary trips, operator alerted |
| Payload forwarded to SOC/DFIR team | DNS query from forensics lab -- canary trips, operator alerted |
Burned Payload Response
When a canary trips from an unexpected source, consider the following response actions:
- Verify the source IP against known target infrastructure. False positives can occur if the target organization uses cloud DNS resolvers or VPN exit nodes.
- Rotate the listener if the canary is associated with a listener that may now be known to the defender.
- Kill the beacon if the canary is associated with a specific implant that may be under analysis.
- Generate a new payload with a fresh canary domain for continued operations.
Relay DNS Integration
The relay's DNS C2 server automatically checks incoming DNS queries against registered canary domains. When a match is found, it calls the internal POST /api/v1/c2/canary/trip endpoint (no JWT required). This means canary detection works passively -- no additional configuration is needed beyond registering the canary during payload generation.