Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
Tools/GitHubGitHub/squeeze440/inference-gateway-poc
Vulnerability AnalysisExploitationWeb SecurityPenetration TestingAuthenticationAPI Security
GitHubsqueeze440/inference-gateway-poc

inference-gateway-PoC

PoC — cross-origin requests reuse the configured provider API key in inference-gateway (GHSA-5293-fcm6-fh8v, CVE-2026-87009, CVSS 5.4).

View Repository
12h 22m agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

inference-gateway: security advisory

ResearcherDostxodjayev Abdullox (@squeeze440)
AdvisoryGHSA-5293-fcm6-fh8v
CVECVE-2026-87009
CVSS 3.15.4 (Medium) — CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:L
WeaknessCWE-352, CWE-306, CWE-346
StatusFixed in v0.46.0

Summary: inference-gateway binds to 0.0.0.0 and ships authentication disabled (AUTH_ENABLED=false) by default, and its ANY /proxy/:provider/*path passthrough route unconditionally strips any caller-supplied Authorization header and replaces it with the gateway operator's own server-configured provider API key before forwarding upstream, with no CORS policy and no CSRF protection of any kind, allowing any web page a victim's browser visits to silently drive billed LLM requests through the victim's own OpenAI/Anthropic/etc. account.

Product: inference-gateway/inference-gateway — self-hosted, cloud-native LLM gateway (Go, Gin).

Tested version: commit 6677da6afd0a606899f833c2351635edeef386f5 (main, 2026-08-04). Affected: <= 0.45.0.

Details

Three independent facts combine into the bug.

1. Auth is off and the bind is public by default. config/config.go:77 — AuthConfig.Enabled defaults to false. config/config.go:94 — ServerConfig.Host defaults to 0.0.0.0. With auth disabled, NewOIDCAuthenticatorMiddleware (api/middlewares/auth.go:27-30) returns OIDCAuthenticatorNoop, whose Middleware() (api/middlewares/auth.go:48-52) is a pure passthrough. There is no per-request identity check on any route in this mode. The quickstart examples/docker-compose/basic/docker-compose.yml publishes 8080:8080 with no AUTH_ENABLED set, so the documented getting-started path produces exactly this configuration.

2. /proxy/:provider/*path always injects the operator's own provider key. api/routes.go:102-131 (ProxyHandler) calls applyProviderAuth, api/routes.go:287-312:

root@kitploit:~
func applyProviderAuth(req *http.Request, provider core.IProvider) error {
	req.Header.Del("Authorization")          // caller's own Authorization header is discarded
	token := provider.GetToken()             // the operator's configured key (env var, e.g. OPENAI_API_KEY)
	switch provider.GetAuthType() {
	case constants.AuthTypeBearer:
		req.Header.Set("Authorization", "Bearer "+token)
	...

There is no code path where the caller's own credential is used; the design always substitutes the gateway's configured key. Combined with fact 1, an unauthenticated caller gets the operator's real key attached for free.

3. No CORS policy and no CSRF protection exist anywhere in the middleware chain. cmd/gateway/main.go:271 builds the router with gin.New() (no default middleware); the chain (:273-290) is otel → logger → telemetry → OIDC auth → guardrails → MCP. go.mod/go.sum contain no CORS package. No Access-Control-Allow-Origin header is ever sent. The proxy handler needs no custom header or CORS-unsafe Content-Type to work (it forwards the raw body, then overwrites the outbound Content-Type to application/json at api/routes.go:254), so a "simple" cross-origin fetch() (Content-Type: text/plain, no custom headers) is sent by the browser with no preflight. The server-side billed request completes independent of the browser's read-side CORS enforcement.

Net effect: any origin a victim's browser visits, while the gateway is reachable from that browser (loopback, LAN, or public if the operator followed the documented 8080:8080 publish pattern), can drive arbitrary attacker-chosen chat completions through the operator's real provider account, with zero authentication and no user-visible indication.

Proof of concept

Dynamically confirmed end-to-end with a real Chrome browser making a genuine cross-origin request between two distinct loopback origins (gateway on 127.0.0.1, attacker page on 127.0.0.2). See poc/:

  • poc/attacker_site/attack.html — the exact page served from the attacker origin; its only action on load is one fetch() to /proxy/openai/chat/completions.
  • poc/mock_upstream.py — stands in for api.openai.com, logs the Authorization header, Origin, and body it receives.
  • poc/README.md — full run steps.

Observed: the cross-origin browser request (Origin: http://127.0.0.2:8000) reached the mock upstream carrying Authorization: Bearer sk-proj-VICTIM-REAL-BILLED-KEY-... and the attacker-chosen body {"messages":[{"role":"user","content":"CSRF-DRIVEBY-MARKER-8271"}]} — the attacker page never possessing, seeing, or being asked for any credential. Browser network inspection confirmed POST http://127.0.0.1:8081/proxy/openai/chat/completions [200] fired from the 127.0.0.2:8000 page. Full browser-driven evidence (network log, screenshot) is attached to GHSA-5293-fcm6-fh8v.

Impact

Any operator running inference-gateway with its documented default configuration has their configured provider API key(s) usable by any web page reachable to a browser that can reach the gateway's port, with no credential, cookie, or special network position beyond "can send an HTTP request to the gateway's address". Concretely: unauthorized billing/quota consumption on the operator's own provider account, driven blindly by any third-party website, ad, or compromised page the operator (or anyone on the same LAN) has open while the gateway is running. The browser blocks the attacker from reading model output (no CORS headers), so this is a blind forced transaction, not a read primitive.

Weaknesses

  • CWE-352 Cross-Site Request Forgery — an expensive state-changing action performed via a browser-issued cross-origin request with no anti-CSRF token, no Origin/Sec-Fetch-Site check, and no CORS restriction.
  • CWE-306 Missing Authentication for Critical Function — every route except /health has zero per-request identity check when AUTH_ENABLED=false, the documented default.
  • CWE-346 Origin Validation Error — no CORS policy or origin allow-list anywhere in the middleware chain.

Remediation

Fixed in v0.46.0 (maintainer hardened the defaults). Recommended measures:

  1. Require a custom, non-safelisted header on /proxy/:provider/*path (and other state-changing routes), which forces a CORS preflight for cross-origin callers and gives the gateway a place to enforce an origin allow-list. This closes the "simple request" bypass without requiring auth to be enabled.
  2. Change SERVER_HOST's default from 0.0.0.0 to 127.0.0.1, requiring explicit opt-in to a broader interface (as Ollama did for the same class of bug).
  3. Emit a startup warning, or refuse to start, when AUTH_ENABLED=false and SERVER_HOST is not loopback.
  4. Document the risk in README.md / Configurations.md.

Credit

Dostxodjayev Abdullox (@squeeze440)

Download Tool