Skip to main content
Lesson 17 of 18 · Mistral Agents: Building Autonomous AI

Secure agents with guardrails

Lesson 17 of 18 Updated November 3, 2026 Developer
On this page
  1. Agent security is not optional
  2. The guardrails parameter
  3. Instructions: your first line of defense
  4. The principle of least privilege
  5. Filter handoffs
  6. Don’t store what doesn’t need to be stored
  7. Moderate upstream
  8. Tune generation
  9. Before going to production
  10. Key takeaways

Updated November 3, 2026. Both examples previously passed guardrails={"enabled": True}, a format that does not exist: the official parameter is a list of moderation_llm_v2 configurations, with a threshold per category. The text also clarifies what the documentation states about their scope: they only moderate the incoming message. Sources: Moderation & Guardrailing · Agents & Conversations · SDK mistralai 3.7.0.

Agent security is not optional

An autonomous agent that uses tools, accesses the internet, and executes code poses a risk if its actions are not constrained. The difference from a simple completion call is fundamental, not just a matter of degree: a model that produces text can be corrected upon review, but an agent that acts has already acted. Guardrails are the set of mechanisms that define the boundaries of what an agent can and cannot do. None of them is sufficient on its own; it is their layering that provides protection.

The guardrails parameter

The first level is declared when creating the agent.

from mistralai.client import Mistral
import os

client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])

agent = client.beta.agents.create(
    model="mistral-large-latest",
    name="Secure Agent",
    description="Agent with guardrails enabled.",
    instructions="""You are a professional assistant.
- Never share personal information
- Never generate inappropriate content
- Refuse out-of-scope requests
- If in doubt, ask for clarification""",
    tools=[{"type": "web_search"}],
    guardrails=[
        {
            "block_on_error": True,
            "moderation_llm_v2": {
                "custom_category_thresholds": {
                    "sexual": 0.1,
                    "hate_and_discrimination": 0.1,
                    "violence_and_threats": 0.2,
                    "criminal": 0.1,
                    "selfharm": 0.1,
                    "pii": 0.2,
                    "jailbreaking": 0.2,
                },
                "action": "block",
            },
        }
    ],
)

Each listed category receives a threshold from 0 to 1: beyond this point, the user’s message is rejected with a 403 error before reaching the model, and block_on_error also rejects the request if the evaluation itself fails. According to the documentation, all conversations for the agent inherit these guardrails. They only moderate the input: neither web search results nor the agent’s response are checked by them.

The same parameter is accepted at the conversation level, where it overrides the agent’s configuration. This lets you temporarily tighten the behavior of a shared agent without creating a second version of that agent for a single use case.

response = client.beta.conversations.start(
    agent_id=agent.id,
    inputs="Analyze this confidential document.",
    guardrails=[  # replaces the agent's guardrails for this conversation
        {
            "block_on_error": True,
            "moderation_llm_v2": {
                "custom_category_thresholds": {"pii": 0.05, "jailbreaking": 0.1},
                "action": "block",
            },
        }
    ],
)

Instructions: your first line of defense

The system prompt remains the most effective lever because it acts before any model decision. A well-constructed security prompt clearly separates the role, scope, prohibitions, and expected format.

instructions = """## Role
You are a legal assistant specializing in French labor law.

## Scope
- ONLY French labor law
- Refuse any out-of-scope questions (tax, real estate, criminal law, etc.)

## Strict Prohibitions
- NEVER give definitive legal advice
- NEVER draft legal documents without a disclaimer
- NEVER share information about other clients
- ALWAYS mention that a lawyer must validate

## Format
- Cite relevant legal articles
- Clearly state the limits of your response
- Always propose consulting a professional"""

Notice what the “Scope” section does: it doesn’t just say what the agent handles; it explicitly names the adjacent domains it must refuse. Without this enumeration, a tax question related to a dismissal might slip through because it resembles labor law enough for the model to engage. The “Strict Prohibitions” section follows the same logic: it formulates refusals, not recommendations. An agent told to be “cautious” calibrates its own caution; an agent forbidden from drafting without a disclaimer applies a rule.

The principle of least privilege

Every declared tool is a capability the agent can mobilize at the wrong time. Compare these two configurations.

# Too many tools — large attack surface
dangerous_agent = client.beta.agents.create(
    model="mistral-large-latest",
    name="do-it-all-agent",
    tools=[
        {"type": "web_search"},
        {"type": "code_interpreter"},
        {"type": "image_generation"},
        {"type": "document_library", "library_ids": [lib.id]}
    ]
)

# Principle of least privilege — only what is necessary
secure_agent = client.beta.agents.create(
    model="mistral-large-latest",
    name="documentation-agent",
    tools=[{"type": "document_library", "library_ids": [lib.id]}]
)

The second agent cannot go online to fetch information missing from your documents, nor execute code on content you haven’t reviewed. This isn’t a limitation you suffer; it’s the guarantee that its answers come from your knowledge base and nowhere else. Ask yourself tool by tool—if you can’t find a scenario where the agent needs it, remove it.

Filter handoffs

In a multi-agent system, client mode gives you veto power over every handoff. A whitelist is enough to prevent one agent from reaching another via a path you didn’t anticipate.

response = client.beta.conversations.start(
    agent_id=router.id,
    inputs=user_query,
    handoff_execution="client"
)

ALLOWED_AGENTS = {research.id, analyst.id}  # Whitelist

for entry in response.outputs:
    if entry.type == "agent.handoff":
        if entry.next_agent_id not in ALLOWED_AGENTS:
            print(f"BLOCKED: unauthorized handoff to {entry.next_agent_id}")
            continue
        # Continue with the authorized agent

The whitelist lives in your code, not in the agent configuration: it remains valid even if someone adds a handoff target to the router without notifying you.

Don’t store what doesn’t need to be stored

For sensitive data, the best protection is to store nothing.

response = client.beta.conversations.start(
    agent_id=agent.id,
    inputs="Confidential data: Q1 2026 financial report...",
    store=False  # Nothing persists
)

This setting is decided per conversation, which lets you retain the history of ordinary exchanges while processing confidential content in ephemeral mode.

Moderate upstream

An elegant variant is to place a moderation agent at the head of the chain: it examines the request and only transfers it to the specialist if it is acceptable.

moderator = client.beta.agents.create(
    model="mistral-large-latest",
    name="moderator",
    description="Checks that requests are appropriate.",
    instructions="""Analyze the user request:
- If appropriate: transfer to the specialist
- If inappropriate: politely reply that the request is not supported
- If ambiguous: ask for clarification"""
)

specialist = client.beta.agents.create(
    model="mistral-large-latest",
    name="specialist",
    description="Handles validated requests.",
    tools=[{"type": "web_search"}]
)

moderator = client.beta.agents.update(
    agent_id=moderator.id,
    handoffs=[specialist.id]
)

The value of this pattern lies in the separation of roles: the moderator has no tools and does only one thing, so a malicious request it rejects never reaches the agent that knows how to act.

Tune generation

Completion parameters also contribute to security for a simple reason: a hallucinated response is a risk, and creativity is its breeding ground.

agent = client.beta.agents.create(
    model="mistral-large-latest",
    name="Factual Agent",
    description="Factual and conservative agent.",
    completion_args={
        "temperature": 0.1,   # Very low creativity
        "top_p": 0.85,        # Restricted nucleus
        "max_tokens": 1024    # Short responses
    }
)

A temperature of 0.1 paired with a top_p of 0.85 leaves the model very little latitude: for a question whose answer appears in your documents, it retrieves it instead of embroidering a variant. The 1024-token cap plays a similar role, because a response that grows too long eventually strays from the documented scope and produces filler. These settings obviously don’t suit a creative agent, but they are the default configuration for any agent expected to state facts—legal assistant, technical support, product expert.

Before going to production

These mechanisms are only valid when layered, and the final check comes down to a few verifications. Instructions must explicitly define scope and prohibitions, and the agent must have only the tools strictly necessary for its task. Verify that guardrails are enabled, and that critical workflows run in client mode so no handoff executes without your approval. Ensure store=False accompanies any conversation involving sensitive data, and that temperature remains low wherever the agent is expected to stay factual. Finally, place a moderation agent in front of the chain so that unacceptable requests never reach the agents that know how to act.

Key takeaways

  • Guardrails are configured at the agent and/or conversation level
  • Instructions are your first line of defense—be explicit about prohibitions
  • Apply the principle of least privilege: give only the necessary tools
  • Client mode allows you to validate and block unauthorized handoffs
  • In production: upstream moderation, logging, agent whitelist, store=False for sensitive data