Security Gateway
Policy-driven filtering of prompts and responses: secrets, PII, codenames, request shape, and prompt injection.
What it is — and what it is not
The Security Gateway evaluates every proxied request and response against policies you define. It can observe, redact, or block. Every match is recorded with the request id, the caller, the model, the rule that fired, and the action taken, so the outcome is attributable and reportable.
It is an accident-prevention and audit control, not a security boundary. A determined insider can rephrase, encode, or split material across turns to get past any filter. What the gateway promises is that every attempt is policy-evaluated, blocked where configured, logged and attributable — which is what compliance actually buys.
Two tiers exist. The deterministic tier (secrets, PII, term lists, request shape) needs no model and no GPU, observes on every edition (redact and block need Business), runs in the gateway process in well under a millisecond, and produces span-level evidence an auditor accepts. The classifier tier (prompt injection in this version) needs a guard model and adds latency; it is the only way to catch things defined by intent rather than structure.
Policies and bindings
A policy is a named bundle of checks. Each check has a kind, a mode (observe / redact / block), a direction (ingress, egress, or both), and for model-backed checks a fail stance (closed or open) and the classifier that backs it.
A policy does nothing until it is bound to a scope: Everyone, a group, an upstream provider, personal subscriptions (people’s own connected plans, all providers or one), a model, a managed model, or a service token. One binding per scope. Resolution is most-specific-wins: Everyone → group → upstream provider or personal subscriptions → model → managed model → service token.
A policy bound to Everyone may be marked mandatory. Its checks then become a floor: a more specific binding may add checks or tighten a mode (observe → redact → block), fail stance (open → closed), direction, or hold window — never relax or remove. Administration → Safety & Security → Security → Bindings → "Explain effective policy" shows the resolved checks for any caller and model, and names every relaxation that was refused. Precedence you cannot see is precedence you cannot audit.
Bindings are deliberately not part of grants. Grants answer "may this caller use this model"; policies answer "what rules apply to this traffic". Keeping them apart is what makes "block secrets org-wide" one binding instead of one edit per model per group — and is what stops a service token from being a bypass.
Rollout: observe first
Every check defaults to observe. In observe mode nothing is blocked or rewritten; matches are recorded exactly as they would be in block mode. Run a new policy in observe for long enough to see what it would have done to real traffic, review the Violations tab, then switch individual checks to redact or block.
Save a new policy without binding it (an unbound policy affects nothing), then use Security → Policies → Test to dry-run a sample request against it. Test runs the saved policy, not unsaved edits, and saving a policy that is already bound changes live traffic. A dry run makes no upstream call, writes no usage event and records no violation.
On Community every check runs in observe mode; redact and block need Business. Policies that already redact or block keep doing so after a downgrade, but a policy with a redact or block check cannot be saved again until the license allows it.
The checks
Secrets: gitleaks-style rules for API keys, tokens, private keys, JWTs, and credentials embedded in connection strings. Structured rules (AWS, GitHub, Slack, Stripe, private-key blocks, …) are enabled by default; the generic high-entropy rule is off because it fires on base64 images, hashes and tool-call payloads in prose. Patterns are Go RE2 — linear time, so an administrator-authored rule can never take the proxy down.
PII: payment cards (Luhn-checked), IBANs (mod-97), US Social Security numbers (hyphenated by default, structural checks), NPIs, e-mail addresses and phone numbers. Redact rather than block for most of these: blocking "summarize this complaint" over an e-mail address is the false positive that gets the feature switched off.
Term lists: your own words — project codenames, client names, classification markings. Modes: exact (whole words), substring, regex, or fuzzy (catches Pr0j3ct H4lb3rd and confusable characters). Lists are encrypted at rest and never shown in listings; viewing or exporting a list is written to the audit log. Import a text or CSV file rather than typing four hundred names into a form.
Shape: limits on message count, body size, image parts and tools, and a rule that refuses system-role messages from service tokens.
Prompt injection: a text-classification guard model (Llama Prompt Guard 2 is the reference) scores every message in overlapping windows, or a decision model (Jev, Nimble) judges the newest turn (see What a decision model reads). Unlike harmful-content filtering, nothing upstream protects you from injection — it targets the application, not the model.
Tool output: messages with role tool (or function) are tool output, not the person’s words. Violations found in them are recorded as tool output, and Child Safety judges them as content shown to the child, never as the child’s request. Pages, search results and file transcripts that Janus Chat reads for a reply are checked when Chat reads them, against the person’s policy. One that trips prompt injection or content safety is withheld from the model (the reply says “Withheld something it read”) and the reply goes on. The violation is listed under Security → Violations as “in a page Chat read”, not as the person’s words. Pages read by the provider’s own tools (hosted web search and page reading) are not checked when read; only the reply is.
What a block looks like
By default a blocked request receives HTTP 403 with an OpenAI-shaped error, code policy.security_blocked, and the check kind in error.param. The rule id and the matched text are never returned to the caller.
A policy may instead answer with a synthetic refusal: HTTP 200 and a well-formed completion whose finish_reason is content_filter, for clients that render errors badly. Streaming callers receive it as one chunk followed by [DONE]. The usage event still records the block either way. The synthetic refusal applies to chat completions only: a block on a decisions call (/v1/decisions, /v1/systemone, /api/alpha/decisions) always returns HTTP 403 with the error object (code policy.security_blocked).
A redacted request sets X-Janus-Redactions on the response. The upstream saw different text than the user sent; that must never be silent.
Responses and streaming
Checks with direction egress or both also scan the model's output — message content, reasoning content, and tool-call arguments. On a buffered response a block replaces the body with the error shape; a redaction rewrites the spans in place.
On a stream the gateway withholds a small trailing window of text (hold_bytes, default 256) so a match can be caught before the bytes leave. Frames are released once their text is older than the window and scanned clean. A blocking match drops everything still held, emits a final in-band error frame and [DONE], and records stream_cut on the usage event. Text already flushed cannot be recalled: the window is the entire protection, and 256 bytes is enough for every deterministic rule at a latency no reader can perceive.
Non-streaming replies larger than the response size limit (JANUS_MAX_RESPONSE_BYTES, 100 MiB by default) are never passed through unchecked when a reply check applies. For a child covered by Child Safety the reply is withheld and the child sees the stop notice. With a Security Gateway reply policy, the first part of the reply (up to the limit) is scanned by the deterministic checks; a match in block or redact mode withholds the whole reply (it cannot be rewritten), and observe mode records it. Replies with no reply check (for example large images) are passed through as before.
Tokens the upstream generated before a cut are metered normally. The spend happened; hiding it would misstate what the filter costs.
What is recorded — capture the attack, never the asset
Every violation row carries the request id, caller, model, policy, binding, check kind, rule id, action, offset/length and a hash of the matched span. What else is kept depends on the kind:
Secrets: hash only. Storing the match would move a live credential into a second at-rest location. Term lists: hash only — the log must not leak the codename it protects. PII: the redaction marker, never the value; a security log must not become a new regulated data store. Prompt injection and content safety: the judged message, encrypted, when the policy’s Keep prompt-injection request bodies for analysis is on (off for a new policy, from the editor or the API; otherwise hash only) — the attack text is the intelligence, and it is what tunes the classifier. Child Safety never keeps what a child wrote.
Reading captured text (Violations → Reveal) is itself written to the audit log. Retention is per kind: prompt-injection captures 90 days / 50k rows; secrets, PII, term-list and shape rows 30 days / 100k rows. Content-safety rows, Child Safety events included, are kept 90 days / 100k rows. Violations are never kept longer than the request log (JANUS_USAGE_RETENTION_DAYS, 365 days by default). Nothing captured ever leaves the gateway.
Classifier models
Add the guard model's server as an upstream of type TEI (Hugging Face Text Embeddings Inference, the standard host for Llama Prompt Guard 2 — an encoder model that generative engines such as vLLM cannot load). Discovery reads the server's /info, finds the one model it serves, and assigns the classifier role automatically; confirm it under Administration → Safety & Security → Security → Classifiers before referencing it in a policy.
A decision model (TypeSafe Jev, Bespoke Nimble) takes the Decision model role and can back prompt injection, content safety, or both. When both checks use the same decision model Janus asks them together; see Classifiers: speed and accuracy.
A model with a classifier role is removed from /v1/models, cannot be granted, and is called only by the gateway. Classifier models (guard and text-classification roles) only check traffic: they can’t be an alias’s target, fallback or pool member, and a model a managed model uses can’t be made a classifier until it is removed from that managed model. A request that still resolves to one is refused. A caller who could invoke the judge directly would have free, unlimited oracle access to the thing judging them.
Every classifier call is metered as a usage event on a platform-overhead subject with no user or service token attached: finance can see what the security feature costs and no user's quota moves because of it. The classifier is wrapped in a circuit breaker: three consecutive failures of the security checks' own calls open it for thirty seconds and raise a critical admin alert. Calls made by other features on the same decision model (Auto-routing, Usage insights, policy dry runs, Try boxes) never open it, and neither does a call the caller canceled. While it is open, blocking checks with fail=closed refuse requests and say so in the error message; checks with fail=open pass and log. Observe-mode checks never block, whatever their fail setting. Choose fail=closed for security; choose fail=open only where availability matters more, and pair it with the alert. “Security classifier unavailable” is sent once per outage for the whole cluster (again after 6 hours if it is still down), followed by “Security classifier recovered” when it answers again.
A classifier whose model is disabled or stale in Models is not called. Checks that use it follow their fail setting: fail closed refuses requests, fail open lets them through. Child Safety always fails closed. Rotating the API key or base URL of a classifier’s upstream takes effect on every replica within JANUS_CONFIG_CACHE_TTL_SECONDS (5 seconds by default).
Generative guard calls that report token usage (for example Llama Guard on a paid API) are priced from the model’s rate card, like decision-model calls; encoder guards on TEI report no usage and cost nothing.
Llama Prompt Guard 2 is distributed under the Llama 4 Community License: the download is gated, "Built with Llama" attribution applies, and any fine-tune must carry a name beginning with "Llama". If those terms are unacceptable to your organization, any model served in the same text-classification shape can back the check instead.
Content safety: security categories
Content safety asks a classifier whether a request (and, if you choose, the reply) falls under categories you care about. The default method is Categories: a decision model checks the categories the policy selects. The fixed hazard list Llama Guard uses is still available as Llama Guard compatible, a legacy method for Llama Guard models; checks saved before categories existed keep using it and behave exactly as before.
Security → Categories lists two groups. Safety: the fourteen standard hazard categories under plain names (Violent crimes, Child sexual exploitation, Suicide and self-harm and the rest), built in; their wording can be edited and reset. Your categories: ones you add. The children’s categories (Feeling low or unsafe, Homework done for them and the rest) belong to Child Safety and are not offered to policies; a policy that still selects one shows it only so you can remove it.
Each category has a name, what it includes and what it does not include (the text the classifier reads), a minimum confidence, test examples and an on/off switch. Instead of writing a description, a category can follow a Usage insights category, reading that category's name and description; editing the Usage insights category changes it too. Say what counts and name the near neighbors that do not: that is what stops false alarms.
Try a request at the top of the tab shows the probability for every category that is on and which ones would count. Test all examples runs every category's examples through the chosen decision model and reports which it missed and what it said instead. Neither stores anything.
In the policy editor, the content safety check's Method picks Categories or Llama Guard compatible. A new check starts on Categories with Violent crimes, Sex-related crimes, Child sexual exploitation, Indiscriminate weapons and Suicide and self-harm selected, and lists only decision models. Ask is either together (one question listing every selected category, the default) or one yes/no question per category, which is more accurate on self-hosted Nimble and Clef but makes one call per category; the editor shows the number of calls. A check takes at most 25 categories.
A category counts when the classifier is at least as sure as its minimum confidence. One violation records every category that counted, by name, ordered by confidence. In block mode a request is refused; replies are always observed and logged, never withheld. A category a policy uses cannot be deleted or turned off until it is removed from that policy. Under a mandatory policy the selected categories are a floor: a more specific policy may add categories, never remove one, and cannot switch the method.
Child Safety (every edition)
Child Safety is one set of rules for the children on a gateway, free on every edition. Open Administration → Safety & Security → Child Safety, switch it on, choose a safety model and add the children. The rules follow each child to every model they can use — current and future ones, organization and personal-plan models alike — in Janus Chat and through the API. They go by who the child is, not by the model they pick or the workspace they work under, so a grant to everyone or a newly added model is covered without any upkeep. Child Safety is not a policy you bind: it applies to the children in addition to, and after, any Security policies that apply to them.
Add a child directly, or a group (team) of children, and give each an age range: Little kids (8 and under), Kids (9-12) or Teens (13-17), or your own range copied from one of them. A child’s own age range wins over their groups’; a child in several groups gets the strictest setting of each category.
Each age range sets six categories — Feeling low or unsafe, Not suitable for children, Getting around parental controls, Sharing personal information, Homework done for them, and Homework learning — to Off, Answer appropriately or Block. Answer appropriately sends the message to the model with that category’s instructions added to the system prompt (editable, with Reset to built-in). Block answers with a short, kind refusal that names no category; the message is not sent to the model, and administrators are notified. For Feeling low, Block means Janus answers itself with a kind message pointing to a trusted adult and the 988 Suicide & Crisis Lifeline (911 in an emergency, Childhelp 1-800-422-4453 if home does not feel safe), and every administrator is told the child may need support — never what they wrote.
Out of the box, Little kids blocks Feeling low or unsafe, Not suitable for children and Getting around parental controls; Kids blocks Feeling low or unsafe; Teens blocks none of them and gets a milder Not suitable for children text. Every other category is set to Answer appropriately. A new range starts as a copy of the one selected.
Each message is judged with the recent conversation as context, so a follow-up is read for what it refers to: “how do I do that without my parents knowing?” right after asking where to buy a vape is treated as the same request. The last six earlier messages are included (user messages cut to their first 1,000 characters and assistant replies to their first 300) with the latest message marked as the one to judge. A message long enough to be checked in several windows is checked window by window, without the context.
Every message from a child also gets the age range’s “every message” text. While either homework category is set to Answer appropriately, every message also gets the tutor rule: never give the final answer, the result or a worked solution, even after the child tries — when they share an answer, say only whether it is right or wrong and which step to look at again. Replies are checked for an answer given away; one that does stops there and ends with a short note encouraging the child to work it out. That is the tutor working, not an incident, so it does not notify anyone.
A fixed set of safety categories is blocked for every child in every age range, in what they send and what the model answers: child sexual exploitation, sexual content, sex-related crimes, violent crimes, indiscriminate weapons, suicide and self-harm (which always gets the kind answer), hate, and non-violent crimes such as drugs. Replies are also checked for the categories the age range blocks, except Feeling low or unsafe and the homework categories, so a kind reply to a sad child is never cut. A reply is checked a paragraph at a time: each paragraph is held until the safety model clears it; a reply that is stopped ends with a short notice. Children can use chat completions, completions and embeddings. Each age range also has What they can make: four switches — Make pictures, Make videos, Make music, Turn speech into text — all off by default. When one is on, children in that range can use it, in Chat and on its endpoint (/v1/images/generations, /v1/videos, music models, /v1/audio/transcriptions); what they ask for is checked first, like any message. When it is off, Chat does not offer it and the endpoint is refused. With Turn speech into text on, sound and video files a child attaches in Chat are always turned into text and checked before the model reads them; with it off, those files are refused. Pictures a child attaches themselves are passed to the model and are not checked. Every other endpoint (the Responses and Messages APIs, speech, decisions) is refused for them.
What Chat reads for a child (a web page, search results, the text of an attached sound or video file) is judged like a reply, as content shown to the child. Flagged content is withheld from the model and never treated as something the child asked: no support message and no parent notice.
Block these models is optional: the rules already apply to every model, so use it only to keep an age range off particular models. Aliases and routers can be blocked too. A blocked model is hidden from the child’s model list, refused, and never picked by Chat for images, video, music, transcripts or video descriptions. It stays blocked when it or its alias is renamed.
A child cannot leave a team that keeps Child Safety on for them. If a team is deleted, a member is removed, or a directory sync takes someone out of the team, administrators get a “Child Safety no longer covers …” notification. Deleting a team removes its Child Safety assignment.
Any decision model works as the safety model: hosted Jev is recommended as the fastest and most accurate in our tests, but hosted means the messages and replies are sent to that provider to be checked. For fully local checking use Clef; for lower delay on local hardware use Nimble or Clef-Flash, ideally asking one question per category. A Llama Guard model is also listed (marked legacy), but it checks only the always-blocked safety categories, not the six age-range categories; use a decision model. With Child Safety on, the page shows a red Not protecting state, with the reason, until a model is chosen and at least one child is added; nothing is filtered without a model; once one is chosen, a model that is missing or not answering refuses the children's messages (fail closed) and touches no one else.
Events are listed on the page and under Security → Violations. Administrators get an in-app notification when a child’s message or a reply to them is blocked (at most one every 15 minutes per child, across all replicas) and every time a child may need support; none is sent when the safety model was unavailable. Child Safety itself never keeps what a child wrote. Janus Chat keeps the child’s conversation like anyone else’s, and a running troubleshooting session with body capture on also captures it. Alert rules can subscribe to the Child Safety trigger (family_safety in the API) for webhooks (and email, on Business). When a category was answered appropriately, the request’s details in the request log show a Child Safety line naming it (for example “Answered appropriately: Homework learning”), on auto-routed requests too. Other Security policies work on every edition in observe mode; redacting or blocking with them (secrets, personal data, term lists, shape, prompt injection, content safety) needs Business.
Content safety: Llama Guard compatible
Content safety is a second, separate check backed by a different kind of classifier. Llama Guard is a generative model served on a chat engine such as vLLM: add that server as an ordinary OpenAI-compatible upstream, let discovery find the model, and mark it as a generative guard on Security → Classifiers. The two roles are not interchangeable — a Prompt Guard encoder cannot judge hazard categories and a Llama Guard cannot score injection — so a policy that binds the wrong role is refused when saved, with the reason.
The guard judges each conversation turn against the MLCommons hazard taxonomy (S1 Violent Crimes through S14 Code Interpreter Abuse) and answers safe or unsafe with the categories that apply. The policy names which categories to enforce. A verdict blocks only when it names a selected category; anything the guard flags outside the selection is still recorded as observed, so you can see what a category would catch before enforcing it. An empty selection enforces every category. Under a mandatory policy the selection is a floor: a more specific binding may add categories, never remove one.
On requests the check can block. On responses, in this version, it observes and logs only: the guard judges the answer in the context of the prompt it replies to, and the verdict lands in Violations with its categories, but the response is never withheld. A generative verdict cannot be produced inside a streaming hold-back window, and blocking buffered responses while streamed ones pass would be a control that only works when the caller happens not to stream. The editor refuses block on egress for that reason. Streamed responses are not judged at all.
Limitations to state plainly
Text only: images, audio and file attachments are metered but not scanned. Per-message: material split across turns of a conversation is not correlated. Non-English and encoded text (base64, leetspeak beyond the fuzzy term folding) materially reduce catch rates for the classifier. Streaming classifier-backed egress checks are not in this version: a content classifier needs a sentence or two, by which time that text is on the user's screen.