LLM Proxies: Purpose and Security Policy

6 min read

Overview

Unique provides three authenticated passthrough proxies for clients and internal agent workflows that need provider-compatible APIs:

  • OpenAI proxy for OpenAI-compatible APIs: Chat Completions, Responses, model listing, image edits and Code Interpreter containers, including streaming, uploads, and binary responses.

  • Anthropic proxy for Anthropic-compatible Messages API requests, including regular and SSE streaming responses.

  • Cursor proxy for the subset of the Cursor API used by the Cursor SDK agent lifecycle.

These proxies let callers use provider-native request and response formats while Unique manages upstream credentials, model routing, usage attribution, limits, and security controls. Routes and request capabilities are checked before forwarding.

Provider-hosted tools deserve special attention because they execute under credentials held by Unique and may send prompts, files, or tool arguments to infrastructure outside Unique-controlled environments. The proxy policies therefore use explicit allowlists for tool capabilities and reject unknown typed tools by default.

Public endpoints and service location

Clients call the proxies below the Public API base path:

  • /public/chat/openai-proxy/{provider-path}

  • /public/chat/anthropic-proxy/{provider-path}

  • /public/chat/cursor-proxy/{provider-path}

All three proxies replace or supply the upstream authorization credential. Callers authenticate to Unique; provider credentials are kept in the backend.

OpenAI proxy

Purpose and routing

The OpenAI proxy exposes an OpenAI-compatible path surface. The requested model is resolved through Unique's OpenAI service factory, which selects the configured Azure OpenAI or LiteLLM-backed route. It supports normal JSON requests, SSE streaming, multipart uploads, and binary downloads.

Common examples include:

  • POST /v1/chat/completions

  • POST /v1/responses

  • GET /v1/models

  • Code Interpreter container operations and POST /v1/images/edits

OpenAI path checks normalize query strings, repeated slashes, trailing slashes, and encoded path segments before applying the security policy. Equivalent aliases such as /responses and /chat/completions receive the same checks as their /v1/... forms.

Tool and parameter policy (as of release .38)

For Chat Completions routes:

  • Allowed tool types: function, custom.

  • Blocked parameter: web_search_options.

  • namespace tools are rejected on Chat Completions; they are a Responses API construct.

  • The checks apply to both the top-level body and extra_body; therefore extra_body.tools and extra_body.web_search_options cannot bypass the policy.

For Responses and other OpenAI routes carrying tool declarations:

  • Allowed tool types: function, custom, apply_patch, local_shell, and code_interpreter.

  • shell is allowed only when environment.type is local.

  • namespace is allowed as a grouping wrapper only (Codex CLI 0.147 and later send their client-executed function tools this way). The namespace itself executes nothing. It must carry a tools array, and every nested tool is validated against the same client-executed allowlist as a top-level tool: hosted tools, hosted shell environments, and further nested namespace tools inside a namespace are rejected.

  • All other typed tools are rejected by default.

This blocks provider-hosted capabilities, whether declared at the top level, under extra_body.tools, or nested inside a namespace, such as:

  • mcp

  • web_search

  • web_search_preview, except Unique internal Deep Research when OpenAI is the research engine

  • file_search

  • image_generation and image_generator

  • computer and computer_use_preview

  • Hosted shell environments

code_interpreter and OpenAI container routes remain available by design for approved code-execution workflows. Allowing container routes does not allow blocked tool declarations to bypass body validation.

The integrated /integrated/chat/stream-responses flow applies the same Responses tool policy to its options before calling the upstream model.

Anthropic proxy

Purpose and routing

The Anthropic proxy accepts Anthropic-compatible requests and forwards them through the company-scoped LiteLLM route. It supports regular Messages responses and SSE streaming while preserving company-level usage and cost attribution.

Common examples include:

  • POST /v1/messages

  • POST /v1/messages/count_tokens

Tool and parameter policy (as of release .38)

Allowed capabilities:

  • Untyped custom tool definitions

  • Tool type custom

  • Tool type function

  • Tool types beginning with code_execution

Blocked capabilities:

  • mcp_servers, both top-level and under extra_body

  • Typed web search and web fetch tools

  • Typed MCP tools

  • Advisor and tool-search tools

  • Browser and computer tools

  • Bash and text-editor tools

  • Memory tools

  • Any other unknown typed tool

Tool declarations are checked in both tools and extra_body.tools. Anthropic code_execution* remains enabled by design for approved code-execution workflows.

Cursor proxy

Purpose and routing

The Cursor proxy supports the API surface required by the Cursor SDK to create, run, resume, and dispose agents. Requests are forwarded directly to configured Cursor upstreams with the platform-held Cursor credential:

  • Primary API: CURSOR_API_BASE_URL, defaulting to <https://api.cursor.com>

  • Authentication API: CURSOR_AUTH_API_BASE_URL, defaulting to <https://api2.cursor.sh>

Regular responses and Cursor's NDJSON streaming responses are supported.

Allowed routes

Cursor uses a route-and-method allowlist, like the OpenAI and Anthropic proxies. Unlike them, it cannot be extended per environment. Only these routes and methods are forwarded:

  • /v1/agents and descendant agent lifecycle routes: GET, POST, PATCH, DELETE

  • /v1/models: GET

  • /v1/me: GET

  • Exact route /auth/exchange_user_api_key: POST

Every other Cursor route or method is blocked. Cursor does not currently apply an OpenAI/Anthropic-style body tool filter; its security boundary is the narrow route-and-method allowlist required by the SDK.

Route security

OpenAI and Anthropic allowed routes (as of release .42)

The OpenAI and Anthropic proxies forward only the method-and-path pairs below. Paths are relative to the proxy mount. * matches exactly one path segment, such as a container or file ID.

OpenAI (each route also accepted with a /v1 prefix):

  • POST /chat/completions

  • POST /responses

  • POST /containers

  • GET /containers/*

  • GET, POST /containers/*/files

  • GET /containers/*/files/*/content

  • POST /images/edits

  • GET /v1/models (only with the /v1 prefix)

Anthropic:

  • POST /v1/messages

  • POST /v1/messages/count_tokens

Every other method or path is rejected with 403 before any upstream call. This includes the root proxy path, LiteLLM management routes (keys, spend, teams, users, organizations, settings), files, batches, assistants, vector stores, RAG ingest, MCP server registration, agents, and provider passthrough routes.

The allowlist applies at every entry point: the node-chat Public API routes, the node-chat internal routes, and the unique-api facades.

Before matching, paths are normalized:

  • the query string is ignored

  • the path is URL-decoded up to three times; deeper or malformed encoding is rejected with 400

  • repeated slashes are collapsed and a trailing slash is removed

  • paths containing . or .. segments are rejected

Extending the allowlist per environment

Operators can add inference routes without a new image:

  • OPENAI_PROXY_EXTRA_ALLOWED_ROUTES

  • ANTHROPIC_PROXY_EXTRA_ALLOWED_ROUTES

Rules:

  • Format: comma-separated METHOD /path entries, e.g. POST /images/generations,POST /v1/embeddings. * matches one path segment.

  • Allowed methods: GET, POST, PUT, PATCH, DELETE.

  • Paths exclude the proxy mount: /v1/messages/batches, not /anthropic-proxy/v1/messages/batches.

  • Set the same value on backend-service-chat and unique-api. A route allowed on only one service is still blocked on the other entry points.

  • Entries only add routes; they never remove built-in ones.

  • Entries whose first segment (after an optional v1) is a known LiteLLM management or provider passthrough root are rejected, for example key, spend, team, user, admin, vector_stores, rag, mcp, agents, openai, anthropic, azure, bedrock, gemini. The list is not exhaustive: only add inference routes.

  • An invalid or forbidden entry stops the service from starting. Kubernetes keeps the previous pods serving.

Cursor denied routes

For Cursor, every route not present in the allowlist above is denied. This prevents a caller from using Unique's Cursor credential against billing, account-management, administrative, or future Cursor APIs that have not been explicitly reviewed.

Rejection behavior

Security checks run before the upstream request is sent.

  • A route outside the allowlist is rejected with HTTP 403 and the body openai-proxy: upstream route not allowed (or anthropic-proxy: ...). The service logs an error openai-proxy.rejected_route / anthropic-proxy.rejected_route with user ID, company ID, method, and path.

  • A path with malformed or too deeply nested encoding is rejected with HTTP 400.

  • A malformed or disallowed request capability is rejected as a client error by node-chat.

  • The 2026-03-01 unique-api OpenAI/Anthropic facades may expose forwarded non-streaming proxy validation failures as HTTP 422 according to their upstream-error contract.

  • Streaming facades relay upstream status and body where supported.

The policy implementation and tests are the source of truth when provider APIs evolve.

Last updated