0x55aa
Back to Blog

Canary Tokens: The Tripwires Your Attackers Will Step On 🪤

|
6 min read

Canary Tokens: The Tripwires Your Attackers Will Step On 🪤

There's a class of defensive security tooling that costs almost nothing, requires zero agents, doesn't create alert fatigue, and fires exactly when someone is snooping around your infrastructure.

I'm talking about canary tokens. And most engineering teams aren't using them.

Let me fix that.

What Is a Canary Token?

A canary token is a fake artifact — a credential, URL, file, database entry, or environment variable — that has no legitimate business purpose. Nobody on your team should ever touch it. If it gets accessed, you know something has gone wrong.

Think of it as a silent alarm wired to a doorknob that should never be opened.

The original concept comes from network security research, but the practical application is beautifully simple: you leave bait, and attackers walk into it. They don't know the credential is fake. They don't know the URL phones home. They just try to use it, and you get a Slack notification at 2 AM telling you someone is inside your house.

This is incident detection, not incident prevention — and that distinction matters a lot in real defensive engineering.

Why Most Teams Skip This

Detection engineering gets deprioritized because it doesn't feel like it's stopping anything. Prevention tooling (WAFs, input validation, dependency scanning) has a clear story: bad thing came in, we blocked it. Detection feels like "we only notice when we've already lost."

That framing is wrong.

You will be breached eventually. The question is whether you find out during the breach or three months later during a compliance audit when someone notices your prod S3 bucket has been slowly exfiltrating to an IP in Ashburn. Canary tokens collapse that discovery window dramatically.

At Cubet, we started planting canary tokens after an internal red team exercise revealed we had no reliable way to detect lateral movement post-compromise. Blocking was decent. Visibility was terrible. Canaries changed that.

Types of Canary Tokens Worth Deploying

Fake AWS credentials are the classic. An IAM user with no permissions but real-looking keys. Leave them in a .env.example, a commented-out config, or a developer wiki page. If anything calls sts:GetCallerIdentity with those keys — you have a leak.

Honeypot URLs in your API responses. A route that returns a 200 with a payload containing a URL that no legitimate client should ever call. If your logs show that URL getting hit, something parsed your API response and followed it.

Canary files in backups and S3 buckets. A _canary_access_check.txt in the root of a sensitive bucket. If that object gets downloaded, either a developer got very curious or your bucket is being enumerated.

Fake database records. A user row with a canary email address ([email protected]) that should never receive email. Wire up an alert for any outbound email to that address.

DNS canary tokens. A hostname embedded in a document or config file. If that hostname ever resolves, someone read the file and made a network request from the data in it.

The Mechanics: A Working Example

Here's a minimal canary credential setup using AWS and a Lambda function to handle alerts:

# lambda/canary_alert.py
import json
import os
import boto3
import urllib.request

SNS_TOPIC_ARN = os.environ["SNS_TOPIC_ARN"]

def handler(event, context):
    sns = boto3.client("sns")
    detail = event.get("detail", {})
    
    source_ip = detail.get("sourceIPAddress", "unknown")
    user_agent = detail.get("userAgent", "unknown")
    event_name = detail.get("eventName", "unknown")
    
    message = (
        f"CANARY TRIGGERED\n"
        f"Event: {event_name}\n"
        f"Source IP: {source_ip}\n"
        f"User-Agent: {user_agent}\n"
        f"Full detail: {json.dumps(detail, indent=2)}"
    )
    
    sns.publish(
        TopicArn=SNS_TOPIC_ARN,
        Subject="[SECURITY] Canary credential accessed",
        Message=message,
    )

Wire this to a CloudTrail EventBridge rule that triggers on any API call from your canary IAM user's ARN. Zero permissions means every call fails, but every call is logged and triggers your alert.

# terraform/canary.tf
resource "aws_cloudwatch_event_rule" "canary_trigger" {
  name        = "canary-credential-used"
  description = "Fires when the canary IAM user makes any API call"

  event_pattern = jsonencode({
    source      = ["aws.sts", "aws.s3", "aws.iam"]
    detail-type = ["AWS API Call via CloudTrail"]
    detail = {
      userIdentity = {
        arn = [aws_iam_user.canary.arn]
      }
    }
  })
}

resource "aws_cloudwatch_event_target" "canary_lambda" {
  rule = aws_cloudwatch_event_rule.canary_trigger.name
  arn  = aws_lambda_function.canary_alert.arn
}

This pattern is low-noise by design. The rule only fires for one specific IAM ARN. No tuning required, no threshold to calibrate. Either it fires or it doesn't.

Seeding Canary Tokens Strategically

The placement strategy is as important as the token itself. You want tokens where attackers actually look:

  • .env files and their history in git (use git log --all -S "CANARY" to make sure you haven't accidentally committed them)
  • Developer wikis and runbooks — the first place a lateral-mover looks for credentials
  • CI/CD config files and secret stores
  • Backup archives (especially the ones that "probably don't contain anything sensitive")
  • Internal API documentation that describes auth schemes

One subtle trick: plant tokens in likely exfil paths. If an attacker gets code execution, they'll often grab /proc/self/environ or scan common config paths. Put a canary value in APP_INTERNAL_WEBHOOK pointing to a URL you control. If that URL gets called with a weird user-agent, you know exactly how they got there.

The Alert Has to Go Somewhere Useful

The fastest way to kill the value of canary tokens is to alert to a channel nobody reads. The Slack #security-alerts channel that gets muted after the first false positive from your staging environment is not useful.

Canary alerts should:

  1. Go to a dedicated channel with a zero-noise guarantee (since canaries never fire legitimately)
  2. Page on-call immediately — a canary firing is a P1, period
  3. Include enough context to start triage (source IP, user-agent, timestamp, which token was accessed)

We route canary alerts straight to PagerDuty at Cubet. Every other security alert has some escalation threshold. Canaries don't. If the canary fires, someone picks up the phone.

What Canary Tokens Are Not

They are not a substitute for proper detection engineering. They don't catch everything — an attacker who identifies and avoids canary-looking artifacts won't trip them. They're a layer, not a replacement for proper SIEM work, network monitoring, or endpoint detection.

They also won't tell you how the attacker got in. They tell you that someone is in. You still need your logging, your audit trails, your forensic artifacts to answer the "how." Canaries buy you time and detection, not attribution.

Start With One Token Today

The barrier to entry here is genuinely low. Pick one surface — maybe that wiki page with your old staging credentials, or the .env.example in your most-forked internal repo — and plant a canary AWS key pair that alerts on any use.

You probably won't get an alert this week. Or this month. But when you do, you'll know about it in minutes instead of months.

That's the deal. A few hours of setup, and your attacker's first mistake becomes your earliest warning.


If you've already deployed canary tokens or you're working on detection engineering and want to compare notes, find me on X (Twitter) or LinkedIn. I'm always curious what creative placements people come up with — some of the best ones I've heard involve fake SSH keys hidden in employee offboarding checklists.

Plant your canaries. Then wait.

Thanks for reading!

Back to all posts