Security and permission model

July 31, 2026 · View on GitHub

English | 简体中文

Security is layered. MCP authentication, exact operation authorization, capability visibility, query safety, transport policy, and Apache Doris RBAC each protect a different boundary. Enabling one layer does not remove the need for the others.

Trust model

Network and proxy
  -> HTTP Host/Origin/TLS policy
  -> credential authentication
  -> MCP operation scope
  -> domain discovery scope
  -> exact child execution scope
  -> provider allowlist and capability gate
  -> SQL/identifier/result guard
  -> request-specific Doris identity and RBAC
  -> sanitized bounded response

The MCP Server is not an authorization proxy that can grant more data access than Doris. Doris remains the final authority for catalogs, databases, tables, columns, rows, UDFs, audit metadata, and system views.

Authentication modes

Anonymous local development

Unauthenticated HTTP is permitted only on a loopback bind under the default policy. It is not a production mode. Non-loopback startup without an enabled authentication method fails unless the operator sets the explicit dangerous ALLOW_UNAUTHENTICATED_NON_LOOPBACK=true override.

stdio relies on the local process boundary and environment supplied by the Host. Protect local environment variables, config files, and process access.

Static bearer tokens

Enable with ENABLE_TOKEN_AUTH=true. Static tokens are validated at the MCP boundary and can be bound to a dedicated Doris route. Persisted token records use self-describing SHA-256/SHA-512 digests and atomic owner-only writes; plaintext legacy records are migrated one way.

The optional HTTP token-management interface is disabled by default and must remain localhost-only, IP-restricted, and protected by a separate high-entropy admin credential. Admin credentials belong in headers, never query strings.

JWT

Enable with ENABLE_JWT_AUTH=true and configure the expected issuer/key/ algorithm boundary. Private signing keys and shared secrets must be injected from a secret manager or protected process environment. Do not store real keys in the repository.

External OAuth 2.0/OIDC

Enable external access-token validation with ENABLE_OAUTH_AUTH=true. Tokens must pass trusted issuer, audience/resource, lifetime, active-state, and exact scope validation before optional user information is accepted. An invalid or insufficient token returns a standards-aligned Bearer challenge without exposing provider internals.

Email/domain-to-role mappings are normalized and validated. Domain elevation requires verified identity evidence; fallback mappings do not silently widen exact child scopes.

Doris-backed OAuth

ENABLE_DORIS_OAUTH_AUTH=true provides an OAuth boundary whose resulting request identity owns a Doris user connection pool. It requires HTTP, a configured service account, a public resource/base URL, and WORKERS=1 in 1.0. External OAuth and Doris-backed OAuth are mutually exclusive.

Authorization codes, access tokens, clients, and user pool state are process-local. Access tokens are bound to the canonical MCP resource. Required RFC resource values, redirect policies, PKCE/client rules, and application type are validated. Raw Doris passwords are not persisted in the token store.

Database-backed child access is disabled by default and uses explicit feature-ID allowlists and exact scopes when enabled. A Doris OAuth token cannot silently fall back to the global service account for a protected data call.

Exact authorization

Authorization is performed more than once:

  1. MCP operation: for example list_tools, call_tool, read_resource.
  2. Domain discovery: whether the identity can learn about a child.
  3. Child execution: exact policy such as child:call:doris_query:execute_query.
  4. Channel/provider: whether Doris OAuth, semantic, ADBC, MetricFlow, or custom provider access is enabled and allowlisted.
  5. Doris RBAC: whether the selected Doris identity can execute the actual statement or read the actual metadata.

OAuth paths require exact domain/child scopes. Wildcard guesses and pre-1.0 tool scopes do not grant access. Discovery does not imply execution. Unauthorized children are filtered from manifests and execute as not found to avoid capability-name disclosure.

Doris identities and connection routing

The route manager selects credentials in explicit order:

  1. Doris OAuth request identity and its user-owned pool;
  2. static-token-bound Doris configuration;
  3. global service account for configurations that permit it.

Pools are isolated by canonical route identity. Timeout, cancellation, credential mismatch, or unsafe owner/pool state fails closed rather than falling through to a more privileged pool. Query, metadata, FE HTTP, and capability evidence must remain aligned to the same request route.

Use a dedicated least-privileged Doris account for every trust boundary. See Doris fine-grained access control for grants, row policies, and token-bound examples.

SQL and identifier safety

The built-in 1.0 domains are read-only. doris_admin is not registered.

The shared query guard:

  • parses and accepts one supported read-only statement;
  • rejects DDL, DML, administrative commands, stacked statements, comments or constructs that violate policy, and malformed parameters;
  • validates/quotes catalog, database, table, column, function, and metric identifiers;
  • binds caller values instead of concatenating them where the driver permits;
  • checks query target SQL used by Explain/diagnosis as well as direct queries;
  • applies timeout, row, serialized-byte, depth, collection, and text limits;
  • classifies timeout/read-only/argument/backend failures without returning raw backend exception text.

Structured Search never accepts arbitrary filter SQL or a raw search DSL. Allowlisted FE/BE HTTP clients validate configured destinations and prevent caller-controlled SSRF targets.

Result and metadata safety

  • Configured masking rules run before model-facing results are returned.
  • Sensitive table/column policies can restrict or transform data.
  • Raw SQL, client addresses, authentication mappings, object locations, catalog properties, Variant samples, and backend errors are removed or bounded where the domain contract does not require them.
  • Query results, tool inputs, and structured outputs have absolute size/depth limits.
  • Schema validation errors report paths and keywords, not rejected secret values.
  • Trace baggage keys resembling credentials are redacted before propagation.
  • Public capability snapshots use stable reason codes and sanitized evidence, not connection strings or probe exception details.

Transport security

  • Bind local development to 127.0.0.1, localhost, or ::1.
  • Validate both HTTP Host and Origin to mitigate DNS rebinding.
  • A bind address such as 0.0.0.0 is not a public hostname allowlist.
  • Use HTTPS when traffic leaves the machine.
  • Configure trusted proxy CIDRs before accepting forwarded identity/scheme headers; never trust proxy headers globally.
  • Keep credentials in authorization headers or protected environment/secret mounts, never URLs.
  • Run the management interface separately from ordinary MCP access policy.

State and secret handling

  • MCP state handles are HMAC signed, principal/scope/expiry bound, and contain no credentials or query data.
  • Set a shared high-entropy MCP_STATE_HANDLE_SECRET only when independent replicas share traffic; rotate it as a deployment secret.
  • Token digests are not reversible bearer credentials.
  • Logs use redacted credential DTOs and safe representations.
  • Do not enable debug logging that serializes request headers or environment secrets at the reverse proxy or process supervisor.
  • .env, token files, OAuth client files, JWT keys, private Ossie binding manifests, and MetricFlow projects/provider commands require owner-only access and must not be committed when they contain private definitions.

Custom providers

Only installed entry points named in MCP_TOOL_PROVIDERS load. Provider names, tool names, schemas, lifecycle, audit metadata, and bounded rate limits are validated. Startup fails closed on an invalid allowlisted provider. Provider tools cannot shadow built-in tools or silently inherit built-in authorization.

Review Custom tool providers before enabling an extension.

Security limitations in 1.0

  • Doris-backed OAuth is single-worker and process-local.
  • Process-local custom-provider rate limits are not a distributed quota.
  • ADBC is default-off, requires explicit user intent on every call, and is fail-closed for token-bound routes because the Flight client is process-global.
  • The MetricFlow sidecar receives model requests but no Doris credentials. It compiles SQL only; the MCP read-only guard, request route, Doris RBAC, and result limits remain mandatory.
  • Native lineage delivery is asynchronous best effort; it is evidence, not a transactional authorization source.
  • Application-level SQL guards do not replace Doris grants and row policies.
  • Public reverse-proxy host/origin shapes require explicit validation and are not made safe merely by binding 0.0.0.0.

Production checklist

  • Use TLS and an authenticated non-loopback deployment.
  • Use least-privileged Doris accounts and test negative grants.
  • Select one intentional authentication mode and validate exact scopes.
  • Keep token-management endpoints disabled unless actively administered.
  • Store secrets outside source control and verify filesystem permissions.
  • Configure only trusted FE/BE/provider endpoints.
  • Verify /live and /ready separately.
  • Run read-only and permission-denial regression tests against the target Doris patch.
  • Review availability reason codes after upgrades.
  • Monitor audit logs without logging bearer values or raw sensitive data.