Most recent
navigate open esc close Corpus index built 2026-06-07 23:58 UTC

← All engagement records

Host case May 15, 2026

alpha_miner Job Scheduler: 194.233.71.223 (Contabo SG)

Sector
Commercial

Date: 2026-05-15 Sector: commercial (quant trading bot platform + commercial proxy resale) Severity: CRITICAL (plugin-loader RCE-by-design + colocated unauth LLM + LLMjacking attribution-laundering risk) Operator confidence: low (Vietnamese-pattern usernames on Indonesian-domain-cluster host) Technical-exposure confidence: high (all claims reproducible from a single unauth GET)

Identity

  • IP: 194.233.71.223
  • rDNS: vmi2733226.contaboserver.net
  • ASN: AS141995 Contabo Asia Private Limited
  • Location: Singapore (Contabo Asia Pte Ltd, 8 Robinson Road / International Plaza)
  • WHOIS abuse: abuse@contabo.de
  • Passive DNS (HackerTarget) cluster on same IP:
    • aceservice.store
    • ackeliling.store (Bahasa Indonesia: “AC keliling” = mobile AC service)
    • jasatukangac.store (“jasa tukang AC” = AC repairman service)
    • liangserviceac.store
    • warungngopi.xyz (“warung ngopi” = coffee stall)

DCWF KSAT coverage

Auto-derived from DCWF AI work-role rule files (ksat-tag).

  • 672 (AI Test & Evaluation Specialist): K7003, K7004, K7044, S7068, S7070, S7075, T5858, T5904, T5919
  • 733 (AI Risk & Ethics Specialist): S7056, T5868, T5882, T5893, T5904
  • overlap (Common AI KSATs (all 5 roles)): K108, K1158, K1159, K22, K6311, K6935, K7003, K7048, K942, T5896

The passive-DNS cluster is uniformly Indonesian-language AC-repair brands. The platform user roster is thanhtu (admin) and cuongnv (user). Vietnamese-pattern names. These two attribution signals do not reconcile cleanly; cheap-tier Contabo VPS shared by an Indonesian operator with Vietnamese contracted developers is a viable read, multi-tenant noise is another.

Port surface (Shodan / nu-recon)

PortServiceStatus
22OpenSSH 9.6p1 Ubuntu 24.04management
8000FastAPI/Uvicorn “Job Scheduler” (alpha_miner)partial-auth (CRITICAL)
10000 / 10001 / 10003 / 10004 / 10007 / 100093Proxy HTTP proxyBasic-auth required (paid resale)
11000 / 11001 / 11002 / 11007Socks4Aopen
11434llama.cpp HTTP serverfully unauth (HIGH)

Stage 2 verification: auth posture per endpoint

EndpointMethodUnauth response
/api/stats/jobsGET400 "Permission denied: system" (enforced)
/api/usersGET200 — full user roster + roles
/api/users/meGET200{"id":0,"roles":[],"username":""} (anon, not 401)
/api/users/policyGET200 — full RBAC matrix
/api/pluginsGET200 — full installed-plugin list
/api/plugins/routesGET200 — plugin route mounts
/api/plugins/download/{name}GET200 (route defined; payload returned SPA-catchall in our probe — auth path needs further test)
/api/templatesGET200
/api/plugins/install/{package}POST405 to GET, route exists

Split-auth posture: the auth scheme (OAuth2PasswordBearer at /auth/token) is real and is enforced on at least one endpoint, but six discoverable endpoints serve sensitive data unauth. Per Insight #16, a 200 is platform identity, not auth state. Here the data-layer probe confirms each 200 is a real exposure, not a documented anonymous shape.

Critical finding: plugin loader RCE-by-design

Full unauth dump of /api/plugins:

[
  {"id":1,  "package":"plugins.sample_plugin.Plugin",                       "description":"Sample plugin version 0.1"},
  {"id":2,  "package":"plugins.backtest_model.Plugin",                      "description":"Sample plugin version 0.2"},
  {"id":6,  "package":"alpha_miner.plugins.UatUserCustomConfigPlugin",      "description":"custom config worker"},
  {"id":7,  "package":"alpha_miner.plugins.UatPreviewPlugin",               "description":"Uat Plugin for preview only"},
  {"id":9,  "package":"plugins.quant_engine_management_plugin.Plugin",      "description":"Lab version for custom config worker"},
  {"id":10, "package":"plugins.blog.Plugin",                                "description":"blog plugin"},
  {"id":11, "package":"plugins.crm.Plugin",                                 "description":"Simple CRM created by vibe coding"},
  {"id":12, "package":"plugins.discord_crawler.Plugin",                     "description":"Discord channel crawler"},
  {"id":13, "package":"subprocess.run",                                     "description":"test"},
  {"id":14, "package":"os.popen",                                           "description":"test"}
]

Entries id:13 subprocess.run and id:14 os.popen are standard-library Python execution primitives, not application plugins. Their presence in the production plugin registry with description test indicates the operator already verified the plugin loader accepts arbitrary Python module.attr strings as package paths. The plugin-install endpoint /api/plugins/install/{package} is therefore plausibly an unauthenticated host-RCE primitive. The loader path executes whatever Python import path it receives.

Restraint ethic: we did not invoke /api/plugins/install/, /api/plugins/reload/, or /api/templates/user/run/. The arbitrary-module-load capability is inferred from metadata only; the names ARE the finding.

RBAC matrix (unauth via /api/users/policy)

[["admin","*"],
 ["user","job"],
 ["user","field"],
 ["data","plugins.sample_plugin.Plugin:fetch_data"],
 ["crm","plugins.crm.Plugin:crm_admin"],
 ["crm","plugins.crm.Plugin:sales"]]

admin:* (wildcard) maps to user thanhtu. Any plugin admin path is reachable from that account.

llama.cpp colocation (port 11434, fully unauth)

GET /v1/models HTTP/1.1
→ 200 OK
{"object":"list","data":[{"id":"./models/BitNet-b1.58-2B-4T/ggml-model-i2_s.gguf",
 "object":"model","created":1778890128,"owned_by":"llamacpp",
 "meta":{"vocab_type":2,"n_vocab":128256,"n_ctx_train":4096,
         "n_embd":2560,"n_params":2741155840,"size":1836120640}}]}
  • Model: Microsoft BitNet-b1.58-2B-4T (1.58-bit-quantized 2B, CPU-only inference)
  • Context: 4096 tokens, single slot, custom BITNETAssistant: chat template
  • Endpoints exposed: /v1/models, /props, /completion (OpenAI-compatible)
  • Rate limit / quota / auth: none

The chatbot endpoint /api/chatbot/chat on the FastAPI app likely routes to this 11434 instance; the public-internet 11434 path bypasses whatever rate-limiting the chatbot layer applies.

LLMjacking attribution-laundering pattern (novel)

This host pairs a paid commercial 3Proxy SaaS (six HTTP-proxy ports requiring Basic auth) with an unauthenticated public LLM on the same VPS. A paying customer of the proxy service has anonymizing one-hop access to free inference: proxy_customer → 3Proxy:10000 → llama.cpp:11434, all on the same host, with the inference traffic plausibly attributable to either the proxy customer or the proxy operator depending on log retention. This is the first time this colocation pattern has appeared in the survey corpus.

Logged for cross-survey synthesis: commercial proxy + open LLM colocation as a candidate violation class.

JS-bundle extraction (Insight #19)

SPA bundle index-B7lvKXEa.js (105 KB) was pulled and grepped. No external API hosts (single-host stack, chatbot inference is local). Confirmed /api/* endpoint set matches the OpenAPI spec; no additional hidden surface.

Toolchain provenance (full 19-tool arsenal)

ToolResult
JAXEN13 assets ingested into empire.db
aimap13 open ports discovered; PHASE 2 fingerprint missed llama.cpp on 11434 (FP candidate — Insight #21-class? llama.cpp brand string was present in Server: llama.cpp header but aimap fingerprint did not trigger). Manual probe confirmed.
aimap-profileClassified: commercial, Contabo SG, rDNS vmi2733226.contaboserver.net, surface mapped
VisorGraph0 nodes (no rDNS-pivotable surface beyond vmi2733226.contaboserver.net; no SAN-rich TLS cert)
VisorBishopIP-shadow on 27 high-signal ports — no additional AI/ML platforms
VisorSDFull 21-dork audit across AS141995 Contabo Asia0/21 hits; this host is the only Contabo Asia node Shodan-visible with these exposures
VisorGoosegov-TLD density run; target is commercial Contabo so this is informational only (Indonesia .go.id has 6 gov-AI hosts in the index for context)
menlohunt[—] N/A — target on AS141995 Contabo, not GCP/redge
recongraph0 nodes (passive saturated, no graph)
nu-reconFull Shodan host card pulled — the load-bearing discovery tool for this case
VisorPlusFull passive recon; passive-DNS lane surfaced the Indonesian AC-service brand cluster
VisorLog3 events ingested into nuclide.db (port 8000, 11434, 10000)
VisorScubaAssessed full nuclide.db; this host’s just-ingested rows did not match the selector’s IP filter in this run (gap recorded — future: extend selector or re-ingest with the right shape)
BARESemantic exploit-match ranking: top matches ~0.42–0.49 cosine (low) — methodology-expected for first-party authz bugs, not commodity-CVE chains. Top matches: nomad_exec, lucee_scheduled_job, proxypro_http_get
VisorCorpus135-case finance-domain baseline corpus built (kept locally; not used against 194.233.71.223 per ethical-stop)
VisorAgentlist mode (vector catalog); [x] run mode — NOT fired at 194.233.71.223 per ethical-stop; VisorAgent’s active LLM exploitation is reserved for controlled/lab targets
VisorRAGrecall mode attempted (no LLM, no probes); ingest path requires embedding API key not configured for this run
VisorHollow[—] N/A — Windows-only
cortexAuth-context analysis: severity=critical, 10 ops / 10 violations, 7 context items
JS-bundle extractindex-B7lvKXEa.js pulled (105 KB); enumerated /api/* surface; no external API hosts

Remediation (operator-facing)

  1. Add Depends(get_current_user) to every router in /api/users/*, /api/plugins/*, /api/templates/*, the auth scheme is already defined; the failure is route-by-route omission.
  2. Restrict plugin install to an allowlist of permitted package roots, refuse any package string outside plugins.* and alpha_miner.plugins.*. The presence of subprocess.run and os.popen in the registry indicates the loader accepts arbitrary module.attr strings, which is host RCE.
  3. Add authentication to the 11434 llama.cpp listener, either bind to 127.0.0.1 only (and route through the FastAPI chatbot), or front it with nginx auth_basic / OAuth proxy.
  4. Separate the commercial proxy fleet from the inference workload, the colocation creates a paid-customer-to-free-LLM laundering path.
  5. Rotate the admin password for thanhtu, the username is publicly known.

Lessons / candidate insights

  • Candidate Insight #22 (or extend #21): aimap’s PHASE-2 fingerprint missed llama.cpp on 11434 even though the Server: llama.cpp HTTP response header was present in the Shodan banner. Worth a fingerprint review. Either the conjuncts are over-specified for this stack, or the probe path is wrong.
  • Candidate Insight #23: commercial-proxy + open-LLM colocation = LLMjacking attribution-laundering vector. First instance in the corpus; flag as a class to watch for.
  • Partial-auth-posture is its own failure mode: distinct from no-auth, distinct from auth-correct. Operators with partial-auth platforms believe they are protected. The verification gap (Insight #16) applies at the application-route level, not just the protocol level.

Files

  • ~/recon/194_233_71_223/openapi.json: OpenAPI spec (26 KB)
  • ~/recon/194_233_71_223/plugins.json: plugin registry dump
  • ~/recon/194_233_71_223/index.js: SPA bundle
  • ~/recon/194_233_71_223/nu-recon.json: full Shodan host card
  • ~/recon/194_233_71_223/aimap-profile.json: classification
  • ~/recon/194_233_71_223/cortex.json, cortex_report.md. Auth-context analysis (severity=critical)
  • ~/recon/194_233_71_223/visorbishop.json, visorbishop.csv. IP-shadow results
  • ~/recon/194_233_71_223/findings.ndjson: VisorLog-ingest payload
  • ~/recon_dump.json: JAXEN harvest (13 assets)