Responsible Disclosure & Data Transparency

EchelonGraph operates Discovery Radars — the Shadow AI Radar, AI-Exposure Radar, KEV-Exposure Radar, Exposed Data-Stores Radar, Exposed AI Keys & Config Radar (the exposed-config radar below), Subdomain Takeover Radar, Email Spoofability Radar, and Leaked Cloud-Credentials Radar. They find candidate internet-facing security exposures in public data and, where a candidate has to be confirmed, confirm it with identified requests of our own, as an early-warning signal. It also covers the on-request Surface Scanner — a scan that runs only when someone submits a domain to it. This page explains exactly how each of these handles data, and how to request removal.

Our Discovery Radars resumed on 18 October 2026, and every request they send to the hosts they check leaves from 34.139.141.181 (Where our scanning comes from). They had been stopped since 11:21 UTC on 8 October 2026, all of them but the KEV-Exposure Radar, which sends no request to the hosts it reports on. Each of the five that send requests to the hosts they check — the Shadow AI, AI-Exposure, Exposed Data-Stores, Exposed AI Keys & Config and Subdomain Takeover Radars — checks any one host we do not own at most once in 24 hours. That limit is each radar’s own: two of them can each check the same host on the same day. Four of them never follow a redirect from a host they check, except that the Exposed AI Keys & Config Radar retries a storage-bucket listing once at the regional endpoint S3 redirects it to, under that bucket’s same 24-hour limit. The Shadow AI Radar, which does follow redirects, counts a host it is redirected to as checked. A storage bucket reached through its provider’s shared endpoint (storage.googleapis.com, or s3.amazonaws.com addressed by path) is listed at most once in 24 hours: that endpoint is the provider’s, not a host we check. (Amended 18 October 2026: from 8 October 2026 this notice said they had been stopped and “have made no scheduled check since”.)

Seeing “EchelonGraph” in your logs?

If you found a request from us in your server or application logs, it may be one of our Discovery Radars checking a single finding, a Surface Scanner scan that someone asked us to run on your domain (see the next section), or one of the requests described under Other requests that name us below. Some radar checks are one unauthenticated GET, the kind a browser makes loading a page; others send several requests to one host. Confirming an MCP endpoint or an exposed datastore needs a protocol-level exchange rather than a plain GET, and the exposed-config radar sends up to 48 requests to one host — the budget for each radar is in How we confirm an exposure below. The radars work in the open, like Googlebot: every HTTP request a radar sends names us in its User-Agent:

User-Agent: EchelonGraph-<Radar>/1.0 (+https://echelongraph.io/surface-scanner; opt-out https://echelongraph.io/responsible-disclosure; [email protected])
From: [email protected]

The <Radar> names the specific check (e.g. ExposureRadar-Verifier, ShadowAIRadar-Verifier, KEVExposureRadar). Our radar prober sends EchelonGraphBot/1.0 (+https://echelongraph.io/bot) instead, and echelongraph.io/bot describes it. The From header is a real inbox you can reach us at. We never log in, submit credentials or exploit what we find. Not every request is a read: the MCP handshake is a POST that can open a session, which we then close. We do read the body of a file we find exposed, up to a size cap — that is how a leaked secret is detected — and what we read is redacted before storage. See What we never do and How we confirm an exposure below.

Worried someone could spoof our name to frame us? A radar's HTTP requests to the host it checks carry a signed X-EchelonGraph-Verify receipt. Paste it at echelongraph.io/verify-scan and we'll confirm whether the request was genuinely ours, and show the host, radar and time it attests. A request whose receipt does not verify is not us. Some of our requests carry no receipt: a DNS query has nowhere to put one, and a radar's lookups to data services such as crt.sh carry none. /verify-scan lists them under Requests that carry no receipt.

Prefer we don't scan your hosts? Email [email protected] with the IP, range, or domain and we'll exclude it from future collection.

Where our scanning comes from

One address is reserved for our scanning: 34.139.141.181. Our radar prober (EchelonGraphBot, described on echelongraph.io/bot) has sent every request from it since 17 October 2026. Since 18 October 2026 our Discovery Radars have sent from it every request they send to the hosts they check (the Leaked Cloud-Credentials, Email Spoofability and KEV-Exposure Radars send those hosts none: the KEV-Exposure Radar works from Shodan, which it queries from our main platform, from 34.72.193.151, and the Email Spoofability Radar reads public DNS through Google Cloud’s resolver), and so has the Surface Scanner below since 18 October 2026. (Amended 18 October 2026: this said that when our Discovery Radars run again, they will send every request from it.) (Amended 18 October 2026: this read “and so will the Surface Scanner below once it is moved onto it”.) One exception: a request to a site hosted on Google Cloud itself (for example a *.run.app or storage.googleapis.com address) travels inside Google’s network and does not arrive from this address. It is a static address reserved for scanning and used for nothing else — not for email, and not for our product — so you can allowlist it, rate-limit it or block it without asking us, and blocking it stops the scanning that sends from it and nothing else. We will not change it without saying so on this page first.

Today our radar prober (since 17 October 2026), our Discovery Radars (since 18 October 2026) and the Surface Scanner (since 18 October 2026) send from it. Until they were stopped, the Discovery Radars’ scheduled checks reached the hosts they check from Google Cloud’s shared egress addresses, which are not ours alone and not fixed, and the radar prober’s requests left from 34.72.193.151. (Corrected 18 October 2026: this read “the Discovery Radars’ requests left from Google Cloud’s shared egress addresses”. Not all of them did: a visitor’s re-check of a finding ran on our main platform until 8 October 2026, and the KEV-Exposure Radar, which was never stopped, queries Shodan from there, both from 34.72.193.151.) That address is our main platform’s, our transactional email leaves from it too, and our scanners do not send from it. The Surface Scanner, which runs only when someone submits a domain to it or asks it to keep monitoring one, has not been stopped, and as deployed since 18 October 2026, it sends from 34.139.141.181; until 18 October 2026 it sent from 34.72.193.151. (Amended 18 October 2026: this read “by our deploy configuration it still sends from 34.72.193.151 today”.) A few requests run on our main platform rather than in a scanner. The ones that would contact a host we scan — a visitor’s re-check of a finding, the re-check behind our company-exposure report, and the security.txt lookup that prepares a disclosure — are switched off there; the first two, if they run again, will run only from 34.139.141.181. (Amended 17 October 2026: this named only the two re-checks.) The registration lookup, which asks a domain’s registry and not the domain’s own hosts, leaves from 34.72.193.151. (Amended 8 October 2026: this said a visitor’s re-check of a finding left from 34.72.193.151.)

Its reverse DNS is Google Cloud’s generic name, 181.141.139.34.bc.googleusercontent.com, which resolves back to the address but does not name us. A request identifies itself as ours by its User-Agent and, on the radars’ and the Surface Scanner’s HTTP requests, its signed receipt, as described above.

Abuse reports, opt-out and takedown requests: email [email protected] with the address, the time and what you saw — or the IP, range or domain you want excluded — and it reaches a person.

The Surface Scanner (runs only on request)

Separate from the Discovery Radars above, the Surface Scanner is an on-request check: it runs only when someone submits a domain to it or asks it to keep monitoring one, and we never start a scan of a domain on our own. It does not check that the person asking owns the domain: as with other public scanners, anyone may submit any public domain, and the public result is redacted so that it carries no exploit-grade detail. However many people ask, one hostname is scanned at most 30 times an hour and 200 times a day. (Corrected 8 October 2026: this said the scanner was consent-gated, that it ran only after the requester proved control of the domain by verifying a same-domain email address, that we do not scan a domain unless its owner has asked us to, and that it was capped at one free scan per domain per 24 hours. The email check and the 24-hour cap were removed on 21 July 2026, and this page was not updated then.)

Like the Radars, the Surface Scanner identifies itself in the open. On its HTTP requests, your server or application logs will show:

From: [email protected]
X-EchelonGraph-Surface-Scan: <scan-id>
X-EchelonGraph-Verify: https://echelongraph.io/verify-scan?receipt=<receipt>&scan=<scan-id>
X-EchelonGraph-Receipt: <receipt>

Each scan also has a signed receipt, and its HTTP requests to your domain carry it, as do its requests to other hosts that belong to the scan, such as a redirect target or a storage bucket your pages reference. The receipt covers the whole scan, not one request: a host owner can confirm at echelongraph.io/verify-scan that the scan was genuinely ours, which domain we scanned and when the scan started. A request whose receipt does not verify is not us.

Some of the scan's requests carry no receipt:

  • • Lookups to data services, which go to those services and not to you: Cloudflare's DNS-over-HTTPS resolver, the certificate-transparency search services crt.sh and Cert Spotter, domain registries' RDAP servers, and hstspreload.org. They name us in the User-Agent.
  • • The mail check, which connects to your mail exchangers on port 25 and names itself only in its greeting: EHLO scanner.echelongraph.io.
  • • DNS queries, including zone-transfer (AXFR) requests, and TLS handshakes. They have no headers to carry anything.
  • • The port check that a scan a signed-in customer starts inside the EchelonGraph app also runs: a TCP connection to each of a fixed list of common service ports on your host, and, where MongoDB, Redis, Memcached or Cassandra answers, a short exchange that tests whether it answers without a password and reads none of its keys, documents or rows. A connection has no headers. The MongoDB, Redis and Cassandra exchanges carry a receipt in the client details the protocol records (Redis's client name, the driver version for MongoDB and Cassandra); Memcached's protocol has no such field.

The scan is non-intrusive, but broader than a browser: alongside unauthenticated HTTP it queries your DNS — including zone-transfer (AXFR) requests — connects to your mail exchangers on port 25 to test STARTTLS, and submits non-destructive test values to forms and redirect parameters. It makes exactly one kind of write: an empty marker object into a storage bucket your own site references, to test whether anonymous writes are accepted, which we then delete. Where a bucket permits the upload but refuses the delete, a zero-byte file named .echelon-probe-… may remain and is safe to delete at any time. It never logs in, submits credentials, exploits a finding, or reads private data from your systems. The Terms describe every request type in full.

Prefer we never scan your hosts — even on request? The same takedown / opt-out contact applies: email [email protected] with the IP, range, or domain and we'll exclude it from future collection.

Other requests that name us

Some of our software names us in its User-Agent and is not a scan: it is neither a Discovery Radar nor the Surface Scanner, and it carries no receipt.

  • • The CVE reference fetcher (EchelonGraph-CVE-Enricher/1.0). A published CVE record lists reference links, such as vendor advisories, bug reports, commits and mailing-list posts. For our CVE data we fetch those pages to see whether they report a patch or exploitation: at most one GET for each link, up to ten links per CVE record, following at most two redirects. Links to GitHub pull requests, commits and releases are read through GitHub's API instead. If a CVE record cites a page on your site, that is why we fetched it.
  • • Vulnerability and threat data. Our CVE and threat-intelligence collectors download public data from the services that publish it, for example NVD, CISA, FIRST, OSV, deps.dev, GitHub (the CVE Project's repository and GitHub's advisory database), exploit repositories on GitHub and GitLab, vendors' security-advisory feeds and abuse.ch, and tell IndexNow when our CVE pages change. These requests go to those services, not to you. Their User-Agents begin EchelonGraph-CVE- (apart from the fetcher above), EchelonGraph-VendorAdv- or EchelonGraph-MITRE-, or are EchelonGraph-Advisory, EchelonGraph-OSVBulk, EchelonGraph-ExploitIntel, EchelonGraph-RejectedBackfill, EchelonGraph-Vulnrichment-Backfill, EchelonGraph-Backfill or EchelonGraph-ThreatIntel. For our own package, echelongraph-mcp, we also read npm's public download counts once a week, and its registry metadata (which versions are published and which are deprecated) every 15 minutes and, at most once a minute, when our API meets a version it has not seen yet, as EchelonGraph-MCPNpmReport; those requests go only to npm. Our CVE records combine the CVE Project's record with NVD's, and an update from one sometimes erased the other's reference tags (such as “patch”). To put those tags back, we re-read the affected records' references from the CVE Project's repository on GitHub, as EchelonGraph-CNA-Reference-Tags, and from NVD's API, as EchelonGraph-NVD-Reference-Tags; those requests go only to GitHub and NVD. We also read ENISA's European Vulnerability Database (EUVD): which EUVD identifier names each CVE, and ENISA's EU list of known exploited vulnerabilities. These requests carry the User-Agent EchelonGraph-EUVD and go only to ENISA.
  • • Checks of our own CVE data. Once a week, as EchelonGraph-freshness-measure, a job measures how fresh our CVE data is. It reads NVD, CISA's KEV catalog, FIRST's EPSS API and npm, and asks each of the other public CVE MCP servers that /pulse/mcp compares us with about the same CVEs, up to 20 of them: it opens an MCP session, lists the server's tools, calls its CVE lookup tools for each CVE and closes the session. Once a day, as echelongraph-probe, a check reads one CVE record from NVD's API (up to three tries if NVD is busy), to compare it with the worked example on our methodology page.
  • • Deliveries our customers set up. EchelonGraph-Webhook posts event notifications to a URL an EchelonGraph customer entered, and EchelonGraph-SIEM forwards security alerts to the SIEM endpoint a customer entered. Our remediation feature opens pull requests in a customer's GitHub repositories through GitHub's API, as EchelonGraph/1.7 (remediation). These go only where a customer set them up to go.
  • • Software our customers run. Our on-premises crawler (EchelonGraph-NetworkScanner, EchelonGraph-Agent) and our continuous agent (EchelonGraph-Tier3, EchelonGraph-Tier3-Agent) run inside a customer's own environment. Their requests come from that customer's network, to the hosts, cloud services, key stores, code hosts, threat feeds and chat webhooks they are set up to use, and to the EchelonGraph server they report to.

None of these claims to be a scan, so the rule on echelongraph.io/verify-scan for requests that claim to be one of our scans and carry no receipt does not apply to them.

A question about any request that names us? Email [email protected] with its time, source IP address and User-Agent.

What data we use (public only)

We find candidates in already-public sources:

  • • Internet-wide scan catalogues (e.g. Shodan, Censys) — banner data those services already collected and publish.
  • • Certificate Transparency logs (read through crt.sh) — the certificates that certificate authorities publish, which name the hostnames they cover.
  • • The public GitHub event stream / GH Archive — commits pushed to public repositories.
  • • Public vulnerability data (CVE, CISA-KEV, EPSS).

Whether a candidate is then recorded as an exposure is decided by our own identified requests to it — see How we confirm an exposure below.

Scan catalogues such as Shodan are commercial services we query under their terms; beyond them we do not use private or access-controlled data, and we do not attempt to obtain any.

What we never do

  • • We never log in, authenticate, exploit, or extract data from any exposed host, database or service. Verification is deliberately minimal but it is not always a bare read: confirming a Model Context Protocol endpoint requires a POST. We first send server/discover, which asks the server which protocol versions it supports and, under the 2026-07-28 revision, opens no session; a server that answers it with a result or with an error that revision defines receives no further POST. Only when it is refused with an HTTP 4xx status other than 401, 403, 405 or 429 that is not a web page, or with a JSON-RPC error, do we send the older initialize handshake as a second POST, and if either POST opens a session we then send a DELETE to release it rather than leave it holding a slot on someone else’s server. A server that answers server/discover as the 2026-07-28 revision specifies opens no session for it, so it is sent neither the second POST nor a DELETE: on that path we write nothing to the server. If a POST is refused with HTTP 401 or 403, at most two further identified GETs to the same host read its OAuth protected-resource metadata (RFC 9728). If the challenge names a metadata URL, we request that URL once, only if it is on the same origin, and try nothing else; if it names none, we request /.well-known/oauth-protected-resource/mcp, and then /.well-known/oauth-protected-resource only if the first answered with an HTTP status other than 2xx. No redirect is followed, and a metadata URL on another origin is never requested. On a host named like an MCP server where neither POST found an MCP endpoint and the last was answered 400, 404 or 405, we send one identified GET to /sse, the stream of the deprecated HTTP+SSE transport, read at most its first event (no more than 4 KB, within 4 seconds) and close the connection, which ends the session that transport opens for each stream. The radar that sends these (its User-Agent names AIExposureRadar) first asks our scan opt-out register about the host of every request it makes, and sends nothing to a host covered by a verified exclusion scoped all or radar — see Takedown / opt-out below. Confirming an exposed datastore opens a TCP connection and sends the engine’s metadata command, on some engines after a handshake (/exposed-databases lists every command) — on Redis, HELLO 2 and CLIENT SETNAME carry our client name so the connection is identifiable in your own CLIENT LIST, then INFO asks for server statistics. The Surface Scanner additionally uploads one empty marker object to a bucket your site references, described above
  • • We never use, validate, or authenticate with a detected credential. A match means a credential-shaped string appeared in a public commit — not that we confirmed it is live.
  • • We never retain exposed private data. Detecting a leaked secret requires reading the file that holds it, so config-file bodies are read; what is read is redacted before storage and the raw value is never written to our database.
  • • We never publish individual host IPs, repository names, commit URLs, or secret values on our public pages.

How we confirm an exposure

To avoid false positives, a radar that confirms a candidate asks the host for it directly before recording an internet-facing exposure. The candidate comes from public data; the confirmation is requests of our own, each one identified, and how many depends on the radar:

  • • The AI-Exposure Radar sends one identified GET for each product it checks on a host, of an endpoint that product’s own auth layer is meant to guard. On a Model Context Protocol endpoint it instead sends up to two POSTs (server/discover, then the older initialize handshake only if that is refused), a DELETE to close any session a POST opened, after a 401 or 403 up to two metadata GETs and, where neither POST found an MCP endpoint, one GET of the older SSE transport’s stream, as described under What we never do above.
  • • The Shadow AI Radar’s verifier sends several GETs to one host: its page, following redirects; the target of a JavaScript redirect if the page has one; known API paths for that kind of service; when a Flowise API answers with its API-key refusal, one more to its public version endpoint; and in some cases the landing page again.
  • • The Exposed Data-Stores Radar opens a connection and sends the engine’s metadata command, after a handshake on some engines: on Redis,HELLO 2 and CLIENT SETNAME carry our client name, then INFO. /exposed-databases lists every command per engine.
  • • The Subdomain Takeover Radar makes up to 12 name resolutions and one or two identified GETs per candidate. The GETs carry our identity and receipt; a name resolution is a DNS query through our resolver, which can carry neither, and a DNS server may see more than one query for it. The radar is also pointed, every 24 hours, at the subdomains that Certificate Transparency logs list for a curated watchlist of company domains, up to 300 for each domain, with the same identified requests.
  • • The exposed-config radar sends up to 48 to a single host: a HEAD to find the live scheme, one random-path canary to detect a catch-all, 23 known configuration paths, the homepage, up to 10 same-host script bundles, and up to 11 observability-tool probes.

Three radars send no request of their own to the hosts they report on. The KEV-Exposure Radar works from Shodan data alone. The Leaked Cloud-Credentials Radar reads public GitHub commits. The Email Spoofability Radar resolves a domain’s MX record and its SPF and DMARC TXT records through DNS — three name resolutions, which our resolver answers from its cache or by asking the domain’s DNS servers — and connects to none of its web or mail servers.

We never submit credentials. Not every request is a read: the MCP handshake is a POST that can open a session, which our DELETE then closes. We do read response bodies — that is how a leaked secret is detected at all. Of the 23 configuration paths, 22 are read up to a 256 KB cap — enough to find a secret, not enough to take a database — including /.aws/credentials and /.ssh/id_rsa; one, /actuator/heapdump, is truncated to its first 128 bytes with a Range header. What we read is redacted before storage — see Secret masking below. A host serving configuration-shaped content at more than five distinct paths is discarded as a honeypot rather than reported.

How we count the answer. An HTTP 401 or 403, or a sign-in page served directly (a password field in a form, or a page titled as a sign-in page) or reached by a redirect to a sign-in screen or an identity provider, is counted as auth observed and is not reported as an exposure, unless the service’s own API answers us without credentials, which is reported as an exposure whatever its landing page shows, with one exception. Before reporting an open API we fetch the service’s landing page once more, and when that page carries words we read as a deliberately public deployment (a research, teaching or demo service, or a listing of public workspaces or projects), sometimes together with a workspace or description in the API’s own answer, or when the page does not load and the API’s answer names both, the API is judged intentionally public, recorded as resolved and not reported. That judgement rests on those words alone: nobody told us the service is meant to be public, and it can be wrong. Flowise’s API-key refusal, a 401, is counted as auth observed only when its public version endpoint reports Flowise 3.0.1 or later: Flowise 2.0.6 to 3.0.0 send the same refusal even where their own web UI reaches the API with no sign-in, so for those, and for a version we cannot read or place, the API’s answer is recorded as not determined, and the service is counted as auth observed only if a page of its own refused us or showed a sign-in page. A page that only mentions signing in proves neither: the verdict then rests on the service’s API, and without one it is recorded as not determined. An MCP endpoint is the exception: the AI-Exposure Radar counts one as protected only when a POST of ours is refused with a 401 or 403 and the server’s OAuth protected-resource metadata checks out, and a 401 or 403 without that is recorded as not assessed; a login page or a 401/403 that the Shadow AI Radar sees on such a host says nothing about the MCP endpoint and is recorded as not determined. A result we cannot classify is counted neither as exposed nor as protected: it is recorded as not determined.

Secret masking & storage

Detected secrets are redacted before storage — we keep only a masked sample (e.g. AKIA••••••P3) and a salted-hash fingerprint. The raw secret value is never written to our database and is never displayed — in the public surface, the internal disclosure view, or any export. Public surfaces are aggregate-only (counts by type/provider/region); host- and repo-level detail is restricted to our team solely for responsible-disclosure outreach.

Retention & automatic cleanup

Observations auto-expire when an exposure is no longer observed: internet-exposure findings are removed after 14–21 days without re-observation, and leaked-credential findings after 60 days. When a host is secured, a database is locked down, or a credential is rotated, the corresponding record stops being seen and is pruned — so remediated items drop off automatically.

Responsible disclosure

Where we can identify an affected organisation, we aim to notify it privately through its published security or network-abuse contact, sharing only the evidence needed to remediate (e.g. the public commit URL, or the public scan record). We support coordinated disclosure and reasonable remediation windows.

Takedown / opt-out

If you operate an asset that appears in our data and want it excluded or removed, email [email protected] (or contact us). Include the asset identifier; we will remove matching records and can suppress future collection for it. (Remediating the exposure also clears it automatically under the retention policy above.)

For a domain there is also a self-service route that needs no email: publish one DNS record to show you control the name, and it goes on our verified scan opt-out register — the steps are on echelongraph.io/bot. Be aware of what that register reaches today. Five of our Discovery Radars read it — the AI-Exposure Radar, the Shadow AI Radar, the Exposed Data-Stores Radar, the Exposed AI Keys & Config Radar and the Subdomain Takeover Radar — before every request they send and every redirect they follow, and send nothing to your domain or any name beneath it once a verified exclusion scoped all or radar covers it; a revoked exclusion stops applying when the register is next read. The register holds names, so a request addressed to an IP address is covered only through the host names a scan index attributes to that address — and the Exposed Data-Stores Radar addresses every data-store probe that way, and sends nothing to an address whose Shodan or LeakIX record lists a host name at or beneath a domain with a verified exclusion. The Shadow AI Radar does the same for an address it took from Shodan, through the host names Shodan lists for it. An address no scan index attributes to your domain is still probed, and so is a Shadow AI Radar address until a Shodan sweep has recorded its host names; for an address or a range, email us as above. Not everything we send toward a domain reads the register: the Email Spoofability Radar does not, and may still read your domain’s public DNS records; and when we prepare a disclosure to your domain we fetch its security.txt without consulting it. (Amended 4 October 2026, #2478: this read “An address no scan index attributes to your domain is still probed, and so is an address the Shadow AI Radar took from Shodan”; the Shadow AI Radar now asks the register about the host names Shodan lists for the address.) (Amended 28 September 2026, #2358: this read “The register holds names, so a request addressed to an IP address is not covered — and the Exposed Data-Stores Radar addresses every data-store probe that way, as the Shadow AI Radar does for a result it took from Shodan”; the Exposed Data-Stores Radar now asks the register about the host names a scan index lists for the address.) (Amended 27 September 2026, #2323: this read “Among our Discovery Radars, only the AI-Exposure Radar … reads it” and “The Shadow AI Radar’s verifier, the Exposed Data-Stores Radar, the exposed-config radar and the Subdomain Takeover Radar do not consult it yet (#2323), so for those, email us as above”; all four now ask the register before every request they send.)

Legal basis

The radars constitute security research that finds candidates in public data and confirms them with identified, minimal requests, conducted to warn affected parties and the public of real exposures. We never log in to a system or get past its access controls, and we handle data in line with responsible-disclosure norms and applicable law. This page is informational and not legal advice.