Skip to main content

OttoBot Security

Document statusPublic documentation
Target audienceEnterprise security & compliance teams
Last updated2026-08-21

This page describes how per-org OttoBot — the conversational assistant available to your organization inside Phoenix — is deployed, how data moves through it, how requests are authenticated and bound to your organization, and which controls keep one customer's activity separated from another's.

It is written for a security reviewer performing an assessment. For the broader Phoenix platform, see AI Governance; for the technical detail of input handling, redaction, and adversarial testing, see Security Guardrails.

Scope of this document

This document provides a technical and architectural overview of the per-org OttoBot integration. It describes current system design and operational practices.

This document is not:

  • A contractual agreement (see your HG Insights MSA for binding terms)
  • A substitute for HG Insights Corporate InfoSec documentation (SOC 2, penetration testing, etc.)
  • A guarantee of specific SLAs (see service agreement)

Specific contractual commitments, audit rights, and liability terms are negotiated separately in customer agreements.

Not covered here: embedding OttoBot in your own application via iframe. That surface has a separate authentication model and will be documented separately.

1. Integration architecture

Per-org OttoBot is a chat surface inside the Phoenix web application. It is not a separate product you log into, and it is not reachable from the public internet as a standalone service.

A conversation turn moves through three components:

┌──────────────┐     ┌─────────────────┐     ┌──────────────────┐
│ Browser │────▶│ Phoenix webapp │────▶│ OttoBot service │
│ (your user) │ │ (chat route) │ │ (in-cluster) │
└──────────────┘ └─────────────────┘ └──────────────────┘
▲ │
│ Phoenix MCP, as the │
└────────────────────────┘
end user
  1. Browser → Phoenix. Your user is authenticated to Phoenix by an ordinary session. The chat request goes to a Phoenix API route scoped to your organization.
  2. Phoenix → OttoBot. Phoenix authorizes the request (§3), mints a short-lived credential bound to that user and organization, and proxies the turn to the OttoBot service over in-cluster networking. The OttoBot service has no public hostname and is not reachable from outside the cluster.
  3. OttoBot → Phoenix. To answer, OttoBot calls Phoenix's MCP data interface under the end user's identity, using a second short-lived credential. It cannot see data that the signed-in user could not already retrieve in Phoenix directly.

1.1 Shared multi-tenant deployment

Per-org OttoBot runs on a shared multi-tenant service. One process serves many customer organizations. Your organization does not receive a dedicated instance, and we do not currently offer a dedicated-instance tier.

Separation between organizations is logical and enforced per request: every turn resolves its own organization context from a validated credential, and the controls in §4 are applied on that per-request basis rather than being fixed when the service starts. §4.3 states the residual characteristic of this model honestly.

ComponentProviderRegion
Phoenix webappHG Insights (AWS EKS)US
OttoBot serviceHG Insights (AWS EKS)US
DatabaseNeonDB (PostgreSQL)US
Artifact & trace storageAWS S3US
Model inferenceAnthropic / OpenAIVaries by provider

2. Data flow and handling

2.1 What crosses each boundary

BoundaryWhat crosses it
Browser → PhoenixThe user's message; optionally a client-held transcript of the current conversation (§2.2); the session cookie
Phoenix → OttoBotThe message and transcript; a short-lived credential identifying the user and organization
OttoBot → Phoenix MCPData queries issued as the end user, authenticated by a separate short-lived credential
OttoBot → model providerThe prompt, the persona/instructions for your organization, and tool results needed to answer

2.2 Conversation history is not stored server-side

Per-org OttoBot chat has no server-side conversation history store. Turns are stateless on the server: there is no database table, cache, or file in which one organization's transcript is retained and could later be served to another.

Conversation context is instead supplied by the browser with each request, and is treated as untrusted input. It is validated against a strict schema that:

  • rejects any unexpected field, at the top level or nested within a history entry;
  • caps history at 50 messages per request;
  • caps each individual message at 8,000 characters;
  • rejects the request rather than silently truncating a malformed payload.

Because history is client-supplied, it is treated as conversational context, not as an authoritative record — and never as a source of authorization. What a user may retrieve is determined by their Phoenix identity (§3), not by anything asserted in the transcript.

2.3 What is persisted

DataWhereNotes
Operational tracesAWS S3 (US)Written under a per-organization prefix derived per request (§4.1). Retention is bounded and configurable.
Generated artifactsAWS S3 (US)Same per-organization prefixing.
Chat transcriptsNot persisted server-sideSee §2.2.

Traces are written through a credential-redaction step that scrubs recognised secret formats — API keys, bearer and basic authorization headers, and credential-bearing connection strings — before anything is persisted. This is pattern-based redaction applied on the write path, not a guarantee that every possible secret shape is caught. For the platform-wide redaction behaviour applied to sensitive values, see Security Guardrails §2.

3. Authentication and authorization

3.1 Credential chain

A request is authorized in three stages, each narrower than the last:

  1. Phoenix session. The user authenticates to Phoenix normally. No OttoBot surface accepts anonymous traffic.
  2. Short-lived chat credential. Phoenix mints an opaque bearer token, scoped exactly to OttoBot chat, bound to the resolved user and organization, with a five-minute lifetime. It is minted server-side and forwarded to the OttoBot service; it is never used by the browser to call anything else.
  3. Short-lived data credential. When OttoBot needs to query Phoenix data, the chat credential is exchanged for a second, independently revocable token scoped to data access only, likewise bound to that user and organization.

The two credentials are not interchangeable in either direction: the chat credential is rejected by the data interface, and the data credential is rejected by the chat route. A token minted for one purpose cannot be replayed against the other surface, and neither carries a mixed or broadened scope — scope sets are matched exactly, not by prefix or subset.

3.2 Enforcement on the chat route

When your users chat with OttoBot inside Phoenix, every request passes the following checks before any turn begins. Each failure is terminal, and each is evaluated server-side on the request itself — none is inferred from the client.

CheckFailure
Caller holds a valid Phoenix session401
Caller is not a read-only administrator acting on behalf of the organization403
Caller is a member of the organization named in the request path403
The organization has OttoBot enabled, with a stored upstream that passes the egress allowlist (§3.3)404 / 422

Only after all of these pass does Phoenix mint the short-lived chat credential (§3.1) for that user and organization and begin the turn. Credential minting happens after authorization, not before it, so an unauthorized request never causes a credential to be issued.

Membership is checked on every request through Phoenix's authorization service. That service maintains a short-lived cache of membership results, so a membership change propagates within the cache lifetime rather than instantaneously.

The separate credential-bearing entry point used for embedded deployments applies additional checks — exact scope matching, organization binding on the credential, and revalidation of the underlying API key against the key registry. That surface is out of scope for this page (see Not covered here above).

3.3 Egress restrictions

Phoenix will only forward an OttoBot turn to an address that passes an allowlist check at the moment the route is configured:

  • The OttoBot service address must be in-cluster service DNS, with one exception: a single hardcoded, non-routable hostname reserved for automated testing. Arbitrary public hostnames, localhost, raw IP addresses, and embedded credentials are rejected. This prevents a misconfigured or maliciously edited route from redirecting a customer's conversation to an external endpoint.
  • The configuration store address must be either in-cluster service DNS or an HG-operated managed cache endpoint in our production region. The check is a naming-pattern match rather than an account-ownership proof, so it rejects a third party's endpoint in the same region on the strength of the hostname shape. Embedded credentials are likewise rejected.

Both checks are applied at write time, so an invalid destination cannot be stored in the first place.

4. Security controls

4.1 Per-request tenant controls

The following controls are live in production and applied per request, each deriving its behaviour from the validated credential's organization rather than from fixed start-up configuration. Each fails closed: an unrecognised organization is rejected rather than served a default.

ControlWhat it enforces
Per-request persona selectionThe instructions and workspace serving a turn are selected from the validated organization, behind an allowlist with path containment. An unknown organization is refused, not given a fallback persona.
Per-organization or disabled tool credentialsThird-party in-process integrations (for example Salesforce, Confluence) are disabled outright on the shared service, before any credential is read. Only per-user Phoenix data access is available, and that is already scoped to the requesting user.
Organization-scoped data session keyingThe organization is part of the key identifying a pooled connection to Phoenix, so connections for two organizations cannot collide even if user, conversation, and thread identifiers were identical. Pooled connections are additionally torn down when the credential changes or expires.
Per-request trace and artifact prefixingTrace paths, artifact paths, and observability tags are derived per request from the organization. Two organizations' traces and artifacts land under distinct prefixes and carry distinct tags.

The browser chat surface accepts only these authenticated, organization-bound requests. There is no unauthenticated path into it, so there is no code path on which a turn could execute without a resolved organization.

4.2 Limits we do not overstate

  • Spend caps are enforced at model provisioning, not in-process. The in-process budget guard operates per turn: it stops a single runaway conversation. It is not a cumulative per-organization quota. Caps therefore bound spend; they are not a concurrency control, and we do not claim otherwise.
  • The model-facing protections for OttoBot are prompt-level. They live in the persona and instruction layer. Per-org OttoBot chat does not run a pre-model classifier or input-scanning filter in front of the model. The input sanitization described in Security Guardrails §1 applies to the Phoenix agent product, not to this path. The redaction (§2), output guardrails (§3), and adversarial testing programme (§4) described there are platform-wide.
  • Authorization is not delegated to the model. What a user can retrieve is fixed by the credential chain in §3 before the model is invoked. Prompt content — including client-supplied history — cannot widen it, because the data credential is bound to the validated user and organization at mint time and cannot be swapped by anything the model emits.

4.3 Residual risk of a shared service

A shared service means one process memory space. Organizations served concurrently by the same process are separated by the per-request controls above rather than by an operating-system or hardware boundary. A sufficiently severe defect in the runtime — one permitting arbitrary code execution or out-of-bounds memory disclosure — is the class of issue those controls narrow but do not categorically eliminate.

We state this plainly because it is the honest characterization of the deployment model, and because we do not currently offer a dedicated-instance alternative. The controls in §4.1 exist to minimize what is resident per turn: credentials are short-lived and per-request, third-party integration credentials are not loaded at all, and no organization's conversation is retained server-side between turns.

Organizations whose requirements do not permit a shared process should raise this with their HG Insights representative before enabling OttoBot.

5. Certifications and attestations

Phoenix is operated by HG Insights and is covered by HG Insights' corporate security programme.

For SOC 2 reports, penetration-testing summaries, and other formal attestations, contact HG Insights Corporate InfoSec through your HG Insights representative. Those artifacts are issued and maintained at the corporate level.

This page makes no independent certification claim on behalf of the OttoBot integration. It describes architecture and controls; it is not itself an attestation, and it does not assert that this integration has been separately certified.

QuestionWhere to go
SOC 2, penetration tests, formal attestationsHG Insights Corporate InfoSec
Contractual terms, audit rights, liabilityYour HG Insights MSA
Data-residency requirements beyond USYour HG Insights representative
Technical questions about this pageYour HG Insights representative

Document control

VersionDateAuthorChanges
0.12026-08-21Phoenix TeamInitial publication — per-org OttoBot architecture, data flow, authentication, tenant-isolation controls, and residual-risk disclosure for the shared multi-tenant deployment