In order to discover what would happen we created two honeypot LLM gateways: one mirroring LiteLLM and another one mirroring a generic OpenAI-compatible endpoint. We then proceeded to create over 40 individual organizations, each with at least on Github repository in a way that was convincing to threat actors. API keys along with the addresses of the gateways were added to these repositories in such a way that it looked like they were added by mistake by AI or human error. From this we observed over 3 million requests to our gateways, most of which were probing attacks and some of which ended up using inference in a pattern that we identified as reseller/gateway activity. Some connected to harnesses like OMP or Hermes, others connected to Telegram agents and some were even directly sourced from black market reseller domains directly.

The experiment

How the keys were exposed

For realism we initially created GitHub projects spanning a wide array of types: ticket triage, document indexing, agent tools, and other AI applications. To make our accidental leaks seem realistic, we included a working key and our gateway’s URL in code examples in the repositories.

In order to  make our honeypot more attractive we advertised multiple SOTA models including astra, fable, opus 5 and sol. The attacker prompts were routed to hosted open-weight models in order to control costs while providing a believable attack surface. We also included guardrails that ensured model specific questions wouldn't reveal the true identity of our model and instead provide a facade that they were actually interacting with a SOTA frontier model from a company gateway. 


NYCLiteLLM-style gateway36 days
SFOSeparate model router9 days

We ran New York gateway for 36 days; San Francisco ran for nine as it was set up later, so the totals weren't equal as one had more time to collect "users".

The keys were released in waves in order to be more realistic. The table below shows us how long the keys were publically available to attackers.

How long the keys had been public at the snapshot cutoff
Exposure timeKeys
Less than a day19
One to seven days91
More than a week64
No precise publication time5

What we tracked

To ensure that we could extract as much from our honeypot as possbile we recorded as much signal las possible including: the key used, headers, referrers, ip, geoip, route, model, prompts, http status and more. We also saved every prompt and its response for further analysis.


The snapshot contains traffic from both gateways. Here is what the three counts mean:

  • 1,605,260 saved request captures across all endpoints.
  • 1,417,507 captures from prompt endpoints, including rejected requests.
  • 9,375 prompt requests using keys matched to our 179 documented leaks, counted in the request logs.

The 9,375 figure is the documented-leak subset, not the total prompt volume. Most captured traffic used credentials we could not match to those publication records.

Published-key use

Which leaked keys were used?

In total we published 179 keys. Outside requests used 65 to fetch the model list and 18 to send prompts. Requests using 16 keys returned HTTP success. We compared the projects and leak locations to investigate the difference.

9,375prompt requests using our published keys
4,711prompt requests returned HTTP success
80recorded source addresses behind those successes

A model-list request checked the advertised catalog; a prompt request tried to use a model. In 82 IP/key pairs, the list check preceded the first successful prompt. The median gap was 37 seconds, measured between API requests, not from publication.

Leak location and project type

Which leak locations drew requests

We compared the projects, the files containing the keys, and the time each key had been public. The table covers three batches of 40 repositories. To give each key the same observation period, we counted only its first 24 hours after release.

Keys checked and used during their first day
Repository batchKeys releasedKeys checkedKeys used for prompts
Early developer projects · NYC40387
Utility projects · NYC40124
Utility projects · SFO4051

In the early batch, one source checked 37 keys within a minute of each release. These were model-list requests. The entire batch produced only seven prompt requests, all from another source repeating the same message. Broad collection did not lead to sustained use of every key it found.

The two utility batches let us hold several things constant. All 80 projects were Python tools, advertised gpt-6-sol, and contained a key beside the gateway URL in config/development.env. Yet only 17 keys were checked and five were used for prompts. The other 63 never appeared in our gateway logs during more than four days of observation.

The four New York utility keys used for prompts came from api-response-code-map, http-header-safety-check, pagination-field-check, and operation-id-audit. San Francisco’s came from cors-wildcard-credentials-check. They were all API-related tools. These projects differed in release order and organization, so we cannot tell whether their subject matter drove the selection.

File format may matter too. Six of the early batch’s seven prompt-tested keys came from Go projects with JSON configuration; one came from a Node project, and none from its 14 Python projects. All seven prompt requests came from one source. Language and file format changed together, so we cannot tell which affected that source’s choice.

We also tried other leak locations. A GitHub Gist key received eight prompt requests. Keys in two documentation pages and two downloadable starter archives received no gateway requests over roughly six days. One of six keys exposed in commit history was checked and used for prompt attempts. Those small groups show which surfaces produced observable use, but not which were scanned.

The newest keys had less time to be found: 19 had been public for less than a day. But 91 keys had at least three days of exposure without a request. All 64 keys whose first request we could time were checked within six hours of release. We did not retain repository crawl or download telemetry, so we cannot distinguish a key that was never collected from one that was collected and ignored.

Once a few keys were adopted, their repeated use dominated the traffic. Six keys accounted for 98.9% of prompt requests using our leaked credentials. Repeated use of these keys drove the request volume.

Requests with other credentials

The arithmetic question behind most captured prompts

A request can carry any string as its API key. We recorded those attempts even when authentication failed, so a saved prompt does not necessarily mean the sender had a working key. Many attackers tried to brute force over 100+ admin keys that didn't work. This relates to an original vulnerability with LiteLLM where many gateways shipped with a default admin key

What the repeated credential tests looked like

Prompt requests carried 93,100 nonempty credential values outside our publication records. Of those, 78,130 were only 1–16 characters long. 93.7% of prompt requests outside the publication match returned HTTP 401. Almost all of these attempts carried curl-labelled headers.

The clearest repeated pattern was this message:

Repeated credential checkExact submitted message
What is 483*927+1145? Answer with only the final number.

We captured 1,401,673 copies across 92,596 supplied credential values and 20 requested model names. None of those values matched our documented leaks. Replaying a fixed question while changing the token and model is consistent with automated credential and model testing.

Repeated use of our leaked keys

A key check described how a relay collected API keys

This source made 1,215 prompt requests using our leaked keys. Within that traffic, we recorded 21 copies of one exact message. We’re highlighting it because it described how a relay collected and managed API keys. It began:

“The relay pool keeps a small SQLite database of API keys collected from public channels.”

The prompt described a “relay pool”: keys and API connections managed by a gateway. The system would retry keys that had hit their quota once an hour, test all the keys every six hours, and update the gateway’s routing each day. It would choose connections based on throughput, response time, and account balance, and could block collection sources by chat title.

After that description, the only instruction to the model was Ответь одним словом: OK—“Answer with one word: OK.” The requests also carried the software label keypool in their user-agent header.

21copies of this exact message
5leaked keys used for these checks
3model names requested

Of those requests, 12 returned HTTP 200, 7 returned 429, and 2 returned 404.

This is the system described in the submitted prompt; we did not inspect the collector’s code.

Gateway connections

Following the traffic to an API relay

my.git.christmas resolved to an IP that was sending prompts to our API. Requests from that IP also mentioned the domain. Veridrop lists it as an OpenAI-compatible API relay.

Requests from the same IP referred to a fo2api deployment. Together, the DNS record and prompts linked the source to relay infrastructure, though they didn’t tell us how many users were behind it.

Evidence linking the recorded address to a relay
ObservationEvidence
Requests to our API618 HTTP-successful prompt requests used our published keys.
DNS matchmy.git.christmas resolved to the same address recorded in those requests when we checked.
Submitted contextRequests mentioned the domain and work on a fo2api deployment.

The older logs retain a forwarded source address, without a separate socket-peer record. The DNS and context matches support the link; they do not identify an operator.

Relay development and testing

Troubleshooting a relay through our gateway

The sender also used our gateway to troubleshoot fo2api. One prompt asked a coding agent to fix a production JSON tool-schema error affecting ChatCompletions, Responses, and Anthropic routes, and pointed it to specific backend files to inspect.

From a chat export into a gateway’s key pool

Earlier turns asked the agent to check keys from a chat export, find ones that could serve StepFun models, and add the working ones to a Sub2API-based gateway. NaraRouter’s endpoint appeared in the export and in the testing output. A generation probe returned 402, and a later account listing marked that connection as an error.

The user then supplied an OpenLux endpoint and key, asking the agent to check it and add it to the API. The following tool output included model tests, retries, and routing mappings. A later listing showed the OpenLux account as active.

An APIMart key came next, along with a request for auto-glm, auto-kimi, auto-qwen, and auto-stepfun: model names that would route requests between the best working models in each family. The APIMart test output reported 402 errors for insufficient balance, and its account was listed as an error.

A separate history from another IP included the CLIProxyAPI README. That task was to configure a coding agent to send service_tier: "fast" through the proxy. OpenLux and APIMart also appeared in the README’s sponsor list; those links were incidental to the documentation lookup.

These were instructions and tool results inside submitted histories, not calls from those providers to our gateway.

Telegram bot traffic

What Telegram histories revealed about the traffic

Telegram message metadata and earlier replies appeared in 88 captured requests from three recorded source addresses, including the source linked to my.git.christmas.

Another of those addresses was in Helsinki on Xorek-labelled hosting, in the AEZA network. It sent 31 of the captures containing Telegram conversation metadata. The submitted histories included 12 distinct sender IDs marked as non-bot accounts. This is the same source discussed in the hosting section; the location describes its server, not the people in the conversations.

The reply history highlighted telegram bot named @obed2021bot, with the same account ID across all three sources. In its public profile it is called “Обед” and advertises GPT 6 Astra Max along with free access to whomever has access. The message metadata from this bots requests also included two fields: guest_query_id and guest_bot_caller_user: Telegram fields for guest-mode bot interactions. Those fields give us enough evidence that we can say that Telegram conversations were being passed through an inference gateway to our system.

After removing duplicate message metadata, we found 29 distinct sender IDs marked as non-bot accounts. They appeared in 16 private chats and 10 supergroups. These are IDs in the conversation histories, not verified users. We have omitted personal identifiers.

Telegram fields in submitted historySelected fields; personal identifiers omitted
{
  "format": "telegram_message_context/v1",
  "message": {
    "reply_to_message": {
      "from": {
        "is_bot": true,
        "username": "obed2021bot"
      }
    }
  }
}

We couldn’t verify who operated the bot or whether our replies reached Telegram.

Browser testing

Testing our leaked keys from a browser

6 requests using our published keys carried a www.hvoyai.com referrer. Each returned HTTP 200 and used the default message in Hvoy’s current tester:

“Calculate 17 + 26. Reply with only the number.”

The tester takes an endpoint, key, and model name, then sends the request directly from the visitor’s browser. The matching prompt and browser headers point to visitor-side testing, not a request from Hvoy’s servers. We checked the current implementation; we don’t have a historical copy.

Following the test requests

A browser test led back to VPN infrastructure

Other requests from the IP behind the Hvoy tests included instructions for maintaining updates.listokdoma.ru. When we checked DNS, that domain and related subdomains pointed to the same IP. This links the recorded address to the VPN configuration in the prompts; it doesn’t link Hvoy to the VPN.

What we found at the recorded source address
ClueRecorded evidence
Domain matchlistokdoma.ru, manage.listokdoma.ru, and updates.listokdoma.ru resolved to the recorded IP when we checked.
VPN maintenance7 captured requests included system context naming updates.listokdoma.ru alongside Xray/3x-ui VPN setup and Nginx reverse-proxy maintenance. 3x-ui manages Xray proxies.
Coding agentRequests carried omp/18.3.1 headers and context describing Oh My Pi configuration and model roles.
Session handlingSubmitted instructions described skill and memory services that inject user_id, team_id, and agent_id from a session.
Request toolsOther requests from the same address carried browser and Python headers.

Using our published keys, the same recorded address made 155 prompt requests; 132 returned HTTP success.

Asked to review a coding agent’s actions

Some prompts asked for a safety score for a coding-agent action, formatted as <severity>N</severity>. They included commands, browser output, project instructions, and configuration from the session being reviewed. The commands were review material, not instructions to execute on our gateway.

Hosting infrastructure

Where the leaked-key prompt traffic came from

Of the 9,375 prompt requests using our leaked keys, network lookups classified 8,058 (86%) as coming from hosting infrastructure. The largest groups included Xorek, Hetzner, and the PLAY2GO and Liteserver networks.

Requests using our leaked keys came from 53 recorded autonomous systems (ASNs)—network identifiers used for internet routing. Another 2 requests had no ASN. The table shows the eight largest groups; the complete breakdown is below.

Largest recorded networks · leaked-key prompt requests
Network · exit countriesRequests · shareWhat the requests containedSoftware fingerprints
PLAY2GO INTERNATIONAL LIMITEDAS215439Finland, Sweden, The Netherlands2,65628.3% of total
  • 1,897 short prompts / liveness checks
  • 584 coding/agent indicators
  • 53 Telegram histories
  • 6 relay-maintenance context
  • Sub2API 1,575
  • claude-cli 336
  • Python urllib/urllib3 230
  • OpenCode 107
Other headers · 408
  • Other headers 120
  • curl 67
  • OpenAI Python SDK 57
  • Missing header 55
  • Bun 31
  • OpenAI SDK 26
  • Browser headers 24
  • OkHttp 7
  • Python aiohttp 6
  • Python requests 6
  • Go HTTP client 4
  • Node undici 4
  • Python HTTPX 1
AEZA INTERNATIONAL LTDAS210644Finland2,20823.6% of total
  • 1,088 short prompts / liveness checks
  • 963 coding/agent indicators
  • 31 Telegram histories
  • claude-cli 867
  • Sub2API 764
  • Python urllib/urllib3 347
  • OpenCode 55
Other headers · 175
  • curl 65
  • Missing header 31
  • Python aiohttp 30
  • Other headers 20
  • OkHttp 17
  • Browser headers 6
  • Bun 3
  • Python HTTPX 2
  • Node undici 1
LiteserverAS60404The Netherlands1,21513.0% of total
  • 457 short prompts / liveness checks
  • 21 copies of the key-collection description
  • 52 identity / limit questions
  • keypool 1,025
  • Go HTTP client 181
  • Python urllib/urllib3 9
Hetzner Online GmbHAS24940Germany97210.4% of total
  • 662 short prompts / liveness checks
  • 16 coding/agent indicators
  • 315 Reply exactly: ok checks
  • Zoltraak 591
  • Go HTTP client 381
JSC SelectelAS50340Russia5215.6% of total
  • 521 ping checks
  • Python urllib/urllib3 521
HOSTSLIM OUAS207083Estonia2282.4% of total
  • 140 short prompts / liveness checks
  • 15 identity / limit questions
  • 11 reasoning / arithmetic prompts
  • Browser headers 117
  • claude-cli 50
  • PowerShell 18
Other headers · 43
  • Python HTTPX 18
  • Python urllib/urllib3 13
  • Python requests 12
Blockchain Creek B.V.AS207994The Netherlands2012.1% of total
  • 201 hi checks
  • FelixKeyBot 201
U1 DIGITAL SERVICES LTDAS213877Finland, Germany1651.8% of total
  • 103 short prompts / liveness checks
  • 14 coding/agent indicators
  • 17 reasoning / arithmetic prompts
  • Browser headers 93
  • Python HTTPX 27
  • Python urllib/urllib3 22
  • Oh My Pi 10
Other headers · 13
  • Other headers 5
  • Missing header 4
  • OpenAI Python SDK 4

Shares use all 9,375 leaked-key prompt requests. Activity counts describe captured inputs, include rejected requests, and can overlap. Software fingerprints are sender-supplied header labels.

HTTP 2xx counts successful request statuses. ASN holders, hosting brands, and the people using their services are separate identities.

All 53 recorded ASNs
Complete network breakdown · all 9,375 leaked-key prompt requests
Recorded networkExit locationsPrompt requestsHTTP 2xx
PLAY2GO INTERNATIONAL LIMITED
AS215439
Finland, Sweden, The Netherlands2,656674
AEZA INTERNATIONAL LTD
AS210644
Finland2,208831
Liteserver
AS60404
The Netherlands1,215886
Hetzner Online GmbH
AS24940
Germany972689
JSC Selectel
AS50340
Russia521405
HOSTSLIM OU
AS207083
Estonia228165
Blockchain Creek B.V.
AS207994
The Netherlands201199
U1 DIGITAL SERVICES LTD
AS213877
Finland, Germany165142
Verizon Business
AS5650
United States15627
AS203087
AS203087
Kazakhstan151105
SERV.HOST GROUP LTD
AS207957
Poland1370
SMARTNET Germany GmbH
AS203446
France130107
OOO Post ltd
AS12494
Russia12984
DpkgSoft International Limited
AS215590
Finland8637
ZetServers
AS25198
France, Germany5049
IT7 Networks Inc
AS25820
United States4843
MSS LLC.
AS44843
Russia3535
ETERNITY INTERNATIONAL LIMITED
AS212743
Estonia, Germany, The Netherlands3432
Eons Data Communications Limited
AS138997
Japan2019
Amazon.com, Inc.
AS16509
Japan185
M247 Europe SRL
AS9009
Belgium, United Kingdom1717
Cloudflare, Inc.
AS13335
Estonia, Germany, United States159
Datacamp Limited
AS212238
Japan158
GTHost
AS63023
Switzerland1515
Baxet Group Inc.
AS26383
United States134
ISPCONNECTED CORP
AS398712
United States1313
PJSC Rostelecom
AS12389
Russia1212
MTS PJSC
AS13055
Russia1212
Black Mesa Corporation
AS46997
United States120
OneAsiaHost
AS59211
Singapore1010
ALEXHOST SRL
AS200019
Switzerland, The Netherlands87
Shenzhen Tencent Computer Systems Company Limited
AS45090
China77
Oy Creanova Hosting Solutions Ltd.
AS51765
Finland77
SKYDIGITAL TELECOM LTD
AS214143
France66
Datagio Systems Ltd.
AS218914
Estonia66
YES TELECOM TELECOMUNICAÇÕES LTDA
AS267038
Brazil66
eStruxture Data Centers Inc.
AS10929
Canada55
H2NEXUS CLOUD SERVICES - FZCO
AS215730
Germany55
UAB Cherry Servers
AS59642
The Netherlands44
NEXTTRANSLATE LTD
AS203614
Latvia33
Advin Services LLC
AS22295
Germany33
SkyNet Ltd.
AS35807
Russia33
NLS Kazakhstan LLC
AS200590
Kazakhstan22
Aztelekom LLC
AS28787
Azerbaijan20
Orgtechservice Ltd
AS56361
Russia22
Scalaxy B.V.
AS58061
Finland22
FREEDOM TELECOM LLP
AS58172
Kazakhstan22
ASN not recordedFrance22
GSL Networks Pty LTD
AS137409
Japan11
OVH SAS
AS16276
United States11
CONECTE MARECHAL
AS270371
Brazil11
GVA Cote d'Ivoire SAS
AS36924
Uganda11
PJSC Vimpelcom
AS8402
Russia11
TE-AS
AS8452
Egypt10

The total is 9,375 prompt requests and 4,711 HTTP successes. These are cached source-network observations, including access networks and proxies; they are not 53 identified attackers or hosting businesses.

European servers, Russian payment options

PLAY2GO and Xorek both advertise hosting accessible through Russian payment systems. Together, their recorded sources accounted for 4,950 requests (52.8%) using our leaked keys. That groups their payment offerings, not their ownership.

PLAY2GO lists ruble and euro prices, and its public channel advertises Russian cards and SBP payments. Its current website names a Dubai company, PLAY2GO - FZCO. The UK filing for PLAY2GO International, the name in our ASN records, lists a Ukrainian controlling shareholder.

Xorek offers Moscow and European server locations with ruble pricing and MIR/SBP payments. Its website identifies DpkgSoft International as the operator; that company’s UK filing lists a Russian resident with at least 75% ownership.

A sanctioned network behind the Telegram-linked traffic

One source connected from an address geolocated to Finland on the network of AEZA International, a U.S.-sanctioned hosting company. The Xorek-labelled traffic spans two ASNs: 2,208 requests on AEZA International’s AS210644 and 86 on DpkgSoft’s AS215590. Treasury describes it as the UK branch of Russia-based AEZA Group.

That is a documented connection to a sanctioned network. Our logs do not show who paid for these servers or establish sanctions evasion by PLAY2GO or Xorek.

Rostelecom’s AS12389 also appeared in the logs, with 12 leaked-key prompt requests, all returning HTTP success. Its OFAC listing carries narrower restrictions: Directive 3 prohibits U.S. persons from dealing in specified new debt with a maturity longer than 14 days or new equity. AEZA’s SDN designation is broader: its property under U.S. jurisdiction is blocked, and U.S. persons are generally prohibited from dealing with the company.

Half the prompt traffic came from two Finnish addresses

Two recorded addresses geolocated to Finland sent 4,749 requests—51% of the leaked-key prompt traffic. One was the address linked to my.git.christmas on the PLAY2GO network. The other was on Xorek-labelled hosting and also sent the Telegram conversation histories described above.

The larger Xorek source sent 2,208 requests under 23 model names. It mixed short checks with longer requests: 830 contained coding-agent system instructions. The network address therefore covered both automated checks and agent activity; its Finland location does not tell us where the users were.

The same check ran on Xorek and Hetzner

Two recorded addresses repeatedly sent Reply exactly: ok: 67 requests from Xorek-labelled hosting and 315 from Hetzner. All 382 carried a Zoltraak-labelled header, with one user message, no streaming, and a request for only five or eight output tokens.

The checks covered 11 model names and 6 leaked keys. The Hetzner address sent them to both honeypots. The matching prompt, header and request settings suggest shared checking software; they do not establish that the two addresses had the same operator.

Gateway capability tests

5,000 requests to find out what our gateway could do

A server geolocated to Buffalo, New York, on ColoCrossing hosting kept asking our gateway to edit a Python file, identify a cat, and find a marker buried in a long input. It repeated these tasks under different model names, checking what the endpoint could do.

Across 27 days with recorded traffic, it sent 5,036 prompt requests under 18 model names, plus 368 model-list checks. 3,254 prompt requests returned HTTP success.

The requests carried AutoGenX-Engine/9.1 headers. Their system instructions described an “internal routing and logging system” serving models “via OpenRouter.” We found that description in 172 captured requests. It describes the sender’s setup; it does not establish that OpenRouter sent the traffic.

There were only 183 distinct user messages in the captures. The repeated tasks explain much of the volume:

Repeated tests in this source’s captured requests
TestWhat the prompt asked forSaved checks
Model identityIdentify yourself precisely. Return a fixed JSON schema describing the model and its capabilities.813
File editingChange PORT from 8000 to 9090 in api_server.py and add TIMEOUT = 30.959
Function callingInvoke get_weather for the temperature in London.314
VisionIdentify the animal in an embedded cat photograph and return only its name.260
Long-context retrievalRecover CTX_64K_OK, a marker hidden in a long block of repeated text.288
BrowsingLook up a webpage’s title and return it as JSON.314

The coding test asked for a specific edit: change PORT from 8000 to 9090 and add TIMEOUT = 30. It supplied a Windows-style C:\work workspace and coding-agent instructions, then repeated the task under 17 model names. The histories contained no assistant or tool turns, so we could see the task being tested but not whether any resulting tool calls were executed.

Other tests checked images and long inputs. The roughly 77,000-character image payload was mostly an embedded JPEG. The retrieval tests hid a marker about 15% or 90% of the way through repeated filler text; the largest input contained 396,862 characters. In 283 requests, the sender asked for up to one million output tokens. That is a request setting, not measured consumption.

Another honeypot recorded the AutoGenX-Engine header family on model-API probes. Here, the repeated tasks show capability testing. We found no customer conversation histories, resale prices, or key-pool configuration in this source’s captures.

The recorded reverse-DNS name was sportsmanslocker.com, but forward DNS did not match the source address when checked. We have not identified the operator. Its credential did not match our publication records, so these counts are separate from the leaked-key totals.

Access checks

What happened after a key worked

The requests also showed how people tested the keys: trying different model names, repeating a check on a schedule, or using the same key from several addresses. In the examples below, we’ve replaced IPs with labels that apply only within each example. We estimated start times from completion timestamps and latency, including time spent waiting in the gateway.

Model checks

One greeting, 29 model names

One IP used a published key to send hi while requesting 29 different model names. The requests started within about 27 seconds, and all returned a successful HTTP status.

Prompthi
Estimated time offsetRequest
+0.000sSource A · claude-fable-5-1 · HTTP 200
+0.005sSource A · gpt-4o · HTTP 200
+0.007sSource A · gpt-6-luna · HTTP 200

29 model checks in about 27 seconds

One IP sent the same greeting to each model name.

29 model names checked by 27 seconds

The line counts requests by estimated start time. It shows when the checks began, not when replies arrived.

We found 38 sessions lasting no more than ten minutes where one IP/key pair sent the same message under at least five model names.

Scheduled checks

A working key was checked roughly once an hour

In another series, one IP kept sending ping with the same key and model name. We recorded 95 successful requests across 5 observed days. The requests carried a Python urllib header.

Promptping
Estimated time offsetRequest
+0h 00m 00sSource A · claude-opus-5-5 · HTTP 200
+1h 00m 25sSource A · claude-opus-5-5 · HTTP 200
+2h 01m 29sSource A · claude-opus-5-5 · HTTP 200

The time between checks stayed close to an hour

One source IP, one published key, one model, the same ping prompt.

The intervals use estimated start times. The requests span parts of five days.

We also saw roughly five-minute checks carrying a “sub2api” header. The public Sub2API gateway includes scheduled model checks, but the header alone doesn’t tell us which deployment sent these requests.

We saw 23 IPs return on later days, out of the 80 that sent successful prompts with our published keys. Of those, 3 appeared on seven or more days.

Use from several addresses

Seven IPs used the same key within a minute

In one burst, 7 source IPs used a single published key to send 10 successful checks under 10 model names.

Promptliveness
Estimated time offsetRequest
+0.000sSource A · gpt-5-mini · HTTP 200
+0.879sSource B · gpt-4.1 · HTTP 200
+1.584sSource C · o3 · HTTP 200

Every request carried a curl header and the same 8-character message: liveness. Response recording had not begun; the success statuses come from request metadata.

The IPs could belong to several users or to one script using several network exits.

The same key check appeared from eight countries

A key we had planted in payloadgrove-dev/http-header-safety-check appeared in 23 successful requests from 8 recorded source addresses. Every request used the same 24-character message and an undici header. Together, they checked 17 model names in about 30 minutes.

The matching key, message, and header suggest coordinated testing. The recorded addresses geolocate to eight countries; the logs do not separately verify the socket peers.

Scripts, tools, and timing

Recognizing scripts and tools in the request headers

We examined the 4,711 successful prompt requests using our published keys. They came from 80 distinct source IPs, using a mix of scripts, browsers, and named tools.

The user-agent header often named a library or tool. The sender can change it, so we checked the labels against request behavior and public software.

Named tools1,553 requests · 5 source IPs
Python urllib / urllib3703 · 19 source IPs
Go HTTP library409 · 3 source IPs
Browsers302 · 15 source IPs
curl272 · 32 source IPs

The chart shows the most common header categories, not every request. An IP can appear in several rows.

The named-tool row covers “keypool,” “Zoltraak,” and “sub2api.” We looked for public software that could explain these labels:

What those software labels mean
Name in the headerWhat we could establishWhat we saw in our traffic
Sub2APIAn open-source gateway that turns access to AI subscription accounts and upstream API keys into an API for its users. It handles authentication, routing, and billing. Its monitoring code checks whether upstream models answer.2,421 prompt requests carried the label; 320 returned HTTP success. Some short checks were roughly five minutes apart. We haven’t identified the deployment sending them.
keypoolKey pooling means managing multiple API keys through one program or gateway. Public projects such as llm-keypool do this. We found no verified code match for the software sending these requests.1,060 labelled prompt requests; 823 returned HTTP success. Alongside short checks, requests carrying this label included the recurring collector description.
ZoltraakWe couldn’t identify the software behind this label. A separate gateway operator also reported a ZOLTRAAK header while investigating an exposed AI gateway.675 labelled prompt requests; 410 returned HTTP success. These included short checks and prompts asking for a value that changed with each request.

Daily activity

How leaked-key use changed over time

We tracked the keys we leaked on GitHub to see how they were used. The chart shows all 11,841 requests using those keys: model-list checks, prompts, and failed attempts.

Requests using published keys

Daily counts from September 6 through the October 11 snapshot (UTC). The vertical axis uses a logarithmic scale.

Sep 6Oct 11

Operator takeaways

What to look for in your own gateway logs

The examples give us three patterns to investigate when grouping gateway requests by credential:

  1. Many model names requested through the same key in a short window.
  2. Repeated checks at a stable interval after a key has already worked.
  3. A change in the addresses using a key, especially during a burst of prompt requests.

Compare these patterns with your own SDKs, load balancing, and monitoring before treating them as abuse. A stable identifier lets you group requests without storing the raw key. We haven’t measured detection accuracy or false positives.

Methods

How we counted and linked the requests

Scope. Aggregate counts use the October 11 snapshot and only keys backed by our publication records. Known owner traffic, including our Israel and Westfield addresses, is excluded. The eight-address test comes from a separate 24-hour capture ending October 12; its counts are not added to the frozen totals.

Capture. Response recording started partway through the study. HTTP success comes from request metadata and does not establish answer quality. Older captures could truncate long text.

Attribution. Headers and conversation histories are supplied by the requester. A DNS match corroborates a recorded address, not a person. Older logs did not separately retain socket peers, so forwarded addresses cannot all be independently verified.

Labels. Coding and agent categories use lexical indicators in the latest user message. Embedded instructions, tool results, and Telegram fields are submitted context, not independently authenticated activity.

Exposure. Keys were published in waves and had different amounts of time to be found. New York and San Francisco also had different observation windows and API surfaces. The totals describe this experiment, not a geographic comparison or a general leak rate.

InferTrail

Seeing similar patterns in your gateway logs?

I’m happy to compare notes on what you’re seeing and which signals are available in your gateway metadata.