Subscribe to Running With Scissors

Hacking, policy, advocacy, and the sharp end of security research. Delivered to your inbox.

Free. No spam. Unsubscribe anytime.

Check your inbox

A confirmation link has been sent to your email.

Feedback Requested: Coordination is going API-first. Contact Discovery and Attribution still aren't solved.

Vulnerability coordination is going API- and MCP-driven, but attribution and contact discovery are still the hard part. What's new in lookup.disclose.io — and where we want your feedback.

Feedback Requested: Coordination is going API-first. Contact Discovery and Attribution still aren't solved.

The way we coordinate vulnerabilities is in the process of changing shape. For twenty years it has been a human craft — you find a bug, you go hunting for who to tell, you compose an email, you wait. The finding and the judgment are not going anywhere: people still direct the testing, decide what is worth reporting, and choose who to trust. What is changing is the plumbing around those decisions. The lookup-and-route grunt work that sits between a finding and the right inbox is getting more programmatic — APIs, integrations, and increasingly MCP, so the tools and assistants you already drive can pull in an answer instead of sending you on a twenty-minute hunt.

That is good. The judgment is the valuable part; the plumbing is the part we should have sorted out years ago. Better plumbing does not make the hard part go away, though — it just exposes it. The hard part has always been the very first step: whose thing is this, and who do I even tell?

Look up the wrong contact by hand and you usually sense something is off and double-check. Bake that same wrong answer into a tool, an integration, or a pipeline, and it just keeps being wrong — quietly, the same way, for everyone who relies on it. That is the catch with better plumbing: the contact layer underneath it has to be two things at once — correct, and easy for your tools to call. Right now it is usually neither.

That is the gap lookup.disclose.io exists to close, and it is why this post is also a request: tell us where it is still wrong.

What it is

lookup.disclose.io takes almost any internet asset and tells you who owns it and the right way to reach their security team. A domain, an IP, an ASN, a URL, an email, a CIDR. A repository or a package — npm, PyPI, crates, Go, Maven. A container image or a cloud bucket. A mobile app, a desktop app, a browser extension. A piece of hardware, right down to an FCC ID. Or just a company name. Sixteen input types in all, auto-detected from the shape of what you paste.

It resolves each one to a channel — a security.txt, a bug bounty program, a VDP, a PSIRT, or, when nothing better exists, a national CERT. It also chains: hand it a package and it walks to the repository, to the owning organization, to that org's published security.txt, up to three hops deep.

Three rules it plays by, because they matter more under automation than they ever did by hand:

  • Always an answer, best-effort. No direct channel? You get the strongest available backstop, not a dead end.
  • Never hallucinate. It will not invent a contact to look helpful — there is no language model inside lookup that could invent one. Every channel it returns is one the engine actually found.
  • Confidence, labelled. Strong reporting channels are kept separate from fallbacks, so an agent — or a person — knows how much to trust the answer.

That second rule is the whole game when a model is in the loop. An LLM asked "who do I email about a bug in this package?" will happily produce a plausible, well-formatted, completely fictional security address. lookup is built to refuse to do that — and it can, because lookup itself is fully deterministic. There is no LLM or AI anywhere in its pipeline, and it sends no queries to one: every answer is explicit code walking real records — security.txt files, registries, WHOIS, package and registry metadata, FCC grantee tables — so the same input always returns the same result, and a contact only ever comes back if lookup genuinely found it. The model in the loop is yours, calling lookup; lookup is the deterministic ground truth you point it at.

What's new: it plugs into your tools now

The biggest changes since launch are about letting it plug into the tools and pipelines you already use.

A hosted MCP server. lookup is now in the official MCP registry as io.github.disclose/lookup-disclose-io, and you can point any MCP client straight at it — no install. In Claude Code that is one line:

claude mcp add --transport http lookup https://lookup.disclose.io/mcp

It exposes two tools: lookup_security_contact (the full lookup — returns a readable summary plus structured data) and classify_asset (an instant asset-type classifier with no network call). Cursor and LM Studio have one-click deeplinks on the site. The assistant you are already working in can pull the right contact into the conversation when you ask for it, instead of making you break out to a separate tab.

A proper JSON API. One endpoint — POST /api/lookup, body {"input": "..."} — returns the same structured result the web UI and the MCP server use, because all three run the same engine. There is an OpenAPI 3.1 spec at /openapi.yaml, a Swagger UI at /api-docs, and an llms.txt (plus a fuller llms-full.txt) so you can hand a coding agent one file and have it wired in. It is free and anonymous at 30 requests a minute per IP; if you need more, email hello@disclose.io for a key.

A hard push on attribution accuracy. None of the above matters if the answer is wrong, so we have put most of our recent work into the unglamorous part — getting attribution right on the assets where it is genuinely hard. That deserves its own section, because the failure modes are instructive.

Why attribution is hard — and where it used to break

Naive attribution does not fail by returning nothing. It fails by returning something wrong, with total confidence. A few real examples from our own test corpus — cases lookup used to get wrong, and now does not:

The npm package webpack. Follow the maintainer email addresses and one of them sits on a qq.com domain. Chase that to an organization and you arrive at Tencent — and a vulnerability report for one of the most-depended-on build tools on the internet gets routed to a company that has nothing to do with it. The right answer is webpack's own security process, not the email provider of one of its contributors.

The PyPI package cryptography. Its homepage points at github.com. Resolve that domain naively and you pull GitHub's own security.txt — so the package looks like it belongs to GitHub, and behind it, Microsoft. GitHub is the host, though, not the owner. The maintainer is the Python Cryptographic Authority. A report to Microsoft's bounty program never reaches the people who can fix it.

The browser extension Dark Reader. Parse the listing naively, take the first word — "Dark" — try to resolve it, and you can land on Netflix. Two things that could not be less related, one quietly routed to the other.

An FCC ID. This was the worst one, because it did not just misroute — it fabricated. Given a hardware identifier, the old behavior would guess a contact like psirt@<that-id>.com: an address that has never existed, presented as if it were verified. A researcher emails it, hears nothing, and the vendor never learns about the flaw. The correct path is to decode the FCC grantee code to the actual manufacturer, then find that manufacturer's real published security contact — and if there is not one, to say so honestly rather than invent it.

There were more — a date library attributed to a maintainer's university, container images attributed to the registry that hosts them instead of the vendor that builds them. The pattern is always the same: a plausible chain that lands one hop short, or one hop sideways, of the truth. Each one is now a regression test. The point is not that lookup is finished — it is that "confidently wrong" is the specific thing it is engineered against, and the only way to keep pushing that down is to find more of the cases where it still happens — which is where you come in.

Put it in your workflow — and build on it

If you do recon, you can already pipe into it. dio-lookup is a unix-style CLI — feed it a list of hosts and it emits one JSON result per line:

subfinder -d example.com | httpx | dio-lookup

There are working integrations for two of the tools researchers live in: caido-lookup (a Caido plugin) and burp-lookup (a Burp Suite extension). Both send only the host string — no request bodies, no headers — and render the attribution and ranked contacts in a panel. Source for all three is public under the disclose GitHub org.

What we would love to see next is the stuff we have not built. A ProjectDiscovery or Nuclei workflow that annotates findings with a disclosure contact. A Caido or Burp action smarter than ours. An agent that, handed a breach dump, drafts the notification batch for you to review and send. The API, the MCP server, and the CLI exist precisely so you do not have to ask permission to build any of it.

Feedback wanted

This is the actual ask, so I will be blunt about it. lookup is useful today and wrong sometimes, and we would much rather hear about the wrong from you than from a misrouted report six months from now. Three questions in particular:

  • Are we getting you to the right places? When you looked something up, did the contact it returned turn out to be correct? When it did not, what was the right answer? Wrong and missing answers are the single most useful thing you can send us.
  • What input types are we missing? Sixteen covers a lot, but not everything. What did you want to paste in and couldn't — or pasted and got nothing useful back?
  • Where would you wire it in? If you'd run this inside Caido, Burp, a ProjectDiscovery or Nuclei pipeline, a SOAR playbook, or your own assistant — tell us, or just build it. The API, MCP server, and CLI are there for exactly that.

Tell us on whichever social thread brought you here, in the thread on community.disclose.io, or by email at hello@disclose.io. That same address gets you an API key if you need volume. Know someone who spends their afternoons hunting for the right inbox? Send them the link — spreading the word is the highest-leverage thing you can do to make a shared contact layer actually shared.

Try it: lookup.disclose.io

More of vulnerability coordination is moving through tools and integrations, and that is a good thing — it frees people up for the parts that actually need judgment. It only works if the layer underneath is right. The contact layer should be a boring, correct, shared, open utility that any tool can call and nobody has to re-derive badly. Help us make it that.