Security & Redaction

Privacy hardening for context snapshots and monitoring

Diagram

Security & Redaction

📋 User Request

⚙️ Security & Redaction

✅ Result

Diagram
Security & RedactionAgentUserSecurity & RedactionAgentUserRequestProcess requestResultResponse
python
from praisonaiagents import Agent

agent = Agent(
    name="secure-agent",
    instructions="Redact sensitive data from context before processing.",
)
agent.start("Process this document and redact all PII.")

Context security features protect sensitive data in snapshots and validate output paths.

The user sends messages containing secrets; redaction strips sensitive fields before context reaches the LLM.

Diagram

Security & Redaction

📝 Raw Input

🛡️ Redact PII

🤖 Agent

✅ Safe Snapshot

How It Works

Diagram
LLMRedactorAgentUserLLMRedactorAgentUserMessage with secretsredact_sensitive=TrueSanitised contextResponse without leaked PII

Quick Start

  1. Enable redaction in config
    python
    from praisonaiagents import ContextManager, ManagerConfig
    
    config = ManagerConfig(
        redact_sensitive=True,
        allow_absolute_paths=False,
        monitor_path="./context.txt",
    )
    manager = ContextManager(config=config)
  2. Redact text directly
    python
    from praisonaiagents.context import redact_sensitive
    
    safe = redact_sensitive("My API key is sk-abc123def456ghi789")
    # "My API key is [REDACTED]"

Automatic PII redaction on every LLM call

enable_pii_redaction() scrubs secrets from every outgoing message before it reaches the LLM — call it once at process start and all agents in the process are covered.

python
from praisonaiagents import Agent
from praisonaiagents.trace.redact import enable_pii_redaction

# Register once at process start — all agents in this process
# now have their outgoing messages scrubbed before hitting the LLM.
enable_pii_redaction()

agent = Agent(
    name="Assistant",
    instructions="You are a helpful assistant.",
)
agent.chat("My api_key=sk-ABCDEF12345 and password=hunter2 — help me debug?")
# → the literal secret is replaced with [REDACTED] before the request goes out.

enable_pii_redaction() registers a sequential BEFORE_LLM hook. Sequential is what actually mutates the outgoing message stream — parallel hooks cannot write modified_input back. If you built your own PII-style hook, register it with sequential=True or it will silently no-op. (Fixed in PraisonAI PR #4034, released with praisonaiagents versions built from main on/after 2026-08-19.)

Diagram
LLMBEFORE_LLM (sequential)AgentUserLLMBEFORE_LLM (sequential)AgentUserchat(“api_key=sk-… password=hunter2”)scrub outgoing messagesmodified_input (secrets → [REDACTED])scrubbed payloadresponse without leaked secrets

Redaction Patterns

Automatically redacted:

PatternExample
OpenAI keyssk-abc123...
Anthropic keyssk-ant-...
Google API keysAIzaSy...
Google OAuthya29....
AWS access keysAKIA...
Bearer tokensBearer ...
Passwordspassword = "..."
API keysapi_key: "..."
URL userinfo (credentials)postgres://admin:pw@db.internal → postgres://[REDACTED]@db.internal
URL userinfo (token-only)https://ghp_abc123@github.com/o/r.git → https://[REDACTED]@github.com/o/r.git
Bot-token path segment/bot123:AAH-xY_z9/sendMessage → /bot[REDACTED]/sendMessage
Sensitive URL query params?api_key=sk-secret, ?token=... → ?api_key=[REDACTED]

URL-borne secrets

redact_string masks credentials embedded in URLs, and scrub_pii_text and enable_pii_redaction() cover them automatically because they share the same primitive.

python
from praisonaiagents.trace.redact import redact_string

dsn = "postgres://admin:hunter2@db.internal:5432/app"
print(redact_string(dsn))
# postgres://[REDACTED]@db.internal:5432/app

An agent that echoes a DSN into its prompt stops leaking it once redaction is on:

python
from praisonaiagents import Agent
from praisonaiagents.trace.redact import enable_pii_redaction

enable_pii_redaction()  # once at process start

agent = Agent(name="Ops", instructions="Help debug this connection.")
agent.chat("Our DB is postgres://admin:hunter2@db.internal/app — why does it time out?")
# The payload reaching the LLM contains postgres://[REDACTED]@db.internal/app

Using Redaction

python
from praisonaiagents.context import redact_sensitive

text = "My API key is sk-abc123def456ghi789"
safe = redact_sensitive(text)
# "My API key is [REDACTED]"

Path Validation

validate_monitor_path detects absolute paths across operating systems and blocks writes to sensitive system locations.

python
from praisonaiagents import validate_monitor_path

# Cross-platform absolute detection (both POSIX and Windows drives)
validate_monitor_path("/etc/passwd")             # (False, "Absolute paths not allowed ...")
validate_monitor_path("C:\\Windows\\System32")   # (False, "Absolute paths not allowed ...")

# Home reference is blocked
validate_monitor_path("~/context.txt")           # (False, "Suspicious path pattern: ~")

# Drive-relative paths are treated as RELATIVE, not absolute
validate_monitor_path("C:context.txt")           # (True, "")

# Relative paths containing suspicious substrings are accepted
validate_monitor_path("myapp/home/config.txt")   # (True, "")
validate_monitor_path("project/users/ctx.txt")   # (True, "")

# Defence-in-depth: sensitive roots stay blocked even with allow_absolute=True
validate_monitor_path("/etc/passwd", allow_absolute=True)
# (False, "Suspicious path pattern: /etc/")

# A benign absolute path is allowed when opted in
validate_monitor_path("/tmp/context.txt", allow_absolute=True)  # (True, "")

Cross-platform behaviour

Absolute detection follows three rules regardless of the host operating system:

RuleExampleResult
POSIX leading slash/etc/passwd, \context.txtAbsolute
Windows drive with separatorC:\Windows, C:/dataAbsolute
Home reference~/context.txtBlocked as home

A bare drive-relative path like C:context.txt has no separator after the drive, so it is treated as a relative path. Relative project paths that merely contain a matching substring (for example myapp/home/config.txt or project/users/context.txt) are accepted — the suspicious-pattern check only runs when the path is absolute or a home reference.

Suspicious roots blocked include /etc/, /var/, /usr/, /root/, /home/, ~, and the Windows entries /windows/, /system32/, and /users/.

Ignore/Include Patterns

Respect .praisonignore and .praisoninclude files:

python
from praisonaiagents import (
    should_include_content,
    load_ignore_patterns,
)

# Load patterns from files
ignore, include = load_ignore_patterns(".")

# Check if file should be included
if should_include_content("secret.key", ignore, include):
    # Include in snapshot
    pass

.praisonignore

# Ignore patterns (glob)
*.key
*.pem
*.env
secrets/
node_modules/

.praisoninclude

# Include patterns (whitelist)
*.py
*.js
*.md

Configuration

python
config = ManagerConfig(
    redact_sensitive=True,       # Enable redaction
    allow_absolute_paths=False,  # Block absolute paths
    monitor_path="./context.txt",
)

Environment Variables

bash
export PRAISONAI_CONTEXT_REDACT=true

Redaction in Snapshots

All snapshot outputs are redacted:

python
# Human format
# API key: [REDACTED]

# JSON format
# {"content": "API key: [REDACTED]"}

Adding Custom Patterns

python
from praisonaiagents.context.monitor import SENSITIVE_PATTERNS

# Add custom pattern
SENSITIVE_PATTERNS.append(r'my-custom-token-[a-z0-9]+')

Best Practices

Keep redaction enabled

Default redaction is on for a reason — do not disable it in shared or production environments.

Prefer relative paths in snapshots

Absolute paths can leak usernames and directory layout to logs or support tickets.

Maintain .praisonignore

Exclude secrets, credentials, and env files from context indexing and snapshots.

Rotate keys if exposed

If a snapshot ever captured a live secret, rotate the credential immediately — redaction is not retroactive.

Related