Prompt Injection Protection

Automatic safety wrapping for results from external/untrusted tools

Web search and other external tools wrap results in safety markers β€” the model treats them as data, not instructions.

python
from praisonaiagents import Agent
from praisonaiagents.tools import duckduckgo

agent = Agent(
    name="Researcher",
    instructions="Research topics safely",
    tools=[duckduckgo],
)

agent.start("Find recent AI safety papers")
# duckduckgo results auto-wrapped in <external_tool_result> markers

The user searches the web; external tool output is wrapped so the model treats it as data.

Diagram

Trust-Aware Tool Execution

Trusted

External

πŸ› οΈ Tool call

πŸ” External?

⚑ Pass through

πŸ›‘οΈ Wrap in markers

βœ… Safe result

Quick Start

  1. Simple Usage

    Built-in search tools are protected automatically:

    python
    from praisonaiagents import Agent
    from praisonaiagents.tools import duckduckgo
    
    agent = Agent(
        name="Researcher",
        instructions="Research topics safely",
        tools=[duckduckgo],
    )
    
    agent.start("Find recent AI safety papers")
  2. With Configuration

    Mark custom tools as external:

    python
    from praisonaiagents import Agent, register_tool
    
    def my_web_lookup(query: str) -> str:
        """Fetch data from an external API."""
        return fetch_from_api(query)
    
    register_tool(my_web_lookup, name="my_web_lookup", trust_level="external")
    
    agent = Agent(
        name="Researcher",
        instructions="Use my_web_lookup for facts",
        tools=["my_web_lookup"],
    )

How It Works

Diagram
LLMTrust layerExternal toolAgentLLMTrust layerExternal toolAgentExecuteRaw resultWrapped in markersTreat as factual data only

Auto-protected built-ins include duckduckgo, web_search, tavily_search, scrape_page, fetch_url, and others in the external tools set. MCP tools can be marked at registration time.

Outbound tool results are wrapped in <external_tool_result>; inbound webhook and hook payloads are wrapped in <external_request_payload> β€” same idea, opposite direction. See Untrusted Request Fencing for the ingress boundary.

ConditionAction
Trusted toolResult unchanged
External + string β‰₯ 32 charsWrapped in <external_tool_result>
External + string &lt; 32 charsUnchanged (overhead skip)
External + dict/listJSON-serialised then wrapped
Inbound webhook / hook payloadWrapped in <external_request_payload> at ingress

What happens if the trust decision fails

When the trust registry exists but raises while answering a trust lookup, PraisonAI now fails closed: the tool is treated as external and its result is fenced. Under-fencing an external tool is the exact bug the fence exists to prevent, so a broken registry never quietly downgrades a tool to “trusted”.

The one exception is “no registry at all” (e.g. a slim build): the hardcoded external list is the whole answer there, so unknown tools stay trusted β€” otherwise every ordinary function tool would be fenced.

SituationResult
Tool is in the hardcoded external listExternal β€” result is fenced
Registry exists and says EXTERNALExternal β€” result is fenced
Registry exists and says TRUSTED (or None)Trusted β€” result passes through
Registry exists and raises while answeringExternal β€” result is fenced (fail closed)
No registry available at allTrusted (fallback to hardcoded list only)

Fixed in PR #4969.


Configuration Options

OptionTypeDefaultDescription
trust_level"trusted" \"external""trusted"Set on register_tool(..., trust_level="external")
MIN_CONTENT_LENGTH_FOR_WRAPPINGint32Minimum string length before wrapping
Registry lookup errorβ€”β€”Treated as external (fail closed)

Programmatic Injection Defense

The auto-wrap above protects tool outputs. To also scan all agent prompts at the hook layer, enable the injection-defense pipeline:

python
from praisonai.security import enable_injection_defense

hook_ids = enable_injection_defense()

This registers hooks on BEFORE_TOOL and BEFORE_AGENT that scan inputs through a 6-check pipeline and block critical threats.

One-liner (both defenses)

python
from praisonai.security import enable_security

hook_ids = enable_security()  # injection defense + audit log

Best Practices

Mark external data sources as external

Web APIs, scraping, MCP servers you do not control, and third-party feeds should use trust_level="external".

Do not strip safety markers

Removing <external_tool_result> tags breaks the model’s boundary between data and instructions.

Prefer external when unsure

Wrapping cost is minimal; under-marking exposes you to injection.

Layer with other guards

Combine with Tool Circuit Breaker and input validation for defence in depth.

Scope hooks in multi-tenant hosts

The hook registry is process-global. In multi-tenant servers, hold the returned hook IDs and remove them via praisonaiagents.hooks.remove_hook on teardown, or add per-request hooks manually instead of using the enable_* one-liner.



Related