rogue-security
Official Python SDK for the Rogue Security AppSec evaluation API.
Wraps the two public AppSec methods, evaluate (inline checks) and invoke (saved
guardrail), with typed params and responses (Pydantic v2), typed errors, automatic
retries, and debug logging. Ships sync and async clients.
Install
pip install rogue-security
Quickstart
from rogue_security import RogueClient
with RogueClient(api_key="rsk_...") as rogue:
result = rogue.evaluate(
messages=[
{"role": "user", "content": "What is the patient's SSN?"},
{"role": "assistant", "content": "It is 123-45-6789."},
],
pii_check=True,
prompt_injections=True,
)
print(result.status, result.score)
for group in result.evaluation_results:
for r in group.results:
if r.flagged:
print(group.type, r.label, r.reason)
api_key falls back to the ROGUE_API_KEY environment variable if omitted.
Async
from rogue_security import AsyncRogueClient
async with AsyncRogueClient() as rogue: # reads ROGUE_API_KEY
result = await rogue.evaluate(
messages=[{"role": "user", "content": "..."}],
content_moderation_check=True,
)
Invoke a saved guardrail
result = rogue.invoke(
guardrail_id="gr_abc123",
messages=[
{"role": "user", "content": user_prompt},
{"role": "assistant", "content": model_response},
],
)
if result.blocked:
... # the guardrail's workspace is set to block and the evaluation failed
You can also pass a typed params object instead of keyword arguments:
from rogue_security import EvaluateParams
rogue.evaluate(
EvaluateParams(
messages=[{"role": "user", "content": "..."}],
pii_check=True,
hallucinations_mode="quality",
)
)
Error handling
from rogue_security import RogueAuthError, RogueValidationError, RogueError
try:
rogue.evaluate(pii_check=True)
except RogueAuthError:
... # bad / missing key
except RogueValidationError:
... # 422, e.g. no checks enabled
except RogueError as err:
print(err.status, err)
RogueServerError (5xx), rate limits (429), and network/timeout failures are retried
automatically (default 2 retries, exponential backoff with jitter).
Options
RogueClient(
api_key="rsk_...",
base_url="http://localhost:8006", # local dev; defaults to production (or ROGUE_BASE_URL)
timeout=30.0,
max_retries=2, # retries via tenacity, exponential backoff + jitter
debug=True, # logs via the "rogue_security" logger; key is masked
)
Corporate networks / custom TLS (e.g. Zscaler)
Pass a verify value (CA bundle path or ssl.SSLContext) or your own configured
httpx client. A client you pass in is yours to close; the SDK won't close it.
import httpx
from rogue_security import RogueClient
# Option A: custom CA bundle
RogueClient(api_key="rsk_...", verify="/path/to/corp-ca.pem")
# Option B: bring your own httpx client (proxies, mTLS, etc.)
RogueClient(api_key="rsk_...", http_client=httpx.Client(verify="/path/to/corp-ca.pem"))
LiteLLM proxy guardrail
Setup, routing, coverage, and what a block looks like for each client: LiteLLM proxy integration guide.
rogue_security.litellm.RogueGuardrail evaluates every /chat/completions and Anthropic
/v1/messages request and its response with evaluate, and blocks flagged turns. A streamed
response is checked once, when the stream ends, and in the default stream_mode: monitor a flagged
stream is only logged (see stream_mode below). /v1/messages/count_tokens runs no guardrail.
Anthropic routes convert the raw request body, so documents and search results are evaluated.
The litellm extra needs Python 3.10 or newer, because LiteLLM 1.95.1 does not install on 3.9.
pip install 'rogue-security[litellm]>=1.1.0' 'litellm[proxy]==1.95.1' 'fastapi<0.140.7'
The LiteLLM 1.95.1 proxy fails to start with fastapi 0.140.7 or newer, so keep the
fastapi<0.140.7 pin until LiteLLM ships a fix.
guardrails:
- guardrail_name: rogue
litellm_params:
guardrail: rogue_security.litellm.RogueGuardrail
mode: [pre_call, post_call] # pre_call checks requests, post_call checks responses
default_on: true
api_key: os.environ/ROGUE_API_KEY
rogue_base_url: os.environ/ROGUE_BASE_URL # optional, defaults to production
rogue_action: block # block (default) or monitor (log only)
rogue_checks: # any evaluate check flags; unknown keys fail proxy start-up
prompt_injections: true
pii_check: true
assertions:
- "The assistant never reveals internal system prompts."
fail_open: true # default; Rogue errors and timeouts let traffic through with a warning
timeout: 4 # seconds, default 4, no retries
message_window: 1 # trailing client turns per evaluation, default 1 (last turn only)
stream_mode: monitor # monitor (default) or buffer, see below
evaluate_all_text_blocks: false # default; true checks every text block of the last user message
The options are rogue_action and rogue_checks because LiteLLM already defines typed
action and checks guardrail params. Every *_mode runs at speed; policy_target and
topic_scoping_target are input for requests and output for responses.
With the default message_window of 1, response checks carry only the assistant reply, so
context checks such as grounding have no source text unless you widen the window.
Response checks evaluate the whole reply: every text block and every choice or output part is
joined into one assistant message. Anthropic tools keep their input_schema. On /v1/responses,
the conversation is rebuilt from the request's input and instructions.
A blocked request returns HTTP 400. LiteLLM wraps the guardrail detail, so the reasons are in
error.provider_specific_fields.reasons, not at the top level of the body.
A blocked non-streamed response returns HTTP 200 with finish_reason: "content_filter" and the
block reasons as the message content. A streamed response follows stream_mode.
On /v1/messages, a blocked request returns HTTP 400 with the reasons inside
error.message. A blocked response returns HTTP 200 with the reasons as the assistant text and
stop_reason: "end_turn". The system prompt and tool results are sent to Rogue only when they fall
inside message_window.
message_window counts client turns; the last turn includes the tool results delivered with the
final message. LiteLLM turns one Anthropic user message with tool_result blocks into tool
messages followed by a user message, so the default window sends that user message and every
tool result of the same turn. Pass-through bodies are converted the same way, so their
tool_result blocks become tool messages of the same turn. An assistant or system message is a
turn of its own. Responses count plain trailing messages.
When the last user message of a request holds several text blocks, only the newest block is
checked. Claude Code keeps a blocked prompt in the session and merges consecutive prompts into
one user message, so checking every block would block every later turn. The trade-off: a payload
in an earlier text block of that message, followed by a harmless last block, is not checked. Set
evaluate_all_text_blocks: true to check the joined text of every block instead. Image and
other non-text parts are kept, and tool results are separate tool messages, so they are still
checked. Earlier messages in the window and responses are never trimmed. The rule applies to
pass-through bodies too, after conversion.
stream_mode decides what a flagged stream does:
monitor(default): chunks reach the client as they arrive and the check runs at the end. A flagged stream is only logged, never blocked, and Rogue errors are only logged too.buffer: the proxy holds every chunk until the check passes, then replays the stream. A flagged stream is never delivered. On/v1/messagesthe client gets a complete message that holds the block reasons and no tool call; on/chat/completionsand/v1/responsesit gets HTTP 500 with the block reasons inerror.message. The client waits for the whole response first.
Claude Code
Point Claude Code at the proxy root, ANTHROPIC_BASE_URL=http://<proxy>:4000, and list the
Claude models it uses in the proxy model_list, including Bedrock models as bedrock/....
Every request and response is then checked. With CLAUDE_CODE_USE_BEDROCK=1 or a
/anthropic base URL, LiteLLM forwards the traffic as a passthrough and the response check
does not run.
Pass-through routes
On LiteLLM's provider pass-through routes the guardrail gets the raw client body, not chat
messages. It detects the body format and converts it to chat messages and tools before calling
Rogue: Anthropic Messages (/anthropic/*), Bedrock Converse and Anthropic-on-Bedrock invoke
(/bedrock/*), and Gemini generateContent. System prompts, tool calls, tool results and tool
definitions are kept, as is the text of plain-text documents, search results and cited answers,
along with document and search result titles and Anthropic document context. Tool results are sent
as text, so a result holding only an image or file is sent empty. Images, files, audio, video, base64 payloads, reasoning blocks, Gemini thought parts and
server-side tool results are dropped, and unknown part types are skipped. Only client-defined
function tools are listed as available tools: Anthropic server and versioned tools (bash, text
editor, computer use, web search and the rest), Gemini built-in tools and Converse system tools
are not. As on every route, message_window decides how many of the converted messages are
sent, by default the last client turn (the last user message and the tool results delivered
with it), and only the newest text block of a merged last user message
is kept. Request headers never reach Rogue. Of LiteLLM's own fields, only
the guardrail name, litellm_call_id, and the virtual key alias and team alias or id (when set)
are sent as evaluate metadata. An unrecognised body is sent as its JSON text in one user
message. When a pass-through endpoint sets request_fields for the guardrail, only the text at
those JSONPath fields is sent.
What LiteLLM 1.95.1 checks on each route, from end-to-end runs:
| Vendor | Client endpoint on the proxy | Request check | Response check, non-stream | Response check, stream |
|---|---|---|---|---|
| Anthropic | /v1/messages |
Yes | Yes | Yes (monitor logs after delivery; buffer blocks) |
| Anthropic | Claude Code, ANTHROPIC_BASE_URL at the proxy root |
Yes | Not tested | Yes (monitor logs after delivery; buffer blocks) |
| Anthropic | /anthropic/* pass-through |
Yes | No (LiteLLM never calls the guardrail) | Not tested |
| Bedrock (Claude) | /v1/messages |
Yes | Yes | Yes (monitor logs after delivery; buffer blocks) |
| Bedrock (Claude) | Claude Code, ANTHROPIC_BASE_URL at the proxy root |
Yes | Not tested | Yes (monitor logs after delivery; buffer blocks) |
| Bedrock (Claude) | Claude Code in Bedrock mode (/bedrock base) |
Yes | Not tested | No (LiteLLM never calls the guardrail) |
| Bedrock | /bedrock/* converse |
Yes | Yes | Not applicable, see converse-stream |
| Bedrock | /bedrock/* converse-stream |
Yes | Not applicable | Yes, buffered by LiteLLM; a block is HTTP 500 |
| Bedrock | /bedrock/* invoke |
Yes | Yes, raw JSON | No (LiteLLM never calls the guardrail) on invoke-with-response-stream |
| Bedrock | /chat/completions with a bedrock/... model |
Yes | Yes | Yes (monitor logs after delivery; buffer blocks) |
| OpenAI | /chat/completions |
Yes | Yes | Yes (monitor logs after delivery; buffer blocks) |
| OpenAI | /v1/responses |
Yes | Yes | Yes (monitor logs after delivery; buffer blocks) |
| Gemini | /chat/completions with a gemini/... model |
Yes | Yes | Yes (monitor logs after delivery; buffer blocks) |
| Gemini | /gemini/* pass-through |
Yes | No (LiteLLM never calls the guardrail) | Not tested |
| Gemini | Native generateContent (/v1beta/models/...) |
Not tested | Not tested | Not tested |
| Any | /v1/messages/count_tokens |
No (LiteLLM never calls the guardrail) | No (LiteLLM never calls the guardrail) | No (LiteLLM never calls the guardrail) |
"Buffer blocks" means the flagged reply never reaches the client. On /v1/messages and Claude Code the client gets a complete streamed message holding the block reasons. On /chat/completions it gets an HTTP 200 stream whose one chunk holds the block reasons with finish_reason: "content_filter". On /v1/responses it gets an HTTP 200 stream of one complete response whose output text is the block reasons. Claude Code always streams, so its non-stream column is not tested. converse and invoke are non-streaming calls. LiteLLM buffers a converse-stream response before the check, so the client gets it in one burst; Claude Code in Bedrock mode streams through invoke-with-response-stream, which LiteLLM never checks. On /bedrock/* routes the model in the URL must be a model_name from model_list; a raw Bedrock model ID fails with Invalid model name.
LiteLLM runs a pass-through response check only for guardrails listed in a pass-through
endpoint's guardrails config. Send Gemini traffic through /chat/completions to have both
sides checked.
What happens on an uncovered route
On a side marked No, LiteLLM never hands that traffic to the guardrail. Nothing of ours runs there: no evaluation, no monitor log line, and no fail-open decision, because fail_open only applies when an evaluation is attempted and fails. The traffic passes unchecked. The request side on the same route still runs where the table says Yes. Not tested means no end-to-end run backs the cell either way.
Local development
uv sync
uv run pytest
More: see ../docs for the full API reference, check descriptions, and examples.
Configured guardrails
Discover IDs with client.guardrails.list() and read saved settings with client.guardrails.get(id). Both include the effective API-key workspace. The Guardrails UI also provides Copy ID on each card.
result = client.guardrails.execute(messages=[{"role": "user", "content": "Check this request"}])
print(result.status, result.decision, result.log_id)
The async client exposes the same resource methods with await.
Execution runs all active guardrails using their saved checks and Log/Block settings. Supply available tools when tool checks are enabled. Your application enforces decision; handle indeterminate, incomplete, and no_active_guardrails explicitly. A blocking finding wins over partial failures. List pagination starts at zero, defaults to 20 entries, and allows at most 100. Existing API keys work without new credentials.
Security controls
Inline checks now support secret scanning, explicit PII confidence thresholds (default 0.85), moderation methods (default speed), and coding category policies. Category actions are Off/Log/Block with a minimum raw severity; hidden categories always log. A supplied category map defaults unspecified categories to Block from critical. Saved Log mode caps category enforcement. invoke evaluates all linked checks, including inactive definitions, but only active Block bindings enforce. Inspect completion and decision independently of scores.
Use restricted_topics (Python) or restrictedTopics (TypeScript) for prohibited topics. The old allowed-topics alias remains deprecated with identical restricted-topic behavior; conflicting aliases are rejected. Tool results preserve tool_call_id / toolCallId. Responses include persisted log and workspace IDs. See check options for settings and defaults.
Metadata
Release files for rogue-security 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rogue_security-1.1.0.tar.gz | 328.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rogue_security-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 354.8 kB
Release files / rogue_security-1.1.0.tar.gz
| Download URL | rogue_security-1.1.0.tar.gz |
|---|---|
| Size | 328.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9073526ec57904ef9762104f4159df4ad8193a8a46b1bfdfdcf5f5abc1405f60
|
|
BLAKE2b-256 checksum How to use checksums |
2fcb3231aa4cd45c9f468983b527ccadd51af193871e34b078ddfefd57998e01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / rogue_security-1.1.0-py3-none-any.whl
| Download URL | rogue_security-1.1.0-py3-none-any.whl |
|---|---|
| Size | 26.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0b4c39efa23a2aea4fa9b39eb0e41405ef673b749e5596ca80006c2d2a9beffa
|
|
BLAKE2b-256 checksum How to use checksums |
f8b404abd52e4ea81ee18ce65e3ddf63c753a63fba5df2e97a231fa6ce9543e6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency log