Dify
Your Dify agent can already browse the web and call APIs - it just can't prove to anyone, including you, which agent did it, or stop a compromised one from doing it again.
Dify apps run behind a shared NAT egress IP indistinguishable from every other tenant, so "which of my 40 agents hit this API" is a grep through logs you have to trust, and "kill that agent's network access" means editing the app instead of revoking an identity. The Whisper Agent Identity plugin fixes this at the network layer: a Dify tool-call gets real, routable IPv6 identity - verify any address, provision a new one with its own /128, govern it, and (Dify being self-hostable) route the agent's traffic through that address.
It ships as a standard Dify tool plugin, live today both on GitHub and in Dify's own Marketplace. Like every Whisper integration it is two-tier: the verification tools work with zero configuration and no account, and pasting in a Whisper API key unlocks the control plane and the graph's full depth.
Install it
Marketplace (live now). Inside Dify: Plugins → Marketplace, search "Whisper", install Whisper Agent Identity. langgenius/dify-plugins#2636 merged this listing.
GitHub install (also live). In Dify: Plugins → Install Plugin → Install from GitHub, point at whisper-sec/dify-plugin, pick the latest release. No build step - useful for pinning a specific version ahead of the Marketplace's own release cadence.
Build it yourself - the source is plain Python + YAML, no Whisper tooling required:
# stock tools only
gh release download -R langgenius/dify-plugin-daemon \
--pattern 'dify-plugin-linux-arm64' -O /tmp/dify-plugin && chmod +x /tmp/dify-plugin
git clone https://github.com/whisper-sec/dify-plugin whisper-dify
/tmp/dify-plugin plugin package ./whisper-dify -o whisper-agent-identity-0.1.0.difypkg
Open the plugin's Authorize panel and you'll see exactly two optional credentials: api_key (a whisper_live_… key) and egress_proxy (a local proxy URL). Both blank is a fully working install.
The fifteen tools
The plugin is one Dify tool provider (provider/whisper.yaml) exposing fifteen tools, split into three tiers rather than two:
| Tier | Tool | Wire call |
|---|---|---|
| Keyless | Verify Agent Identity | GET /verify-identity?ip=<addr> |
| Keyless | Lookup RDAP Record | GET /ip/<addr> |
| Keyless | Get Transparency Log | GET /ip/<addr>/transparency |
| Keyless | Get Inbound Lookups | GET /ip/<addr>/lookups |
| Keyless, deeper with a key | Assess Threat Posture | whisper.assess |
| Keyless, deeper with a key | Identify Vendor / Operator | whisper.identify |
| Keyless, deeper with a key | Explain Threat Score | whisper.explain |
| Keyless, deeper with a key | Generate Look-alike Variants | whisper.variants |
| Keyless, deeper with a key | Query Graph (Cypher) | raw Cypher against whisper.security |
| Keyless, deeper with a key | Run Graph Recipe | one of the 29-recipe catalog, by slug |
| Control (needs key) | Register Agent | CALL whisper.agents({op:'register'}) |
| Control (needs key) | Set Policy | op:'policy' |
| Control (needs key) | Get Logs | op:'logs' |
| Control (needs key) | Revoke Agent | op:'revoke' |
| Control (needs key) | Get Egress Config | op:'connect' |
The first four hit the public gateway rdap.whisper.online over plain HTTPS - no header, no cookie, no rate cut. The middle six reach the graph itself: Query Graph and the direct recipes inside Run Graph Recipe (assess, identify, explain, variants, walk, origins, history, and the rest of the 14 direct procedures) work with no key at all, rate-limited and depth-limited; add a Whisper API key and the limit lifts, and the recipe catalog's 15 multi-step flows (typosquat scanning, attack-surface mapping, BGP-hijack exposure, subdomain-takeover detection, and the rest) unlock too. The last five all funnel through the one Whisper control verb, CALL whisper.agents({op, args}), POSTed as Cypher to https://graph.whisper.online/api/query with the caller's key in X-API-Key. The plugin never invents a second API surface; it's a thin, typed wrapper over the same verb the CLI uses, so a tool's behavior is exactly what whisper on your terminal would do. The DoH resolver (/dns-query) is deliberately not exposed as a tool - a DNS-message-in/DNS-message-out endpoint is a broken building block for an LLM tool call.
Verify an agent
Verify Agent Identity answers "is this address a genuine Whisper agent, and who runs it?" by checking that the forward name for the agent's /128 and the reverse PTR agree - the same forward-confirmed reverse DNS trick operators have used since split-horizon anti-spoofing became common practice, formalized here as one call.
Independently, from a terminal, that's a forward-confirmed-reverse-DNS check plus an RDAP lookup - the full walk is in Verify an agent. In Dify it's one tool call:
Verify Agent Identity address = 2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4
{ "is_whisper_agent": true,
"fqdn": "acef2002a323d40d4.t7af9242c44554e0f8e183ac8e6fbf645.agents.whisper.online",
"dane_ok": true,
"jws_ok": true,
"evidence": {
"ptr": "4.d.0.4.d.3.2.3.a.2.0.0.2.f.e.c.4.7.a.c.a.5.b.e.1.0.a.2.4.0.a.2.ip6.arpa",
"forward_aaaa": "2a04:2a01:eb5a:ca74:cef2:2a:323d:40d4",
"agent": "acef2002a323d40d4" } }
The PTR resolves back to the exact address it claims (forward_aaaa), and the leaf is pinned by a DNSSEC-anchored TLSA record (dane_ok) whose transparency entry is signed (jws_ok) - three independent confirmations in one call. An address that anchors no agent - or where forward and reverse disagree - returns is_whisper_agent: false with the specific reason, never a bare 404. That's the same liberal-input contract as whisper verify and every keyless SDK call: never an opaque error, always a verdict plus evidence.
Get Transparency Log is the deeper check: it returns the hash-chained, signed record of every issuance event for that /128 - the append-only ledger analogue of Certificate Transparency (RFC 9162)'s core idea applied to address identity rather than X.509 leaves, so a party who doesn't trust Whisper's word can still verify the chain itself rather than trust a point-in-time API answer.
Register & govern
With stock tools, provisioning a routable, verifiable per-agent identity is not something curl/openssl do for you - there's no RFC for "mint me an IPv6 /128 with reverse DNS, a TLSA record, and a revocation path" you can hand-roll from a resolver. This is exactly the gap the control plane fills.
With the Dify tool:
Register Agent name = scout contact_email = ops@example.com
{ "agent": "scout",
"address": "2a04:2a01:…",
"fqdn": "a<interface-id>.<your-tenant>.agents.whisper.online",
"api_key": "whisper_live_…",
"state": "active" }
The /128 is freshly minted from AS219419 space under your tenant (not the demo's), so the reverse name lands in your own …agents.whisper.online label - exactly the identity you just learned to verify.
The key is returned exactly once - register_agent.py surfaces it in the tool's text summary ("api_key returned once - store it now") precisely so it doesn't silently vanish into workflow logs. From there, Set Policy writes the tenant's DNS allow/deny bundle, Get Logs reads back recent DNS/connection/allocation activity for auditing inside a Dify workflow, and Revoke Agent tears the identity down - withdrawing the /128, its PTR, its tokens, and its key in one irreversible call, so a compromised or retired agent can be cut off from a chat message instead of a config edit.
Egress: making it real, not just observed
Verification and governance are half the story; the other half is that Dify is self-hostable, so an agent's actual traffic can leave from its /128 instead of the shared platform IP. Get Egress Config reports the binding but - by design - never returns the raw egress bearer or WireGuard key, so nothing secret leaks into workflow data. Bring up real egress with the open-source CLI on the Dify host, then point the deployment (or just this plugin's egress_proxy credential) at it:
curl https://get.whisper.online | sh
whisper connect --port 1080
# → socks5h://127.0.0.1:1080, bound to your /128
# egress.compose.yaml - applied to plugin_daemon, api, worker
environment:
ALL_PROXY: socks5h://host.docker.internal:1080
NO_PROXY: localhost,127.0.0.1,db,redis,weaviate,sandbox,plugin_daemon,api,ssrf_proxy
docker compose -f docker-compose.yaml -f egress.compose.yaml up -d
curl --proxy socks5h://127.0.0.1:1080 https://api64.ipify.org
# → your agent's own /128; confirm the identity at /docs/verify
Full recipe, including the whole-deployment vs. single-plugin tradeoff, is in the plugin's shipped EGRESS.md.
Source
Plugin source: github.com/whisper-sec/dify-plugin (MIT). Control-verb reference client: github.com/whisper-sec/whisper-cli.
Next: Integrations overview · MCP server