Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Arvo-AI/aurora/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Aurora implements defense-in-depth security with multiple layers of protection:
- Authentication & Authorization: User identity verification and access control
- Secrets Management: HashiCorp Vault for sensitive credentials
- Network Security: TLS encryption and CORS protection
- Data Protection: Row-Level Security and encryption
- Input Validation: Protection against injection attacks
- Rate Limiting: DDoS and abuse prevention
Authentication
Password-Based Authentication
Aurora uses bcrypt for secure password hashing:
import bcrypt
# Registration
password_hash = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
# Login
password_valid = bcrypt.checkpw(
password.encode('utf-8'),
password_hash.encode('utf-8')
)
Security Features:
- Minimum 8 characters password requirement
- bcrypt hashing with automatic salt generation
- Work factor: Default bcrypt cost parameter (10-12 rounds)
- Constant-time comparison to prevent timing attacks
- No password storage: Only hashed values stored in database
Best Practices:
# SECURE: Timing-attack resistant
if bcrypt.checkpw(user_password, stored_hash):
return True
# INSECURE: Vulnerable to timing attacks
if user_password == stored_password: # DON'T DO THIS
return True
Session Management
Flask session cookies with secure configuration:
app.config.update(
SECRET_KEY=os.getenv("FLASK_SECRET_KEY") or secrets.token_hex(24),
SESSION_TYPE="filesystem",
SESSION_PERMANENT=False,
SESSION_FILE_DIR="/tmp/flask_session",
SESSION_COOKIE_SECURE=True, # HTTPS only in production
SESSION_COOKIE_HTTPONLY=True, # No JavaScript access
SESSION_COOKIE_SAMESITE="Lax" # CSRF protection
)
Session Security:
- Secure cookies in production (HTTPS)
- HttpOnly flag prevents XSS cookie theft
- SameSite=Lax prevents CSRF attacks
- File-based storage (not memory-based)
- Automatic session cleanup
OAuth 2.0 Integration
Cloud provider authentication via OAuth:
GCP OAuth Flow:
# 1. Generate authorization URL
auth_url = get_auth_url(state=user_id)
# 2. User authorizes in browser
# 3. Handle callback with authorization code
token_data = exchange_code_for_token(code)
# 4. Store tokens securely in Vault
store_tokens_in_db(user_id, token_data, "gcp")
OAuth Security:
- State parameter prevents CSRF attacks
- PKCE (optional) for public clients
- Token encryption before storage
- Automatic token refresh
- Scope limitation (principle of least privilege)
Authorization
Row-Level Security (RLS)
PostgreSQL RLS enforces data isolation:
-- Enable RLS on table
ALTER TABLE chat_sessions ENABLE ROW LEVEL SECURITY;
-- Create user isolation policy
CREATE POLICY user_isolation_policy ON chat_sessions
USING (user_id = current_setting('myapp.current_user_id', TRUE)::TEXT);
Protected Tables:
chat_sessions: Users can only access their own chats
incidents: Users can only see their incidents
user_tokens: Users can only access their credentials
llm_usage_tracking: Users can only see their usage
- All Kubernetes and monitoring tables
Setting User Context:
with db_pool.get_admin_connection() as conn:
cursor = conn.cursor()
cursor.execute("SET myapp.current_user_id = %s", (user_id,))
conn.commit()
# Now queries respect RLS policies
cursor.execute("SELECT * FROM chat_sessions")
API Authorization
Header-based authentication for API requests:
from utils.auth.stateless_auth import get_user_id_from_request
@app.route('/api/resource')
def get_resource():
user_id = get_user_id_from_request()
if not user_id:
return jsonify({'error': 'Unauthorized'}), 401
# User authenticated, proceed with request
return jsonify({'data': ...})
Authentication Headers:
X-User-ID: user_abc123
Authorization: Bearer <token> # For kubectl agent
Secrets Management
HashiCorp Vault
Aurora uses Vault for sensitive credential storage:
Architecture:
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Aurora │────▶│ PostgreSQL │────▶│ Vault │
│ Server │ │ (secret_ref)│ │ (secrets) │
└─────────────┘ └──────────────┘ └─────────────┘
Configuration:
VAULT_ADDR=http://vault:8200
VAULT_TOKEN=hvs.xxxxxxxxxxxxx
VAULT_KV_MOUNT=aurora
VAULT_KV_BASE_PATH=
Storing Secrets:
from utils.secrets.vault_utils import store_secret_in_vault
# Store OAuth tokens in Vault
secret_ref = store_secret_in_vault(
user_id=user_id,
provider="gcp",
data={
"access_token": token_data["access_token"],
"refresh_token": token_data["refresh_token"]
}
)
# Store reference in database
cursor.execute(
"UPDATE user_tokens SET secret_ref = %s WHERE user_id = %s AND provider = %s",
(secret_ref, user_id, "gcp")
)
Retrieving Secrets:
from utils.secrets.vault_utils import get_secret_from_vault
# Get reference from database
cursor.execute(
"SELECT secret_ref FROM user_tokens WHERE user_id = %s AND provider = %s",
(user_id, "gcp")
)
secret_ref = cursor.fetchone()[0]
# Retrieve secret from Vault
token_data = get_secret_from_vault(secret_ref)
Secret References:
vault:kv/data/aurora/users/user_abc123/gcp
Redis Caching
Secrets cached in Redis with TTL:
from utils.secrets.secret_cache import get_cached_secret, cache_secret
# Check cache first
secret = get_cached_secret(secret_ref)
if not secret:
# Cache miss, fetch from Vault
secret = get_secret_from_vault(secret_ref)
cache_secret(secret_ref, secret, ttl=3600) # 1 hour TTL
Cache Invalidation:
from utils.secrets.secret_cache import clear_secret_cache
# Clear cache after credential update
clear_secret_cache(secret_ref)
Network Security
TLS/HTTPS
Production Configuration:
# nginx.conf
server {
listen 443 ssl http2;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://aurora-server:5080;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
CORS Configuration
Cross-Origin Resource Sharing protection:
from flask_cors import CORS
CORS(app,
origins=FRONTEND_URL,
supports_credentials=True,
methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
allow_headers=[
"Content-Type",
"X-Provider",
"X-User-ID",
"Authorization"
]
)
Security Headers:
@app.after_request
def add_security_headers(response):
response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['X-Frame-Options'] = 'DENY'
response.headers['X-XSS-Protection'] = '1; mode=block'
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
return response
SQL Injection Prevention
Always use parameterized queries:
# SECURE: Parameterized query
cursor.execute(
"SELECT * FROM users WHERE email = %s",
(user_email,)
)
# INSECURE: String concatenation (NEVER DO THIS)
cursor.execute(
f"SELECT * FROM users WHERE email = '{user_email}'" # SQL INJECTION!
)
XSS Prevention
Frontend sanitization:
import DOMPurify from 'dompurify';
// Sanitize user input before rendering
const cleanHTML = DOMPurify.sanitize(userInput);
Backend validation:
import bleach
# Strip HTML tags from user input
clean_text = bleach.clean(user_input, tags=[], strip=True)
Command Injection Prevention
Never use shell=True with user input:
import subprocess
# SECURE: List arguments (no shell)
result = subprocess.run(
["kubectl", "get", "pods", "-n", namespace],
capture_output=True,
check=True
)
# INSECURE: shell=True with user input (COMMAND INJECTION!)
result = subprocess.run(
f"kubectl get pods -n {namespace}", # DANGEROUS!
shell=True,
capture_output=True
)
Path Traversal Prevention
Validate file paths:
import os
def safe_read_file(base_dir, filename):
# Resolve absolute path
filepath = os.path.abspath(os.path.join(base_dir, filename))
# Ensure path is within base directory
if not filepath.startswith(os.path.abspath(base_dir)):
raise ValueError("Path traversal detected")
with open(filepath, 'r') as f:
return f.read()
Rate Limiting
API Rate Limiting
Protect against abuse and DDoS:
from utils.web.limiter_ext import limiter
# Global rate limit
limiter.init_app(app)
# Per-endpoint limits
@app.route('/api/resource')
@limiter.limit("100/minute")
def get_resource():
return jsonify({'data': ...})
# Stricter limit for expensive operations
@app.route('/api/deploy')
@limiter.limit("10/minute")
def deploy():
return jsonify({'status': 'deploying'})
Configuration:
app.config.update(
RATELIMIT_STORAGE_URL="redis://redis:6379",
RATELIMIT_STRATEGY="fixed-window",
RATELIMIT_DEFAULT="100/minute"
)
WebSocket Rate Limiting
Custom rate limiter for WebSocket connections:
class RateLimiter:
def __init__(self, rate, per):
self.tokens = defaultdict(lambda: rate)
self.rate = rate
self.per = per
self.last_checked = defaultdict(time.time)
def is_allowed(self, client_id):
now = time.time()
elapsed = now - self.last_checked[client_id]
self.last_checked[client_id] = now
self.tokens[client_id] += elapsed * (self.rate / self.per)
if self.tokens[client_id] > self.rate:
self.tokens[client_id] = self.rate
if self.tokens[client_id] >= 1:
self.tokens[client_id] -= 1
return True
return False
# 5 messages per 60 seconds
rate_limiter = RateLimiter(rate=5, per=60)
Data Protection
Encryption at Rest
Database encryption:
# PostgreSQL with encryption
postgres:
image: postgres:15
command: postgres -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt
volumes:
- ./certs:/var/lib/postgresql
Object storage encryption:
from utils.storage.storage import get_storage_manager
storage = get_storage_manager(
user_id=user_id,
encryption=True # Server-side encryption
)
storage.upload_file("sensitive-data.txt", data)
Encryption in Transit
All network traffic encrypted:
- HTTPS for REST API (TLS 1.2+)
- WSS for WebSocket (TLS 1.2+)
- SSL for PostgreSQL connections
- TLS for Redis connections
Data Retention
Soft deletes for user data:
-- Soft delete chat session
UPDATE chat_sessions
SET is_active = false, updated_at = NOW()
WHERE id = %s AND user_id = %s;
-- Hard delete after retention period (30 days)
DELETE FROM chat_sessions
WHERE is_active = false
AND updated_at < NOW() - INTERVAL '30 days';
Vulnerability Management
Dependency Scanning
Python dependencies:
# Scan for known vulnerabilities
pip-audit
# Update vulnerable packages
pip install --upgrade package-name
npm dependencies:
# Scan for vulnerabilities
npm audit
# Automatically fix
npm audit fix
Container Security
Dockerfile best practices:
# Use specific versions (not :latest)
FROM python:3.11-slim
# Run as non-root user
RUN useradd -m -u 1000 aurora
USER aurora
# Minimal base image
FROM python:3.11-slim AS base
# Multi-stage build
FROM base AS builder
# ... build steps ...
FROM base AS final
COPY --from=builder /app /app
Image scanning:
# Scan Docker images for vulnerabilities
trivy image aurora-server:latest
Incident Response
Logging
Security event logging:
import logging
logger = logging.getLogger(__name__)
# Log authentication events
logger.info(f"User logged in: {user_email}")
logger.warning(f"Failed login attempt: {user_email}")
# Log authorization failures
logger.error(f"Unauthorized access attempt: {user_id} -> {resource}")
# Log security-critical operations
logger.info(f"User {user_id} deleted incident {incident_id}")
Monitoring
Security metrics:
- Failed authentication attempts
- Rate limit violations
- Unauthorized access attempts
- Abnormal API usage patterns
- Database connection failures
Reporting Security Issues
DO NOT report security vulnerabilities through public GitHub issues.
Instead, email: info@arvoai.ca
Include:
- Type of vulnerability
- Affected source files
- Steps to reproduce
- Proof-of-concept (if possible)
- Impact assessment
Security Checklist
Development
Deployment
Operations
Additional Resources