Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.praison.ai/llms.txt

Use this file to discover all available pages before exploring further.

Bot security enables safe deployment of PraisonAI agents across messaging channels with built-in protection against abuse and unauthorized access.

Quick Start

1

Basic Security Setup

from praisonaiagents import Agent
from praisonaiagents.bots import BotConfig

# Secure bot with allowlist
config = BotConfig(
    allowed_users=["@your_username", "123456789"],
    unknown_user_policy="deny"  # Default secure behavior
)

agent = Agent(
    instructions="You are a helpful assistant",
    # Bot configuration handled by adapter
)
2

Advanced Security Config

from praisonaiagents import Agent
from praisonaiagents.bots import BotConfig

# Production security setup with pairing
config = BotConfig(
    allowed_users=["@admin_user"],
    unknown_user_policy="pair",  # Secure pairing flow
    auto_approve_tools=True,     # For bot environments
    group_policy="mention_only"  # Only respond when mentioned
)

agent = Agent(
    instructions="Secure production assistant",
    # Configure with your bot adapter
)

How It Works

ComponentPurposeStatus
AllowlistControl accessConceptual
DM PolicyMessage filteringConceptual
PairingChannel authorizationConceptual

Security Model

OpenClaw-style security for messaging bots. This guide covers DM pairing, allowlists, and safe defaults across Telegram, Discord, Slack, WhatsApp, and other channels.
PraisonAI treats inbound DMs as untrusted input by default. Production deployments should use explicit pairing and allowlists to prevent abuse, spam, and prompt injection from unknown senders.

Safe Defaults by Channel

Telegram

Recommended production config:
# bot.yaml
channels:
  telegram:
    token: ${TELEGRAM_BOT_TOKEN}
    allowlist:
      - "@your_username"
      - "123456789"  # User ID
    group_policy: "mention_only"  # Only respond when mentioned
Security features:
  • ✅ User allowlist by username or ID
  • ✅ Group mention-only policy
  • ✅ Built-in command filtering
  • ⚠️ DMs from unknown users are processed by default

Discord

Recommended production config:
# bot.yaml  
channels:
  discord:
    token: ${DISCORD_BOT_TOKEN}
    allowlist:
      - "your_user_id"
      - "guild:server_id"  # Specific server only
    group_policy: "mention_only"
Security features:
  • ✅ User/guild allowlist support
  • ✅ Role-based restrictions
  • ✅ Thread-safe message handling
  • ⚠️ DMs from unknown users are processed by default

Slack

Recommended production config:
# bot.yaml
channels:
  slack:
    token: ${SLACK_BOT_TOKEN}
    app_token: ${SLACK_APP_TOKEN}
    allowlist:
      - "U0123456789"  # User ID
      - "C9876543210"  # Channel ID
    group_policy: "mention_only"
Security features:
  • ✅ User/channel allowlist
  • ✅ Enterprise Grid support
  • ✅ Socket mode security
  • ✅ Built-in DM filtering (mentions required)

WhatsApp

Recommended production config:
# bot.yaml
channels:
  whatsapp:
    allowlist:
      - "+1234567890"    # Phone numbers
      - "group123@g.us"  # Group IDs
    blocklist:
      - "+spam_number"
Security features:
  • Strong default security - allowlist required for DMs
  • ✅ Phone number + group allowlists
  • ✅ Built-in self-chat detection
  • ✅ Automatic spam filtering
WhatsApp has the strongest security defaults and serves as the reference implementation for other channels.

Owner-DM Pairing

The pairing system is now shipped and enables owner-approval for unknown users with inline Approve/Deny buttons sent directly to your DM. For production deployments, use owner-DM pairing to authorize unknown users dynamically:

1. Set Callback Secret

export PRAISONAI_CALLBACK_SECRET="$(openssl rand -hex 32)"
Without PRAISONAI_CALLBACK_SECRET, inline-button callbacks will not work across restarts. Set this in production.

2. Configure Unknown User Policy

from praisonaiagents import Agent
from praisonaiagents.bots import BotConfig

config = BotConfig(
    token="your-bot-token",
    unknown_user_policy="pair",     # Enable owner-approval workflow
    owner_user_id="123456789",      # Your platform user ID
)

agent = Agent(
    name="Support Bot",
    instructions="Help users with their questions",
)

3. Owner Approval Workflow

When an unknown user messages your bot:
  1. Bot generates a pairing code
  2. Owner receives DM with inline Approve/Deny buttons
  3. Owner clicks Approve → User is permanently approved
  4. Owner clicks Deny → Request is rejected
CLI Fallback: If owner_user_id is not set, the bot replies:
Your pairing code: abc12345. Ask the owner to run: praisonai pairing approve telegram abc12345

4. Manual Approval (CLI)

Owners can approve pairing requests manually:
# Approve a specific pairing code
praisonai pairing approve telegram abc12345

# Approve for Discord
praisonai pairing approve discord def67890

# Approve for Slack
praisonai pairing approve slack ghi13579

Gateway Pairing

For production deployments, use gateway pairing to authorize channels dynamically with the shipped pairing system:
The gateway secret is optional - if unset, a per-install secret is auto-generated at <store_dir>/.gateway_secret with 0600 permissions and reused across restarts.

Enable Pairing Policy

from praisonaiagents.bots import BotConfig

config = BotConfig(
    allowed_users=["@owner"],
    unknown_user_policy="pair"  # Enable pairing for unknown users
)

# Unknown users will automatically receive pairing codes when they DM the bot

Approve Pairing Requests

When unknown users DM your bot, they receive pairing codes. Approve them via CLI:
# User receives: "Your pairing code: ABCD1234"
# Owner approves:
praisonai pairing approve telegram ABCD1234 --label "alice"

Manage Pairings

# List all paired channels
praisonai pairing list

# Revoke access for specific channel
praisonai pairing revoke telegram 987654321

# Clear all pairings
praisonai pairing clear --confirm
For detailed pairing documentation, see the Bot Pairing guide.

List Pending Requests

List all pending pairing codes waiting for approval:
from praisonai.gateway.pairing import PairingStore

store = PairingStore()

# All pending codes across every channel
for req in store.list_pending():
    print(req["code"], req["channel_type"], req["channel_id"], req["age_seconds"])

# Filter by channel
telegram_only = store.list_pending(channel_type="telegram")
Response Schema:
KeyTypeSourceNotes
codestrcanonical8-char pairing code
channel_typestrcanonicale.g. "telegram", "discord", "slack", "whatsapp"
channel_idstr | NonecanonicalBound channel id if code was generated with one
created_atfloatcanonicalUnix timestamp (seconds) when code was generated
channelstrUI aliasSame value as channel_type, kept for UI banner compatibility
user_idstrUI aliasCurrently equals code (see note in approve() docstring)
user_namestrUI aliasFormatted as "User {code}"
age_secondsintUI aliasint(now - created_at)
Canonical keys (code, channel_type, channel_id, created_at) are the stable contract. The channel, user_id, user_name, and age_seconds aliases are provided for UI consumers and should not be relied on for scripting — use the canonical keys.

CLI Commands

Use the praisonai pairing commands to manage pairings from the command line:
# List all paired channels
praisonai pairing list

# Approve a pairing code (this is the exact command shown to users)
praisonai pairing approve telegram abc12345

# Revoke a paired channel
praisonai pairing revoke telegram @username

# Clear all paired channels
praisonai pairing clear
Available Commands:
CommandPurposeRequired Args
praisonai pairing listList all paired channels
praisonai pairing approve PLATFORM CODE [CHANNEL_ID]Approve an 8-char pairing codeplatform, code
praisonai pairing revoke PLATFORM CHANNEL_IDRevoke a paired channelplatform, channel_id
praisonai pairing clearClear all paired channels
Platform values: telegram, discord, slack, whatsapp Pairing Flow:

7. REST API

The gateway exposes REST endpoints for pairing management:
MethodPathBody / QueryResponseAuth Required
GET/api/pairing/pendinglist_pending() schema
POST/api/pairing/approve{ "channel": str, "code": str }{ "approved": true, ... }
POST/api/pairing/revoke{ "channel": str, "user_id": str }{ "revoked": true, ... }
Example Usage:
# List pending requests
curl -H "Authorization: Bearer $TOKEN" \
  http://localhost:8000/api/pairing/pending

# Approve a code  
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -d '{"channel":"telegram","code":"abc12345"}' \
  http://localhost:8000/api/pairing/approve

# Revoke a channel
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -d '{"channel":"telegram","user_id":"@username"}' \
  http://localhost:8000/api/pairing/revoke
All endpoints are authenticated and rate-limited. Rate limits are applied per client IP with separate buckets for pairing_pending, pairing_approve, and pairing_revoke operations.

Doctor Security Check

Use the built-in doctor to audit your bot security configuration:
praisonai doctor --category bots
The security check flags:
  • Missing allowlists - channels without allowlist/blocklist
  • ⚠️ Permissive group policies - respond_all in production
  • ⚠️ Missing gateway secret - pairing codes won’t persist
  • Secure configuration - allowlists + mention-only policies
Example output:
Bot Security Config: WARN  
Security recommendations: 2 channel(s) could use stricter defaults

Details:
telegram: No allowlist/blocklist configured
discord: group_policy='respond_all' - consider 'mention_only' for security

Remediation: Consider allowlists for DM security and 'mention_only' group policy

Self-Hoster Security Checklist

Before going public with your bot:
  • Allowlist configured for each channel
  • Unknown sender behavior defined (block/ignore/process)
  • Group policies set to mention_only or command_only
  • Blocklist configured for known spam sources
  • PRAISONAI_GATEWAY_SECRET set
  • PRAISONAI_CALLBACK_SECRET set (for inline buttons)
  • unknown_user_policy configured (deny/pair/allow)
  • owner_user_id set for inline approvals
  • Pairing workflow tested and verified
  • Revocation process documented
  • Dangerous tools require approval (not auto-approved)
  • Approval backend configured (Slack/Telegram/HTTP)
  • Tool risk levels reviewed and appropriate
  • Approval timeout configured
  • Bot security doctor check passing
  • Audit logging enabled (praisonai.security.enable_audit_log)
  • Injection defense active (praisonai.security.enable_injection_defense)
  • Rate limiting configured for API calls
  • Bot tokens stored securely (not in code)
  • Environment variables encrypted at rest
  • Network access restricted (firewall rules)
  • Regular security updates scheduled

Common Security Patterns

1. Staged Rollout

Start with restrictive settings and gradually open access:
# Stage 1: Internal testing
channels:
  telegram:
    allowlist: ["@internal_team"]
    group_policy: "command_only"

# Stage 2: Trusted users
channels:
  telegram:
    allowlist: ["@internal_team", "@trusted_users"]  
    group_policy: "mention_only"

# Stage 3: Public (with safety nets)
channels:
  telegram:
    # Remove allowlist for open access
    group_policy: "mention_only"
    rate_limit: 10  # messages per minute

2. Multi-Channel Allowlist

Maintain consistent allowlists across channels:
# Shared allowlist
x-allowlist: &shared-users
  - "admin_user_1"
  - "admin_user_2"
  - "trusted_group_1"

channels:
  telegram:
    allowlist: *shared-users
  discord:
    allowlist: *shared-users  
  slack:
    allowlist: *shared-users

3. Environment-Based Security

Different security levels per environment:
# development.yaml - loose security
channels:
  telegram:
    # No allowlist for dev testing
    group_policy: "respond_all"

# staging.yaml - moderate security
channels:
  telegram:
    allowlist: ["@staging_team"]
    group_policy: "mention_only"
    
# production.yaml - strict security  
channels:
  telegram:
    allowlist: ["@verified_users"]
    group_policy: "command_only"
    approval: true  # All tools need approval

Security Headers & API Protection

When running bot gateways, enable security headers:
from praisonai.gateway import GatewayServer

server = GatewayServer(
    host="0.0.0.0",
    port=8765,
    security_headers=True,  # Add CORS, CSP, etc.
    rate_limit=True,        # Enable rate limiting
    require_https=True,     # Redirect HTTP to HTTPS
)

Advanced: Custom Security Hooks

Implement custom security logic with hooks:
from praisonaiagents.hooks import add_hook, HookResult

@add_hook('before_tool')
def channel_security_check(event_data):
    """Custom security check based on channel type"""
    channel = event_data.context.get('channel_type')
    sender = event_data.context.get('sender_id') 
    tool_name = event_data.tool_name
    
    # Block file operations from Telegram DMs
    if channel == 'telegram' and tool_name in ['write_file', 'delete_file']:
        if not is_verified_user(sender):
            return HookResult.block("File operations not allowed from unverified Telegram users")
    
    # Require approval for shell commands from all channels
    if tool_name == 'execute_command':
        return HookResult.request_approval(f"Shell command from {channel}: {sender}")
    
    return HookResult.allow()

def is_verified_user(user_id: str) -> bool:
    """Check if user is in verified allowlist"""
    verified_users = os.environ.get('VERIFIED_USERS', '').split(',')
    return user_id in verified_users

Troubleshooting

Pairing Issues

Problem: Pairing codes not working Solution:
  1. Check PRAISONAI_GATEWAY_SECRET is set
  2. Verify code hasn’t expired (5 min default)
  3. Ensure code typed exactly (case sensitive)
Problem: Pairing lost after restart Solution:
  1. Set PRAISONAI_GATEWAY_SECRET env var
  2. Codes without persistent secret are temporary
Problem: praisonai pairing approve reports “Invalid or expired code” even though a code was just generated from the UI Solution:
  1. Upgrade to the latest praisonai version (fix included in 2026-04-22 release)
  2. Older builds had a duplicate internal method that stripped the canonical code key when the UI pairing banner was loaded

Allowlist Issues

Problem: Bot not responding to allowed users Solution:
  1. Check exact user ID format (username vs numeric ID)
  2. Verify allowlist syntax in YAML
  3. Run praisonai doctor for validation
Problem: Bot responding to blocked users Solution:
  1. Check allowlist is configured (not just blocklist)
  2. Verify group_policy setting
  3. Check if user has alternate access path


Best Practices

  • Use explicit allowlists for all channels
  • Regularly review and update allowed users
  • Implement role-based access where possible
  • Log all access attempts for audit trails
  • Store tokens in environment variables
  • Rotate secrets regularly
  • Use encrypted storage for sensitive data
  • Never commit secrets to version control
  • Implement per-user rate limits
  • Set global request quotas
  • Monitor for unusual activity patterns
  • Implement exponential backoff for failed requests
  • Enable audit logging
  • Monitor security events
  • Set up alerting for suspicious activity
  • Regular security reviews

Agent Configuration

Core agent setup and configuration

Gateway Setup

Multi-channel gateway configuration

By following these security practices, your PraisonAI bots will operate safely in production while maintaining the flexibility to serve legitimate users. Regular security audits help ensure your configuration stays secure over time.