Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/joseluis-dev/harness-ai/llms.txt

Use this file to discover all available pages before exploring further.

Security in Harness AI is not a phase-based feature: every control listed on this page is mandatory from Phase 0. The controls are not additive options that harden an otherwise permissive default — they are the baseline below which no deployment of the harness is considered valid. They derive directly from the Threat Model and from the centralized authorization model introduced by mcp-auth-service, auth-sdk, and the dedicated harness_auth_db PostgreSQL instance.

Mandatory Controls

The following controls must be implemented before any agent, workflow, or external integration is activated.

Tool Allowlist

Every agent declares an explicit, bounded list of tools it may invoke. Any tool not on the allowlist is rejected before the MCP layer is reached. There are no wildcard grants.

Model Allowlist

Only models declared in the allowlist may be used by any agent or workflow. Cloud providers are excluded from this list by default; inclusion requires Phase 13 readiness.

SQL View Allowlist

mcp-readonly-sql only executes queries against views explicitly declared in the SQL view allowlist. Direct table access and cross-database queries are not permitted.

HMAC for Webhooks

Every incoming webhook must carry a valid HMAC signature computed over the payload. Requests without a valid signature are rejected before any business logic runs.

Tool Timeouts

Every tool invocation has a maximum execution time configured in tool_registry. Invocations that exceed the timeout are cancelled and logged as audit_event{type="tool.timeout"}.

Payload Limits

All HTTP endpoints and MCP tool calls enforce maximum payload sizes. Oversized payloads are rejected at the transport layer before reaching parsing or validation logic.

Pydantic / Zod Validation

All JSON payloads are validated at runtime against typed schemas — Pydantic v2 in Python services, Zod in Astro. Invalid payloads are rejected with a structured error response.

Docker Private Networks

All internal services run on private-harness-net. Only harness-core is attached to the public network. No internal service is reachable from the internet.

Secrets Outside Repository

No credentials, API keys, database passwords, or HMAC secrets are committed to the repository. Secrets are provided via Dokploy secrets manager or host environment variables.

Structured Logs

All services emit structured JSON logs. The auth-sdk automatically redacts bearer tokens and secrets before they reach the log sink. No plaintext credential appears in any log.

Minimum Permissions

Every agent, client, and service operates with the minimum set of scopes and database permissions required for its function. No implicit inheritance of elevated permissions is permitted.

DB Readonly User

The database user available to mcp-readonly-sql and all RAG-adjacent services holds only SELECT on the declared view allowlist. It cannot write, drop, or alter any object.

Human Review Gate

Actions with risk_level=DESTRUCTIVE or EXTERNAL_SIDE_EFFECT require explicit human approval before execution. Workflows are suspended until /aprobar or /rechazar is received.

Cloud Blocked by Default

allow_cloud=false is the hardcoded default. No request reaches an external cloud LLM provider unless the operator has explicitly enabled the provider under Phase 13 policy.

CLI Sandbox

The CLI Tool Runner executes commands in a sandboxed environment with an explicit binary allowlist and validated arguments. Free shell access from the model is prohibited.

Centralized Authorization Controls

The following controls are required by the mcp-auth-service + auth-sdk + harness_auth_db model introduced in the architecture. They are equally mandatory from Phase 0.

mcp-auth-service as Sole Authority

The mcp-auth-service is the only issuer and validator of tokens in the harness. No MCP server, CLI wrapper, HTTP integration, or external channel implements its own OAuth flow.

harness_auth_db Independent

The harness_auth_db PostgreSQL instance is always separate from harness_db. The two databases have separate connection strings, separate migrations, and separate backup schedules.

Authorization: Bearer Only

All tool invocations over HTTP must include Authorization: Bearer <access-token>. Tokens must never appear in query strings, URL paths, or request bodies.

401 with WWW-Authenticate

Every 401 response from a protected endpoint must include a WWW-Authenticate header with resource metadata and, when applicable, error="insufficient_scope" or error="invalid_token".

No Public Client Self-Registration

Clients are created exclusively via the admin panel (Phase 6+) or versioned database migrations. No public endpoint accepts client registration requests from unauthenticated callers.

risk_level Before Invocation

Every tool call evaluates the operation’s risk_level before executing. The six levels are: READ_ONLY, READ_SENSITIVE, WRITE, DESTRUCTIVE, ADMINISTRATIVE, EXTERNAL_SIDE_EFFECT.

Rotatable JWKS

Token validation uses a JWKS endpoint with key IDs (kid). The auth-sdk performs automatic key refresh. Rotated keys invalidate stale tokens without requiring service restarts.

Webhook Security Requirements

All webhook endpoints — whether receiving events from n8n, Telegram, or external integrations — must satisfy the following requirements simultaneously. HMAC and OAuth authorization are complementary layers, not alternatives: HMAC protects the channel integrity; the auth-sdk / OAuth protects the caller’s identity.
1

HMAC Signature

Every webhook request must include a signature header (X-Harness-Signature or equivalent) containing an HMAC-SHA256 digest of the raw request body, computed with the shared secret for that source.
2

Timestamp

A request timestamp must be included and validated. Requests with a timestamp outside the acceptable skew window (typically ±5 minutes) are rejected to prevent replay attacks.
3

Optional Nonce

High-security webhook sources may additionally include a per-request nonce. When present, the nonce is validated against a short-lived store to prevent replay even within the timestamp window.
4

Schema Validation

The webhook payload is validated against the Pydantic/Zod schema for the declared event type before any processing begins.
5

Rate Limiting

Each webhook source has an individual rate limit. Requests exceeding the limit are rejected with HTTP 429 and logged as audit_event{type="webhook.rate_limit_exceeded"}.
6

Audit

Every received webhook — whether accepted or rejected — generates an audit_event with the source, event type, signature validity, and decision.
7

Event Type Allowlist

Only event types declared in the event allowlist for that webhook source are processed. Unrecognized event types are rejected and logged.
Webhook sources (n8n, Telegram, external integrations) also authenticate to the mcp-auth-service as technical clients using Client Credentials. This means a webhook request must pass both HMAC verification and carry a valid Bearer token. Neither check alone is sufficient.

Hardcoded Prohibitions

Auth by MCP is prohibited. No MCP server, CLI wrapper, or HTTP tool integration may implement its own authentication or token issuance logic. All authentication is delegated to the mcp-auth-service via the auth-sdk. Any pull request that introduces independent auth logic in an MCP component must be rejected without discussion.
Auto-registration of clients is prohibited. No publicly accessible endpoint may accept new client registrations. Clients are created exclusively through the admin panel or versioned migrations executed by an administrator. Any PR that introduces a public /register or /clients POST endpoint accessible without admin credentials must be rejected.
Tokens in query strings are prohibited. Bearer tokens must never appear in URL query parameters, URL paths, or any part of the request that would appear in access logs. The only permitted location is the Authorization: Bearer header. Any logging, proxy, or integration component that captures full URLs would otherwise expose live tokens.

Threat → Control Mapping

The table below maps every threat from the Threat Model to the controls that mitigate it. Multiple controls may apply to a single threat; all listed controls must be active for the mitigation to be effective.
ThreatMitigating Control(s)
Prompt injection in documentsCloud blocked by default; human review gate
Tool injectionTool allowlist; CLI sandbox
MCP abuseTool allowlist; auth-sdk; centralized authorization via mcp-auth-service; risk_level evaluation; scopes per operation
Sensitive data leakageSecrets outside repository; Docker private networks; structured logs with redaction
Arbitrary command executionCLI sandbox; tool timeouts; tool allowlist
Dangerous SQL queriesSQL view allowlist; DB readonly user; Pydantic/Zod validation; SELECT-only enforcement in mcp-readonly-sql
Permission escalationMinimum permissions; model allowlist; risk_level per operation; scopes per operation
Forged webhooksHMAC for webhooks; timestamp; optional nonce; schema validation; rate limit
Malicious document re-indexingAudit trail; human review gate
Public exposure of internal servicesDocker private networks; exposure allowlist; mcp-auth-service and admin-panel without public exposure
Cloud model abuse (Phase 13+)Model allowlist; cloud blocked by default
Authorization bypass (auth-by-MCP, auto-registration)mcp-auth-service as sole authority; auth-sdk required; no public self-registration
harness_auth_db leakageDatabase separation; separate migrations and backups
Tokens in query string or logsAuthorization: Bearer required; auth-sdk log redaction
Stale JWKSRotatable JWKS with kid; automatic refresh in auth-sdk

Phase-Dependent Notes

All controls in this document are mandatory from Phase 0, with one exception: the cloud model abuse control (model allowlist + allow_cloud=false) only becomes operationally relevant when Phase 13 external providers are activated. The control itself must still be configured from Phase 0 — it simply has no cloud traffic to govern until Phase 13.

Build docs developers (and LLMs) love