Skip to content

Security: 0xinit/PigeonAI

Security

docs/security.md

Security

How your data is protected and security best practices.

Security Overview

The PigeonAI is designed with privacy and security as core principles:

┌─────────────────────────────────────────────────────────────────────┐
│                      SECURITY ARCHITECTURE                           │
│                                                                      │
│  ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐ │
│  │   CREDENTIALS   │    │   MESSAGES      │    │   AI INFERENCE  │ │
│  │                 │    │                 │    │                 │ │
│  │  OS Keyring     │    │  AES-256        │    │  100% Local     │ │
│  │  (encrypted)    │    │  Encrypted      │    │  (no cloud)     │ │
│  └─────────────────┘    └─────────────────┘    └─────────────────┘ │
│                                                                      │
│         Nothing leaves your machine without your knowledge          │
└─────────────────────────────────────────────────────────────────────┘

Data Protection Layers

1. Credential Storage

What's protected: API ID, API hash, session string, encryption key

How it's protected:

  • Stored in OS keyring (not plain text files)
  • macOS: Keychain Access (AES-256, Secure Enclave)
  • Windows: Credential Manager (DPAPI encryption)
  • Linux: GNOME Keyring / Secret Service (AES-128)

Code location: src/storage/credentials.py

# Credentials never touch the filesystem
creds = CredentialManager()
creds.store_api_hash(api_hash)  # Goes straight to keyring

2. Message Encryption

What's encrypted: Message text, reply drafts, style profiles

How it's encrypted:

  • Algorithm: AES-256 via Fernet
  • Key derivation: PBKDF2 with SHA256
  • Iterations: 480,000 (OWASP recommended)
  • Salt: Unique random salt per installation

Code location: src/storage/encryption.py

class EncryptionManager:
    def __init__(self, password: str, salt_path: Path):
        # Derive key from password + salt
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=32,
            salt=self._load_or_create_salt(salt_path),
            iterations=480_000,  # OWASP recommendation
        )
        key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
        self._fernet = Fernet(key)

    def encrypt(self, plaintext: str) -> str:
        return self._fernet.encrypt(plaintext.encode()).decode()

    def decrypt(self, ciphertext: str) -> str:
        return self._fernet.decrypt(ciphertext.encode()).decode()

3. Database Security

What's stored: Contacts, messages (encrypted), replies, style profiles

Security measures:

  • SQLite database stored locally
  • Message content encrypted before storage
  • Database file permissions: owner-only (0600)
  • No foreign connections possible (file-based)

Schema security:

-- Messages are stored encrypted
INSERT INTO messages (encrypted_text, ...)
VALUES ('gAAAAABk...encrypted_content...', ...);

-- Plain text never stored

4. Session Security

Telegram session:

  • Session string stored in keyring (not file)
  • Enables reconnection without re-auth
  • If compromised, can be revoked from Telegram settings

Revoking a session:

  1. Go to Telegram Settings > Devices
  2. Find "Unknown session" or suspicious entry
  3. Click "Terminate session"

5. Local AI Processing

No cloud API means:

  • Messages never sent to OpenAI, Anthropic, or Google
  • No API logs of your conversations
  • No third-party data retention
  • Complete control over your data

What Ollama sees:

  • Only what you explicitly send to it
  • Running on your machine
  • No telemetry or logging by default

Attack Surface Analysis

What an attacker would need:

Attack Vector Difficulty Mitigation
Physical access to machine High Full disk encryption
Stolen .env file Medium Don't commit to git, use keyring
Keyring access High Requires OS password
Database file theft Medium Messages are encrypted
Network interception Low MTProto is encrypted
Ollama API access Low Bind to localhost only

Recommended Defenses:

  1. Enable full disk encryption (FileVault, BitLocker, LUKS)
  2. Use a strong OS password
  3. Never commit .env to git
  4. Keep encryption key in keyring, not .env
  5. Regularly check Telegram active sessions

Sensitive Data Handling

What's considered sensitive:

Data Type Storage Encryption
API credentials Keyring OS-level
Session string Keyring OS-level
Message content Database AES-256
Contact names Database Optional
Style profiles Database AES-256
Phone number Not stored N/A
2FA password Not stored N/A

What's never stored:

  • Your Telegram password
  • 2FA passwords
  • Phone verification codes
  • Plain text message content (when encryption enabled)

Telegram API Security

MTProto Protocol:

The app uses Telegram's MTProto protocol which provides:

  • End-to-end encryption for secret chats
  • Transport layer encryption for all communications
  • Perfect forward secrecy
  • Server authentication

API Credential Security:

Your api_id and api_hash identify your application to Telegram:

  • api_id: Public identifier (like a username)
  • api_hash: Secret key (like a password)

Best practices:

  • Never share your api_hash
  • Don't commit credentials to public repos
  • Regenerate if compromised

Rate Limiting Protection:

Aggressive automation can get your account banned:

# Built-in protection
rate_limiter = RateLimiter(
    messages_per_minute=20,  # Conservative limit
    burst_limit=5,           # Prevent rapid fire
)

Security Configuration

Enable Encryption (Recommended)

# Set encryption key in keyring
python -c "
from src.storage.credentials import CredentialManager
import secrets

creds = CredentialManager()
creds.store_encryption_key(secrets.token_urlsafe(32))
print('Encryption key generated and stored')
"

Disable Encryption (Not Recommended)

If you need to disable encryption:

# In main.py, skip encryption initialization
db = Database(
    db_path=settings.database_path,
    encryption_manager=None,  # No encryption
)

Secure File Permissions

# Set secure permissions on data directory
chmod 700 data/
chmod 600 data/assistant.db
chmod 600 data/.salt
chmod 600 .env

Privacy Considerations

What the app knows about you:

  1. Your Telegram messages (to learn style)
  2. Your contacts (to track importance)
  3. Your writing patterns (style profile)

What never leaves your machine:

  1. Message content (local LLM)
  2. Style analysis (local processing)
  3. Contact information (local database)

What goes to Telegram:

  1. Authentication requests
  2. Message fetch requests
  3. Messages you send (through the app)

What goes nowhere else:

  1. No analytics
  2. No telemetry
  3. No crash reports
  4. No usage tracking

Incident Response

If your credentials are compromised:

  1. Revoke Telegram session:

    • Telegram Settings > Devices > Terminate all other sessions
  2. Regenerate API credentials:

  3. Clear local credentials:

    from src.storage.credentials import CredentialManager
    CredentialManager().clear_all()
  4. Change encryption key:

    rm data/.salt  # Remove old salt
    # Re-run setup to generate new key

If your database is compromised:

Without the encryption key, the attacker gets:

  • Encrypted blobs (useless without key)
  • Contact Telegram IDs (semi-public info)
  • Timestamps (metadata only)

With the encryption key, they get:

  • Message content
  • Your style profile
  • Reply history

Mitigation: Keep encryption key in keyring, not .env file.

Security Checklist

Before deploying:

  • Encryption enabled (key in keyring)
  • .env excluded from git
  • data/ directory excluded from git
  • File permissions set (700/600)
  • Ollama bound to localhost only
  • Full disk encryption enabled
  • Strong OS password set

Known Limitations

Not protected against:

  1. Physical access with OS password - If someone has your laptop password, they can access everything

  2. Memory forensics - Decrypted messages exist in RAM while processing

  3. Compromised Ollama - A malicious Ollama build could log prompts

  4. Telegram server-side - Telegram can read non-secret chats

Recommendations:

  1. Use Telegram secret chats for highly sensitive conversations
  2. Enable auto-lock on your computer
  3. Use official Ollama releases only
  4. Regularly review Telegram active sessions

Comparison with Cloud Alternatives

Aspect This App (Local) Cloud API
Message visibility Only you You + provider
Data retention Your control Provider policy
Encryption AES-256 + keyring Provider's choice
Audit trail Your logs only Provider logs
Jurisdiction Your location Provider's servers
Subpoena risk Your device only Provider + you

Reporting Security Issues

If you discover a security vulnerability:

  1. Do not open a public GitHub issue
  2. Email the maintainer directly
  3. Provide detailed reproduction steps
  4. Allow reasonable time for fix before disclosure

Further Reading

There aren’t any published security advisories