이 보고서는 영어로 발행되었습니다.
llm-abuse · llmjacking · ai-infrastructure · inference-endpoint · self-hosted-llm · scanning · vpn-egress · go-http-client
Open Inference APIs Validated With Per-Model Canary Prompts
This is a validation run against internet-exposed self-hosted LLM inference APIs on TCP/11434: a Go HTTP client lists the models an endpoint advertises, then sends one throwaway echo prompt per model to confirm each one really generates text.
작성자 Davis Zheng·
TLP:CLEAR. Cleared for public release. Captured by the Kinryū Labs honeypot sensor network. Indicators below are defanged.
Executive summary
- 81echo prompts across two runs
- 12models checked one at a time
- 2 of 47scanners that sent canary prompts
- 6 min 21 sfirst canary to last prompt
Two sources inventoried an internet-exposed self-hosted LLM inference endpoint model by model, sending 81 one-line canary prompts whose only instruction was to echo a random token back. We observed activity from 29 September to 1 October 2026, one run on each of those dates, twelve advertised models each time, both behind commercial VPN egress and both presenting the library-default Go-http-client/1.1.
The tool asks the endpoint what it can serve, over the OpenAI-compatible listing route that common self-hosted runtimes expose on TCP/11434:
GET /v1/models
Then it posts to the chat completions route on the same port, one line per request. This was the first generation request:
Return exactly this text and nothing else: *_VERIFY_PJPMKT13XSSIBV
The fixed uppercase prefix names the runtime and is masked here as *; the 14-character suffix differs in almost every one of the 81 requests.
Only two of 47 distinct sources went on to test whether generation actually happens. The 47 performed model enumeration on TCP/11434 between 25 September and 2 October, and both figures are exact counts for that window. We assess the activity as the validation stage of an inference-access pipeline, the step public reporting places between discovery of unauthenticated AI endpoints and the use or resale of their compute. Sysdig’s LLMjacking work documents that step for credential validation and resale through proxy storefronts. We hold that at low confidence, and nothing here ties the activity to a named actor.
Key judgments
- Both runs were driven by the same tooling rather than by two unrelated scanners. The two sources used an identical one-line prompt template with a fixed uppercase prefix and a 14-character randomised token, the same Go-http-client/1.1 client, and the same two-step sequence of a model listing followed by at least one prompt per advertised model, with repeat prompts to the same model observed, producing 39 and 42 prompts over 12 models. Moderate confidence.
- The prompts exist to prove the endpoint genuinely generates text, not to get work out of the model. All 81 captured prompts instruct the model to echo back a random token and nothing else, with a different token in almost every request, so a cached or canned response would not satisfy the check. Not one prompt carries a task, a question or a system instruction. Moderate confidence.
- Only two of the 47 enumerators issued the echo-canary prompts that prove a model actually generates text; among sources that enumerate exposed inference endpoints, that check is rare. Between 25 September and 2 October, 47 distinct sources performed model enumeration on TCP/11434 and only these two issued the canary prompts; the busiest enumerator made 2,896 listing requests and sent no prompt at all. These are exact counts, not partial ones. Moderate confidence.
- The operator selected the exposed service rather than the host or its owner. Generation traffic from both sources was confined to the chat completions route on TCP/11434, reached after a request to the model listing route on the same port; the Belgian source also requested the runtime's native API routes there. Moderate confidence.
Timeline
- 2026-09-29 18:35 UTCSource in France requests the model listing on TCP/11434.
- 2026-09-29 18:35 UTCFirst canary prompt sent to the chat completions route.
- 2026-09-29 18:42 UTCLast of 39 canary prompts; the run lasted 6 min 21 s across 12 models.
- 2026-10-01 00:10 UTCSource in Belgium begins the same sequence with the same prompt template.
- 2026-10-01 00:20 UTCLast of 42 canary prompts from the second source; the run lasted 9 min 51 s across 12 models.
The session, in order
18:35:43 GET /v1/models
18:35:45 Return exactly this text and nothing else: *_VERIFY_PJPMKT13XSSIBV
18:37:13 Return exactly this text and nothing else: *_VERIFY_QGZSCYLZK0V1QB
18:37:42 Return exactly this text and nothing else: *_VERIFY_EX3LSI8GI86XCE
18:37:44 Return exactly this text and nothing else: *_VERIFY_LGXPA9UDC2N1RN
18:37:50 Return exactly this text and nothing else: *_VERIFY_MDEITL2ZRYI3VE
18:38:41 Return exactly this text and nothing else: *_VERIFY_1XG154MK0K38D4
The two runs, request by request
On 29 September at 18:35:43 UTC the French source issued its single model listing. That source is 138.199.15[.]173 at Datacamp, AS60068, tagged vpn by VirusTotal, which also records 10 of 92 engines calling the address malicious or suspicious and no passive DNS for it. Two seconds later the source began sending generation requests, and it sent the last one at 18:42:06.
The source prompted some models more than once inside that run. It sent a second canary prompt to the model that took the first generation request 88 seconds after the first,
Return exactly this text and nothing else: *_VERIFY_QGZSCYLZK0V1QB
and it sent one advertised model a second canary prompt two seconds after the first, at 18:37:42 and 18:37:44,
Return exactly this text and nothing else: *_VERIFY_EX3LSI8GI86XCE
Return exactly this text and nothing else: *_VERIFY_LGXPA9UDC2N1RN
A Belgian source repeated the exercise thirty hours later, at 00:10:11 on 1 October, against the same twelve models with the same template and token shape, and finished at 00:20:03; that source is M247, AS9009, also tagged vpn. It also requested the runtime’s native API routes on TCP/11434 alongside the OpenAI-compatible ones.
Table 1: The second run sent three more generation requests than the first and prompted the same twelve models.
| 29 September | 1 October | |
|---|---|---|
| Generation requests | 39 | 42 |
| Models advertised and prompted | 12 | 12 |
| Run duration | 6 min 21 s | 9 min 51 s |
Another address in the French /24, 138.199.15[.]158 at CDN77-Marseille, generated at least 486 events, recorded as SIP credential, registration and flood activity; that result was capped, so 486 is a minimum count.
The canary prompt
A randomised token inside a canary prompt cannot be satisfied by a cache, a static page, a captive-portal interception, or a stub that advertises model names it cannot serve, because only something that processes the prompt returns the token. At least one canary prompt went to each advertised model, and some models got more than one, so each run yields a per-model result.
Two other sources ran the commodity versions of this traffic in the same window. One sent 3,414 prompts consisting of the single word hi across several models. Another made 2,896 model-listing requests and no prompt at all. Neither sent a randomised token.
Tradecraft
The operator wrote the tool against the generic OpenAI-compatible surface and confined all generation to the chat completions route. The same tool works against any runtime implementing that surface, so it will find llama.cpp, LM Studio and vLLM deployments without modification.
The operator records which specific models an endpoint can actually serve, which makes the model the unit of the inventory and is what anyone intending to use or sell that capacity needs to know.
Both runs went through commercial VPN egress in two countries and two autonomous systems, each presenting the library-default Go-http-client/1.1. The operator managed only attribution of the source, leaving volume and content undisguised, which we read as an expectation that nobody reads prompt bodies.
One mistake in the tradecraft is the fixed uppercase prefix that every canary prompt carries before the random suffix. It exists so the tool can recognise its own successful echo when parsing replies, and it also makes the entire campaign greppable on one string for any defender who logs request bodies.
Both sources selected targets by exposed service. Neither requested anything on the hosts it reached except the inference routes. We read that confinement as interest in the model capacity the endpoint offers. Both stopped after the per-model sweep, and neither address appeared again, with no record of why.
In ATT&CK terms, the two sources carried out active scanning for vulnerabilities (T1595.002, the reconnaissance technique), and the consumption their validation prepares for maps to resource hijacking (T1496, the impact technique).
How we tested it
We ruled out two rival readings of the traffic. A published survey would have fingerprinted models from the unauthenticated listing route without consuming generation, and these two sources spent the 81 generation calls from VPN egress in two countries with no identifying user agent or contact string. Nor was the endpoint driving automated offensive tooling, as in 2026 reporting, because none of those prompts carries a task, a target, a system prompt or any multi-turn context. We could not separate one operator rotating exits from two customers of the same tool, because the two addresses share token format, client and run structure, and nothing we observed tells those explanations apart. We did not observe what the validated inventory was used for afterwards, so any later use or resale remains an inference from public reporting.
| Explanation | Test | Result | Verdict |
|---|---|---|---|
| The runs consume generation and do not self-identify, which is not the shape a research survey leaves | Whether the sources consume inference at all, whether they identify themselves, and how they compare with the other model enumerators seen in the same period | Both sources issued generation requests (39 and 42) rather than stopping at the listing; both presented a bare Go-http-client/1.1 with no contact string, and both addresses are tagged vpn by VirusTotal with no scanner-reputation or threat-intelligence record in the providers queried. The busiest enumerator in the same period made 2,896 listing requests and zero generation requests, which is the shape a survey leaves. What the validated inventory is used for afterwards was not observed, so any later use or resale remains an inference from public reporting rather than anything seen here. | Supported |
| A published survey of exposed inference servers explains the traffic | Compare against documented survey methodology, which fingerprints models from the unauthenticated listing route without consuming generation, and check for self-identifying client metadata | Published survey work enumerates model names from the listing route; these two sources went on to spend 81 generation calls, used commercial VPN egress in two countries 30 hours apart, and carried no identifying user agent or contact string. | Refuted |
| The endpoint was being used as a reasoning engine for automated offensive tooling, as in 2026 reporting | Read every captured prompt and count those carrying a task rather than a canary | 81 of 81 captured prompts are the same echo instruction with a randomised token; none contains a task, a target, a system prompt or any multi-turn context. | Refuted |
| One operator rotating VPN exits, rather than two users of a shared tool | Pivot the prompt template across all collected sources and compare client fingerprint, token format and run structure between the two addresses | The template appears from exactly 2 sources between 25 September and 2 October, in 2 hosting organisations and 2 countries, 30 hours apart, with identical token format, identical client and near-identical run structure (39 and 42 prompts, 12 models each). Nothing observed distinguishes a single operator changing exit from two customers of the same tool. | Inconclusive |
Hardening TCP/11434
If you run a self-hosted LLM runtime, bind it to the loopback interface or put authentication in front of TCP/11434. Where that has not happened yet, treat a model listing followed by one short canary prompt per advertised model as evidence that your endpoint is being inventoried for someone else’s use.
Whether validation leads to sustained generation
Whether a successful validation is followed by sustained generation from a different address is not known, and neither is whether the same canary template reaches llama.cpp, LM Studio and vLLM on their own ports.
By the numbers
Figures computed from the evidence and from enrichment lookups.
- Infrastructure. At least 1 other address in this /24 are active over 11 hours, but on different events: probably an unrelated busy block rather than one operator.
- VirusTotal relationships. The address sits with Datacamp Limited in FR. 10/92 engines call the address itself malicious or suspicious. VirusTotal holds no passive DNS for this address: nothing is recorded as having pointed at it.
Indicators of compromise
The 2 network indicators below are defanged; paths are given as observed.
Network
| Indicator | Context |
|---|---|
138.199.15[.]173 | commercial VPN egress (Datacamp, AS60068, FR) used for the 29 September validation run; shared infrastructure, not a dedicated attacker host |
194.110.115[.]19 | commercial VPN egress (M247, AS9009, BE) used for the 1 October validation run with the same prompt template; shared infrastructure, not a dedicated attacker host |
Host artefacts
| Indicator | Context |
|---|---|
Return exactly this text and nothing else: [uppercase runtime name]_VERIFY_<14 uppercase alphanumerics> | prompt body template; the prefix is a fixed uppercase string naming the inference runtime, the 14-character suffix is regenerated per request, observed suffixes include EX3LSI8GI86XCE, LGXPA9UDC2N1RN and MDEITL2ZRYI3VE |
Go-http-client/1.1 | user agent presented on both runs; the library default, unmodified, with no contact string |
Detection
Sigma
Echo-canary prompt to an OpenAI-compatible inference endpoint (request body logging required) (candidate).
title: Echo-canary prompt to an OpenAI-compatible inference endpoint (request body logging required)
status: experimental
description: Detects validation prompts that ask a model to echo a random token, used to confirm an exposed inference endpoint really generates text. Requires a proxy or gateway that records request bodies; plain HTTP access logs will not match.
logsource:
category: proxy
detection:
selection_path:
cs-uri-stem|endswith:
- '/v1/chat/completions'
- '/api/generate'
- '/api/chat'
selection_body:
cs-body|contains:
- 'Return exactly this text and nothing else'
- '_VERIFY_'
condition: selection_path and selection_body
falsepositives:
- Internal health checks that use echo prompts to confirm a model is serving
- Model evaluation harnesses that test instruction following
- Environments that do not log request bodies will never match
level: medium
Detection logic
- Model listing followed immediately by one generation call per advertised model (behavioural, candidate). From a single external source inside one short window: a GET to the model listing route on TCP/11434, then at least one POST to the chat completions route for each model name returned by that listing, sometimes more than one to the same model, each prompt under about 100 characters, with the next request following the previous answer within roughly a second. Alert on the fan-out pattern even without body logging: the discriminator is at least one generation call for every advertised model from an address that has never used the endpoint before.
- Unauthenticated inference port reachable from the internet (network, candidate). Alert on inbound established connections to TCP/11434, and to the equivalent ports used by other self-hosted LLM runtimes, from outside the management network. Any such connection is the precondition for this activity.
Remediation
- Bind the inference runtime to the loopback interface and reach it through an authenticated reverse proxy rather than exposing TCP/11434.
- Require an API key or mTLS on the /v1/* and /api/* routes at the proxy, and reject unauthenticated requests rather than serving them.
- Log request bodies at the gateway for inference routes, or at minimum log model name and token counts per request, so anonymous generation is visible at all.
- Rate-limit generation per source address and alert when one source exercises every model you serve within a few minutes.
- Review GPU and token-usage accounting for unexplained short bursts; a validation run is small, but the use that follows it is not.
MITRE ATT&CK mapping
| Tactic | Technique | Observed |
|---|---|---|
| Reconnaissance | T1595.002 Active Scanning: Vulnerability Scanning | A single GET to the OpenAI-compatible model listing route on TCP/11434 to enumerate the models an unauthenticated inference endpoint advertises, before any generation request. |
| Impact | T1496 Resource Hijacking | 81 generation requests issued to an unauthenticated inference endpoint with no credential, consuming model compute to confirm each advertised model works. |
References
- LLMjacking: Stolen Cloud Credentials Used in New AI Attack (Sysdig)
- LLMjacking evolved: attackers are using stolen AI compute to build offensive agentic tools (Sysdig, 2026)
Methodology and analyst notes
The conclusion rests on two runs, on 29 September and 1 October 2026, totalling 81 prompts and 2 model listings from 2 addresses. Only the request side is established: what the endpoint returned, and therefore whether the operator judged it genuine, is not known, and no claim here depends on it. Neither address has a record with the scanner-reputation or threat-intelligence providers queried, so those providers corroborate neither address as a known scanner; the VirusTotal engine verdicts reported separately are not covered by that statement. What the validated inventory is used for afterwards was not observed; the link to resale rests on public reporting about similar pipelines, not on anything seen here.
Still open:
- Whether a successful validation is followed by sustained generation from a different address.
- Whether the same template is used against llama.cpp, LM Studio and vLLM on their own ports.
Questions or corrections: [email protected].