Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
240 changes: 240 additions & 0 deletions docs/my-website/docs/proxy/guardrails/qohash_qostodian_nexus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Qostodian Nexus by Qohash

[Qohash](https://qohash.com/) is a pioneer of zero-copy data security, the only model designed to secure petabytes of unstructured data in large enterprises. Enterprises run dozens of AI models, copilots, and autonomous agents, all hungry for data. Qostodian Nexus is the single control layer that governs every interaction. It knows your data. It enforces your policies. It scales from prompt inspection to LLM output data governance, interrogating all agentic, human, SaaS and API interactions with one control plane and a consistent set of policies. Nexus scans prompts and responses using deterministic classification policies and LLM-as-a-judge checks, returning an explicit enforcement decision (ALLOW, LOG, REDACT or BLOCK).

:::info
Qostodian Nexus is not a public offering. To inquire about access, visit [qohash.com](https://qohash.com).
:::

## Quick Start

### 1. Deploy Qostodian Nexus

Run Qostodian Nexus as a container with your policy config mounted:

```bash
docker run --rm \
-p 8800:8800 \
-v $(pwd)/nexus.yaml:/etc/nexus/config.yaml \
qohash/nexus:latest
```

Verify it's ready:

```bash
curl -i http://localhost:8800/health
# Expected: HTTP/1.1 200 OK
```

:::note
Additional deployment options are available. [Contact Qohash](https://qohash.com) for details.
:::

### 2. Configure LiteLLM Proxy (config.yaml)

**Pre-call** — block sensitive data before it reaches the model:

```yaml title="config.yaml (pre-call)"
guardrails:
- guardrail_name: "qostodian-nexus-pre-call"
litellm_params:
guardrail: qostodian_nexus
api_base: http://nexus:8800
mode: "pre_call"
default_on: true
```

**Post-call** — redact or block sensitive data in model output before it reaches the caller:

```yaml title="config.yaml (post-call)"
guardrails:
- guardrail_name: "qostodian-nexus-post-call"
litellm_params:
guardrail: qostodian_nexus
api_base: http://nexus:8800
mode: "post_call"
default_on: true
```

### 3. Start LiteLLM Gateway

```bash
litellm --config config.yaml
```

### 4. Test Requests

<Tabs>
<TabItem label="BLOCK" value="block">

Send a prompt containing a credit card number (blocked by a `BLOCK` policy):

```bash
curl -i http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your_litellm_key>" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{"role": "user", "content": "MASTERCARD 5555555555554444 03/2027 123"}
],
"guardrails": ["qostodian-nexus-pre-call"]
}'
```

Expected: Qostodian Nexus returns `BLOCK` → LiteLLM returns an error, no provider request is made.

</TabItem>
<TabItem label="REDACT" value="redact">

**Pre-call** — sensitive substrings are masked before the prompt reaches the model:

```bash
curl -i http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your_litellm_key>" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{"role": "user", "content": "My credit card is 5555555555554444, please summarize this."}
],
"guardrails": ["qostodian-nexus-pre-call"]
}'
```

Expected: Qostodian Nexus returns `REDACT` → LiteLLM forwards a masked prompt to the provider. Response headers include `x-qostodian-nexus-outcome-decision: REDACT`.

**Post-call** — sensitive content in the model response is masked before it reaches the caller:

```bash
curl -i http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your_litellm_key>" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{"role": "user", "content": "Return my credit card number: 5555555555554444."}
],
"guardrails": ["qostodian-nexus-post-call"]
}'
```

Expected: Qostodian Nexus returns `REDACT` → LiteLLM returns the response with masked output.

</TabItem>
<TabItem label="LOG" value="log">

Send a prompt with low-sensitivity data that triggers a `LOG` policy (request continues):

```bash
curl -i http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your_litellm_key>" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{"role": "user", "content": "My employee ID is 123456 (test) and my phone is 555-0100"}
],
"guardrails": ["qostodian-nexus-pre-call", "qostodian-nexus-post-call"]
}'
```

Expected: Qostodian Nexus returns `LOG` → LiteLLM forwards to the provider, response returns normally with decision headers.

</TabItem>
<TabItem label="ALLOW" value="allow">

Send a benign prompt (no sensitive data detected):

```bash
curl -i http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your_litellm_key>" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{"role": "user", "content": "Summarize the main differences between TCP and UDP."}
],
"guardrails": ["qostodian-nexus-pre-call", "qostodian-nexus-post-call"]
}'
```

Expected: Qostodian Nexus returns `ALLOW` → LiteLLM forwards to the provider normally.

</TabItem>
</Tabs>

## Decisions

Qostodian Nexus returns one decision per request:

| Decision | Request continues? | Description |
|---|---|---|
| `ALLOW` | Yes | No policy violation detected |
| `LOG` | Yes | Violation logged; request proceeds with outcome metadata |
| `REDACT` | Yes (masked) | Sensitive substrings replaced in the payload before forwarding |
| `BLOCK` | No | Request fails; no provider call is made (for pre-call) |

## Supported Parameters

| Parameter | Type | Description |
|---|---|---|
| `guardrail` | string | Must be `qostodian_nexus` |
| `api_base` | string | Base URL of your Qostodian Nexus instance (e.g. `http://nexus:8800`) |
| `mode` | string | `pre_call` (scan prompt) or `post_call` (scan model output) |
| `default_on` | boolean | Apply this guardrail to all requests by default |

No API key is required for LiteLLM to call Qostodian Nexus. As Qostodian Nexus is designed to be deployed within your infrastructure, you must secure it using network controls.

## Request Identifiers

Qostodian Nexus requires correlation identifiers on every request. These identifiers are never used to access content, they carry only metadata that attributes detections to the right user, session, and context.

Pass them via request headers:

```bash
curl -i http://localhost:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your_litellm_key>" \
-H "x-qostodian-nexus-identifiers-trace: trace-id" \
-H "x-qostodian-nexus-identifiers-source: source-id" \
-H "x-qostodian-nexus-identifiers-container: container-id" \
-H "x-qostodian-nexus-identifiers-identity: identity@example.com" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{"role": "user", "content": "..."}
],
"guardrails": ["qostodian-nexus-pre-call", "qostodian-nexus-post-call"]
}'
```

| Identifier | Description |
|---|---|
| `trace` | Unique ID for the request or session, used for correlation across events |
| `source` | The application or integration sending the request (e.g. app ID, service name) |
| `container` | The conversation or thread context (e.g. conversation ID) |
| `identity` | The end-user identity (e.g. email or UPN), used for user-level attribution |

These fields are required in all deployment modes. Their effect depends on the operating mode:

### Qostodian Platform

[Qostodian](https://qohash.com/qostodian/) is the Qohash data security posture management (DSPM) platform. It monitors high-risk unstructured data across your organization, providing visibility into sensitive data exposure, behavioral analytics, and governance workflows. When Qostodian Nexus operates in connected or advanced mode, identifiers are forwarded to Qostodian to correlate AI detections with broader data security activity across users, sessions, and applications.

| Mode | Effect |
|---|---|
| Basic standalone | Identifiers appear in structured log output for traceability |
| Basic connected | Connects to the Qostodian Platform — identifiers are used for display and attribution |
| Advanced (platform) | Connects to the Qostodian Platform — identifiers unlock full DSPM capabilities: activity correlation, behavioral profiling, and governance workflows |

## Security Guidance

Qostodian Nexus operates on a **zero-copy, data-sovereign processing model** in all deployment modes: content is analyzed in-memory and never persisted or transmitted to Qohash. Only metadata (detection outcomes, policy decisions, identifiers) is reported — prompt and response content stays within your infrastructure at all times.

- **Use TLS** between LiteLLM and Qostodian Nexus in production environments
- **Authenticate calls** using mTLS (preferred) or bearer token
- **Deploy Qostodian Nexus in customer-controlled infrastructure** (on-premises or cloud tenant) to ensure data stays within your security boundary
1 change: 1 addition & 0 deletions docs/my-website/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const sidebars = {
label: "Team Bring-Your-Own Guardrails",
},
...[
"proxy/guardrails/qohash_qostodian_nexus",
"proxy/guardrails/qualifire",
"proxy/guardrails/aim_security",
"proxy/guardrails/onyx_security",
Expand Down
35 changes: 35 additions & 0 deletions litellm/proxy/guardrails/guardrail_hooks/qohash/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from typing import TYPE_CHECKING

from litellm.types.guardrails import SupportedGuardrailIntegrations

from .qohash import QostodianNexus

if TYPE_CHECKING:
from litellm.types.guardrails import Guardrail, LitellmParams


def initialize_guardrail(litellm_params: "LitellmParams", guardrail: "Guardrail"):
import litellm

_instance = QostodianNexus(
api_base=litellm_params.api_base,
guardrail_name=guardrail.get("guardrail_name", ""),
event_hook=litellm_params.mode,
default_on=litellm_params.default_on,
additional_provider_specific_params=litellm_params.additional_provider_specific_params,
extra_headers=getattr(litellm_params, "extra_headers", None),
)

litellm.logging_callback_manager.add_litellm_callback(_instance)

return _instance


guardrail_initializer_registry = {
SupportedGuardrailIntegrations.QOSTODIAN_NEXUS.value: initialize_guardrail,
}


guardrail_class_registry = {
SupportedGuardrailIntegrations.QOSTODIAN_NEXUS.value: QostodianNexus,
}
74 changes: 74 additions & 0 deletions litellm/proxy/guardrails/guardrail_hooks/qohash/qohash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""
Qostodian Nexus (by Qohash) — LiteLLM guardrail integration.
"""
import os
from typing import TYPE_CHECKING, Literal, Optional, Type

from litellm.proxy.guardrails.guardrail_hooks.generic_guardrail_api.generic_guardrail_api import (
GenericGuardrailAPI,
)
from litellm.types.proxy.guardrails.guardrail_hooks.qohash import (
QostodianNexusConfigModel,
)
from litellm.types.utils import GenericGuardrailAPIInputs

if TYPE_CHECKING:
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj

GUARDRAIL_NAME = "qostodian_nexus"


class QostodianNexus(GenericGuardrailAPI):
def __init__(
self,
api_base: Optional[str] = None,
**kwargs,
):
api_base = api_base or os.environ.get("QOSTODIAN_NEXUS_API_BASE", "http://nexus:8800")

kwargs["guardrail_name"] = kwargs.get("guardrail_name", GUARDRAIL_NAME)

# Merge built-in Qostodian Nexus identifier headers with any caller-supplied extra_headers
nexus_headers = [
"x-qostodian-nexus-identifiers-trace",
"x-qostodian-nexus-identifiers-source",
"x-qostodian-nexus-identifiers-container",
"x-qostodian-nexus-identifiers-identity",
]

existing = kwargs.get("extra_headers") or []
kwargs["extra_headers"] = nexus_headers + [h for h in existing if h not in nexus_headers]

super().__init__(
api_base=api_base,
**kwargs,
)

async def apply_guardrail(
self,
inputs: GenericGuardrailAPIInputs,
request_data: dict,
input_type: Literal["request", "response"],
logging_obj: Optional["LiteLLMLoggingObj"] = None,
) -> GenericGuardrailAPIInputs:
"""
Apply Qostodian Nexus to the given inputs.

NOTE: This override is intentionally a pass-through. It must be present
directly in this class's __dict__ so that LiteLLM's unified guardrail
routing check (`"apply_guardrail" in type(callback).__dict__` in
litellm/proxy/utils.py) routes calls correctly. Do not remove.
"""
return await super().apply_guardrail(
inputs=inputs,
request_data=request_data,
input_type=input_type,
logging_obj=logging_obj,
)
Comment thread
mats852 marked this conversation as resolved.

@classmethod
def get_config_model(cls) -> Optional[Type[QostodianNexusConfigModel]]:
"""
Returns the config model for Qostodian Nexus.
"""
return QostodianNexusConfigModel
5 changes: 5 additions & 0 deletions litellm/types/guardrails.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
from litellm.types.proxy.guardrails.guardrail_hooks.tool_permission import (
ToolPermissionGuardrailConfigModel,
)
from litellm.types.proxy.guardrails.guardrail_hooks.qohash import (
QostodianNexusConfigModel,
)

"""
Pydantic object defining how to set guardrails on litellm proxy
Expand Down Expand Up @@ -84,6 +87,7 @@ class SupportedGuardrailIntegrations(Enum):
BLOCK_CODE_EXECUTION = "block_code_execution"
AKTO = "akto"
MCP_JWT_SIGNER = "mcp_jwt_signer"
QOSTODIAN_NEXUS = "qostodian_nexus"


class Role(Enum):
Expand Down Expand Up @@ -748,6 +752,7 @@ class LitellmParams(
IBMGuardrailsBaseConfigModel,
QualifireGuardrailConfigModel,
BlockCodeExecutionGuardrailConfigModel,
QostodianNexusConfigModel,
):
guardrail: str = Field(description="The type of guardrail integration to use")
mode: Union[str, List[str], Mode] = Field(
Expand Down
Loading
Loading