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 byDocumentation 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.
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 themcp-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; theauth-sdk / OAuth protects the caller’s identity.
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.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.
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.
Schema Validation
The webhook payload is validated against the Pydantic/Zod schema for the declared event type before any processing begins.
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"}.Audit
Every received webhook — whether accepted or rejected — generates an
audit_event with the source, event type, signature validity, and decision.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
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.| Threat | Mitigating Control(s) |
|---|---|
| Prompt injection in documents | Cloud blocked by default; human review gate |
| Tool injection | Tool allowlist; CLI sandbox |
| MCP abuse | Tool allowlist; auth-sdk; centralized authorization via mcp-auth-service; risk_level evaluation; scopes per operation |
| Sensitive data leakage | Secrets outside repository; Docker private networks; structured logs with redaction |
| Arbitrary command execution | CLI sandbox; tool timeouts; tool allowlist |
| Dangerous SQL queries | SQL view allowlist; DB readonly user; Pydantic/Zod validation; SELECT-only enforcement in mcp-readonly-sql |
| Permission escalation | Minimum permissions; model allowlist; risk_level per operation; scopes per operation |
| Forged webhooks | HMAC for webhooks; timestamp; optional nonce; schema validation; rate limit |
| Malicious document re-indexing | Audit trail; human review gate |
| Public exposure of internal services | Docker 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 leakage | Database separation; separate migrations and backups |
| Tokens in query string or logs | Authorization: Bearer required; auth-sdk log redaction |
| Stale JWKS | Rotatable 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.