Skip to content

vortacity/anglerfish

Anglerfish

Anglerfish

CI

Anglerfish is a CLI for security teams in Microsoft 365 shops. It plants Outlook canary messages with Microsoft Graph, then detects mailbox access by matching MailItemsAccessed events from the Microsoft 365 Unified Audit Log back to local deployment records — using the tenant's own audit telemetry as the detection plane. No callback receiver, DNS zone, webhook, or external SIEM is required to identify access; correlation runs against records you keep on disk.

It supports hidden-folder draft canaries, inbox send canaries, local health checks for draft deployments, and audit-log monitoring without callback infrastructure.

Note

Detection is delayed, not real-time. Microsoft Unified Audit Log records typically appear 60–90 minutes after the access event, sometimes longer. Anglerfish surfaces the event when it lands; it does not stream from Exchange directly. See the threat model for details.

Demo

Non-interactive demo deployment (anglerfish --demo --non-interactive ...):

Non-interactive demo deployment

Alert detection (anglerfish monitor):

Monitor alert

Example records

Deploying a canary writes a local deployment record; when the canary is read, a MailItemsAccessed event lands in the Unified Audit Log and Anglerfish correlates it back to that record. These sanitized artifacts show the shape of the evidence without exposing tenant data:

Documentation

Warning

This tool is for authorized security testing and defensive canary deployments only. Mail.ReadWrite application permission grants tenant-wide mailbox write access by default. Production use requires formal approval and explicit scoping decisions.

How It Works

1. Deploy     anglerfish -> Microsoft Graph -> Outlook draft or inbox canary
2. Access     mailbox activity -> Microsoft 365 Unified Audit Log -> MailItemsAccessed
3. Detect     anglerfish monitor -> matches MailItemsAccessed to deployment record -> alert

Anglerfish is intentionally narrow in this release: Outlook only, application authentication only, and one primary workflow built around deploy, list, verify, cleanup, and monitor. Draft deployments add a per-canary ID to the hidden folder name and require an internetMessageId correlation key in the deployment record.

Positioning

Tool Open-source Self-hosted Third-party data plane Tenant-native telemetry
Anglerfish yes (MIT) yes no yes (UAL)
Managed Canarytokens / Canarytools no no (SaaS) yes (Thinkst) n/a (callback pattern)
Self-hosted Canarytokens yes yes operator-controlled n/a (callback pattern)
Defender for Office 365 anomalous mailbox detection no n/a (Microsoft-hosted) n/a yes (UAL)
DIY Sentinel KQL on MailItemsAccessed yes (operator-built content) no (Microsoft-hosted SIEM) no yes (UAL)

Where Anglerfish fits. Anglerfish is not a Canarytokens replacement. It is a narrower, M365-native option for teams that want canary deploys plus native UAL correlation without standing up a separate canary platform, configuring webhook receivers, or maintaining their own KQL hunt. If you already run Sentinel and write your own queries, the Sentinel KQL snippet gives you the same correlation primitive without the CLI; if you want a single self-contained CLI that handles deploy, list, verify, cleanup, and detection, Anglerfish covers that path.

Related work

Anglerfish sits next to several existing approaches; each does something Anglerfish does not.

  • Thinkst Canary / Canarytokens — the most mature canary platform; commercial managed appliance plus an open-source self-hosted token server. Detection is callback-based (DNS, HTTP, SMTP). Anglerfish is M365-only, has no token server, and does not use callback transport — it correlates against the tenant's existing audit log instead.
  • DIY Sentinel KQL hunts on MailItemsAccessed — same audit primitive, surfaced through Microsoft Sentinel queries (the Microsoft Sentinel community repo is the canonical example library). Anglerfish adds the deploy side and gives operators a non-SIEM path; the bundled docs/sentinel-kql.md snippet is provided so Sentinel users can validate Anglerfish's correlation against their own queries.
  • Defender for Office 365 anomalous-mailbox detection — Microsoft-hosted, statistical, and not deterministic per-canary. Anglerfish is deterministic: a deployed canary plus a MailItemsAccessed event with the canary's internetMessageId is the alert.
  • Mailoney / open-source mail honeypots — different threat model (inbound network/SMTP); not M365-native and does not interact with Exchange Online or the Unified Audit Log.

Supported Surface

Command Purpose
anglerfish Interactive Outlook canary deploy
anglerfish list List deployment records
anglerfish verify Check active draft-mode Outlook canaries
anglerfish cleanup <record> Remove a deployed Outlook canary
anglerfish demo-access <record> Read a deployed canary through Graph to generate authorized audit evidence
anglerfish monitor Poll for Outlook access alerts

Notes:

  • draft is the default and best-supported operator path.
  • send is supported for deploy, cleanup, list, and monitor.
  • verify is draft-only because send-mode records do not keep a hidden folder to inspect.

Quickstart

git clone https://github.com/vortacity/anglerfish.git
cd anglerfish
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -e .

scripts/quickstart.sh automates the venv and install steps above.

Anglerfish reads credentials from the process environment. It does not auto-load .env, so export values directly or source a file yourself before running commands.

export ANGLERFISH_TENANT_ID="..."
export ANGLERFISH_CLIENT_ID="..."
export ANGLERFISH_APP_CREDENTIAL_MODE="secret"
export ANGLERFISH_CLIENT_SECRET="..."

Dry-run the default Outlook workflow:

anglerfish --dry-run --non-interactive \
  --canary-type outlook \
  --template "Fake Password Reset" \
  --target adele.vance@contoso.com \
  --delivery-mode draft

Deploy a real canary and write a local record:

export RECORD="$HOME/.anglerfish/records/adele-password-reset.json"

anglerfish --non-interactive \
  --canary-type outlook \
  --template "Fake Password Reset" \
  --target adele.vance@contoso.com \
  --delivery-mode draft \
  --output-json "$RECORD"

Trigger authorized access for a demo tenant, then poll after UAL ingestion:

anglerfish demo-access --non-interactive "$RECORD"
anglerfish monitor --once --records-dir "$HOME/.anglerfish/records"

Try the product offline:

anglerfish --demo
anglerfish monitor --demo --count 2

For a complete Entra app registration walkthrough, see Demo tenant setup guide.

Authentication

Application authentication is the only supported auth model in this release.

Credential selection:

  • --credential-mode secret or ANGLERFISH_APP_CREDENTIAL_MODE=secret
  • --credential-mode certificate or ANGLERFISH_APP_CREDENTIAL_MODE=certificate
  • auto is also accepted and chooses whichever single credential type is configured

Secret mode:

export ANGLERFISH_TENANT_ID="<tenant-guid>"
export ANGLERFISH_CLIENT_ID="<app-client-id>"
export ANGLERFISH_APP_CREDENTIAL_MODE="secret"
export ANGLERFISH_CLIENT_SECRET="<client-secret>"

Certificate mode:

export ANGLERFISH_TENANT_ID="<tenant-guid>"
export ANGLERFISH_CLIENT_ID="<app-client-id>"
export ANGLERFISH_APP_CREDENTIAL_MODE="certificate"
export ANGLERFISH_CLIENT_CERT_PFX_PATH="/path/to/app-cert.pfx"
export ANGLERFISH_CLIENT_CERT_PASSPHRASE="<optional-passphrase>"

PEM certificate configuration is also supported. See .env.example for the full variable set.

Required Permissions

Workflow Permission API
Draft deploy, cleanup, verify Mail.ReadWrite Microsoft Graph
Send deploy Mail.ReadWrite, Mail.Send Microsoft Graph
Monitor ActivityFeed.Read Office 365 Management Activity API

Grant admin consent after adding the permissions.

Warning

Mail.ReadWrite application permission grants tenant-wide mailbox write access by default. Production use requires formal approval and explicit scoping decisions. Operators can use Exchange Online RBAC for Applications to scope access to selected mailboxes, but must ensure unscoped Microsoft Entra grants do not remain in place.

Templates

Bundled Outlook templates:

  • Fake Password Reset
  • Fake Wire Transfer
  • IT Compliance Audit Notice
  • Payroll Direct Deposit Update

Custom Outlook YAML templates are supported through ANGLERFISH_TEMPLATES_DIR:

export ANGLERFISH_TEMPLATES_DIR="$PWD/custom-templates"
anglerfish --non-interactive \
  --canary-type outlook \
  --template "Fake Password Reset" \
  --target adele.vance@contoso.com \
  --delivery-mode draft \
  --var company_name="Contoso"

--template names are case-insensitive. Repeat --var KEY=VALUE to fill template variables.

Usage

Interactive deploy:

anglerfish

Non-interactive draft deploy:

anglerfish --non-interactive \
  --canary-type outlook \
  --template "Fake Password Reset" \
  --target adele.vance@contoso.com \
  --delivery-mode draft \
  --output-json ~/.anglerfish/records/adele-draft.json

Non-interactive send deploy:

anglerfish --non-interactive \
  --canary-type outlook \
  --template "Fake Wire Transfer" \
  --target adele.vance@contoso.com \
  --delivery-mode send \
  --output-json ~/.anglerfish/records/adele-send.json

List records:

anglerfish list --records-dir ~/.anglerfish/records

Verify draft-mode records:

anglerfish verify --records-dir ~/.anglerfish/records
anglerfish verify ~/.anglerfish/records/adele-draft.json

Cleanup:

anglerfish cleanup --non-interactive ~/.anglerfish/records/adele-draft.json
anglerfish cleanup --non-interactive ~/.anglerfish/records/adele-send.json

Trigger authorized access to generate audit evidence:

anglerfish demo-access --non-interactive ~/.anglerfish/records/adele-draft.json
anglerfish demo-access --non-interactive ~/.anglerfish/records/adele-send.json

demo-access performs a Graph read of the deployed canary so a permitted demo tenant can generate a real MailItemsAccessed event. It does not bypass Unified Audit Log latency; poll after the event is available.

Monitor for access:

anglerfish monitor --records-dir ~/.anglerfish/records
anglerfish monitor --once --records-dir ~/.anglerfish/records
anglerfish monitor --records-dir ~/.anglerfish/records \
  --alert-log ~/.anglerfish/alerts.jsonl \
  --slack-webhook-url https://hooks.slack.com/services/...

The monitor flags can also be set via environment variables (ANGLERFISH_MONITOR_STATE_FILE, ANGLERFISH_MONITOR_ALERT_LOG, ANGLERFISH_SLACK_WEBHOOK_URL, ANGLERFISH_MONITOR_NO_CONSOLE); CLI flags take precedence. See .env.example for the full variable set.

Unified Audit Log polling is delayed, not an immediate stream. Microsoft does not guarantee a return time for audit records; core service records are typically available after 60 to 90 minutes. See Microsoft audit search guidance.

To keep the poll loop running unattended, examples/anglerfish-monitor.service is an optional sample systemd unit that supervises anglerfish monitor --no-console. It is a convenience example for operators, not a built-in daemon mode.

The no third-party data plane claim applies to detection. Optional Slack alerting sends post-detection notifications to the configured webhook.

Suppress known-good actors:

anglerfish monitor --exclude-app-id "<known-good-app-id>"

--exclude-app-id is a static allowlist for known-good actors such as backup, DLP, or eDiscovery tools. The option is repeatable when more than one known-good app principal should be excluded from matching. Do not exclude the actor or app used to generate demo evidence.

Demo mode:

anglerfish list --records-dir examples/demo-records
anglerfish cleanup --demo --non-interactive examples/demo-records/outlook-draft-record.json
anglerfish cleanup --demo --non-interactive examples/demo-records/outlook-send-record.json
anglerfish monitor --demo --count 2

anglerfish verify --demo intentionally includes gone/error rows and exits nonzero, so it is omitted from the copy-paste demo block.

CLI Help

anglerfish --help
anglerfish verify --help
anglerfish demo-access --help
anglerfish monitor --help

Those help screens are the source of truth for the current command surface. This release only supports Outlook deploy/detect workflows.

About

Plant Outlook canary messages in Microsoft 365 and detect mailbox access via the tenant's own audit log — no callback infrastructure

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors