Security & Redaction
Privacy hardening for context snapshots and monitoring
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.
How It Works
Quick Start
- 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) - 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.
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.)
Redaction Patterns
Automatically redacted:
| Pattern | Example |
|---|---|
| OpenAI keys | sk-abc123... |
| Anthropic keys | sk-ant-... |
| Google API keys | AIzaSy... |
| Google OAuth | ya29.... |
| AWS access keys | AKIA... |
| Bearer tokens | Bearer ... |
| Passwords | password = "..." |
| API keys | api_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.
from praisonaiagents.trace.redact import redact_string
dsn = "postgres://admin:hunter2@db.internal:5432/app"
print(redact_string(dsn))
# postgres://[REDACTED]@db.internal:5432/appAn agent that echoes a DSN into its prompt stops leaking it once redaction is on:
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/appUsing Redaction
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.
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:
| Rule | Example | Result |
|---|---|---|
| POSIX leading slash | /etc/passwd, \context.txt | Absolute |
| Windows drive with separator | C:\Windows, C:/data | Absolute |
| Home reference | ~/context.txt | Blocked 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:
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
*.mdConfiguration
config = ManagerConfig(
redact_sensitive=True, # Enable redaction
allow_absolute_paths=False, # Block absolute paths
monitor_path="./context.txt",
)Environment Variables
export PRAISONAI_CONTEXT_REDACT=trueRedaction in Snapshots
All snapshot outputs are redacted:
# Human format
# API key: [REDACTED]
# JSON format
# {"content": "API key: [REDACTED]"}Adding Custom Patterns
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
Snapshot output and formats
Protected PathsRestrict file access in agents
HooksSequential vs parallel hooks — why redaction must be sequential
Hook EventsWhich events read/write modified_input
Opt-in redaction for praisonai session export — stable placeholders, standard vs strict