# AgentPaaS Security Specification

## Overview

AgentPaaS is a multi-tenant Agent Platform as a Service. Security is critical because:
- Multiple tenants share the same infrastructure
- Agents execute arbitrary LLM-generated code via tools
- API keys and secrets must be protected at rest and in transit
- WeChat/external channel integrations handle user credentials

## Threat Model

```
External Attacker         Malicious Tenant         Compromised Agent
      |                        |                        |
      v                        v                        v
  [API Gateway]           [Tenant Boundary]        [Sandbox]
  - Auth bypass            - Data leakage           - Code injection
  - CORS abuse             - Quota bypass           - Resource exhaustion
  - Rate limit bypass      - Privilege escalation   - Secret exfiltration
  - Input injection        - SQL injection          - Subprocess escape
```

## Security Architecture

### 1. Authentication & Authorization

**API Key Authentication:**
- Keys generated with `secrets.token_hex(16)` (128-bit entropy)
- Keys hashed before storage (MUST use salted PBKDF2, not bare SHA-256)
- Bearer token in `Authorization` header
- Key prefix stored for identification without exposing full key

**RBAC (Role-Based Access Control):**

| Role | Permissions |
|------|-------------|
| Admin | tenants:\*, agents:\*, keys:\*, billing:read, secrets:\*, admin:\* |
| Developer | agents:read/write/execute, keys:read/write, runs:read, secrets:read |
| Viewer | agents:read, runs:read, billing:read |

**Requirements:**
- All endpoints MUST require authentication (including admin endpoints)
- Scope checks MUST be enforced at handler level
- Failed auth attempts MUST be logged with source IP

### 2. Tenant Isolation

- All database queries MUST include `tenant_id` filter via parameterized queries
- NEVER use string interpolation for SQL (no f-strings, no `.format()`)
- Agent execution contexts MUST be isolated per tenant
- Secrets MUST NOT leak across tenant boundaries

### 3. Secrets Management

**Encryption:**
- AES-256-GCM via `cryptography` library (MUST NOT fall back to base64)
- Master key MUST be provided via `AGENTPAAS_MASTER_KEY` environment variable
- Master key MUST NOT be auto-generated at runtime in production

**Injection:**
- Secrets SHOULD be injected via execution Context, NOT environment variables
- Secrets MUST NOT appear in logs, error messages, or API responses

### 4. Input Validation

- All API inputs MUST have size limits (max_length on string fields)
- Agent configs MUST be validated against schema before compilation
- SQL LIKE queries MUST escape wildcards (`%`, `_`)
- User input to agents MUST be size-limited (default: 100KB)

### 5. Sandbox & Execution

- Agent execution MUST run in isolated sandbox (L0/L1/L2)
- Input data MUST be passed via JSON file, NOT string interpolation in code
- Resource limits (CPU, memory, time) MUST be enforced
- Subprocess creation MUST be explicitly allowed per policy

### 5b. ToolGateway — Runtime Tool Permission Enforcement

> **Implementation**: `lambdagent/tool_gateway.py` (2026-03-28)
>
> All tool calls pass through `GatedTool` before execution. This closes the gap
> where `guard.dangerousCommandBlock` and `guard.highRiskConfirmation` were declared
> in YAML configs but had zero runtime effect.

**How it works in the PaaS context:**

1. Tenant deploys agent with `guard` config via `POST /api/v1/agents`
2. On `POST /api/v1/agents/{id}/run`, compiler calls `build_agent(config)`
3. `build_agent()` reads `guard` → creates `ToolGateway(GatewayPolicy.from_guard_config(...))`
4. Every `Tool` in the agent is wrapped as `GatedTool`
5. Each tool call is classified (SAFE → CRITICAL), checked against policy, and audited

**Risk classification (5 levels, 50+ regex patterns):**

| Level | Action when `dangerousCommandBlock: true` |
|-------|------------------------------------------|
| CRITICAL | Always BLOCK (e.g., `rm -rf /`, `curl\|sh`, credential access) |
| HIGH | BLOCK, or CONFIRM if `highRiskConfirmation: true` (e.g., `sudo`, `rm -r`, `pip install`) |
| MEDIUM | LOG_ONLY (e.g., `mv`, `sed -i`, `git rebase`) |
| LOW / SAFE | ALLOW (e.g., `ls`, `cat`, `git status`, `terminate`) |

**Output control:**
- `guard.maxOutputLength` now enforced: `GatedTool` truncates output, `Guard` triggers retry/fallback

**Audit trail:**
- Every tool call logged with: timestamp, tool name, input, risk level, action, result preview, duration
- Available via `gateway.audit.entries` / `gateway.audit.stats`
- Can be persisted to file via `GatewayPolicy.audit_file`

**Confirmation flow for multi-tenant:**
- `highRiskConfirmation: true` triggers `policy.confirm_callback(tool, input, reason)`
- PaaS can inject a callback that pauses execution and notifies the tenant via API/webhook
- If no callback configured, HIGH-risk calls are blocked by default (safe default)

**Per-tenant policy:**
- Each agent's `guard` config creates its own `GatewayPolicy`
- Tenant A's agent can have `dangerousCommandBlock: false` (dev mode)
- Tenant B's agent can have `dangerousCommandBlock: true` + `highRiskConfirmation: true`
- Policies are compiled at agent creation time, not shared across tenants

**macOS sandbox fix:**
- `RLIMIT_NPROC` (block subprocess creation) previously failed silently on macOS
- Now falls back to Python-level monkey-patching of `subprocess`/`os.system`/`os.exec*`
- Not a kernel boundary — for production multi-tenant, use L2 container sandbox

### 6. Network Security

- Production deployments MUST enforce HTTPS
- CORS MUST use explicit origin whitelist (NOT `*`)
- Rate limiting MUST be enforced per API key
- Security headers MUST be present on all responses

### 7. Error Handling

- Error responses MUST NOT include stack traces or file paths
- Internal errors MUST be logged server-side with full detail
- Client-facing errors MUST use generic error codes

### 8. Credential Storage

- API keys in CLI config (`~/.agentpaas/config.json`): plaintext (acceptable for dev)
- WeChat credentials (`~/.agentpaas/wechat/credentials.json`): SHOULD be encrypted
- Database file: SHOULD use encryption at rest in production (PostgreSQL + TDE)

### 9. Audit Logging

All security-relevant operations MUST be logged:
- API key creation/revocation
- Tenant creation/modification
- Agent deployment/rollback
- Secret access
- Authentication failures
- Admin operations

---

## Implementation Status (2026-03-28)

| ID | Item | Status |
|----|------|--------|
| SEC-09 | Fix sandbox code injection | ✅ Input via JSON in `sandbox.py` |
| SEC-22 | macOS `RLIMIT_NPROC` fallback | ✅ Python-level monkey-patch in `sandbox.py` |
| **SEC-24** | **ToolGateway — runtime tool permission enforcement** | ✅ `lambdagent/tool_gateway.py` |
| **SEC-25** | **guard.dangerousCommandBlock enforcement** | ✅ `compiler.py` → `GatedTool` wraps all tools |
| **SEC-26** | **guard.highRiskConfirmation enforcement** | ✅ confirm_callback flow in `GatedTool` |
| **SEC-27** | **guard.maxOutputLength enforcement** | ✅ truncation in `GatedTool` + retry in `Guard` |
| **SEC-28** | **Tool call audit logging** | ✅ `AuditLog` in `tool_gateway.py` |

---

## TODO List

### P0 - Immediate (Critical/High, blocks production)

- [x] **SEC-01**: Fix admin endpoints — add authentication to all `/api/v1/admin/*` routes (2026-04-01)
- [x] **SEC-02**: Fix CORS — replace `allow_origins=["*"]` with configurable whitelist (2026-04-01)
- [x] **SEC-03**: Remove `scoped_query()` from `tenant/isolation.py` (SQL injection risk) (2026-04-01)
- [x] **SEC-04**: Sanitize error responses — hide traceback from clients in `api/v1/agents.py` (2026-04-01)
- [x] **SEC-05**: Require `AGENTPAAS_MASTER_KEY` — error on startup if not set (non-dev mode) (2026-04-01)

### P1 - Week 1 (High, security hardening)

- [x] **SEC-06**: Implement rate limiting middleware using `TenantContext.rate_limit`
- [x] **SEC-07**: Fix secrets injection — use Context dict instead of `os.environ`
- [x] **SEC-08**: Add input size validation — `max_length` on `RunRequest.input`, config fields
- [x] **SEC-09**: Fix sandbox code injection — use JSON file for input, not string interpolation
- [x] **SEC-10**: Remove crypto fallback — require `cryptography` library, no base64 fallback
- [x] **SEC-11**: Add HTTPS enforcement middleware for production mode
- [x] **SEC-12**: Escape SQL LIKE wildcards in tag search
- [x] **SEC-24**: ToolGateway runtime tool permission enforcement (2026-03-28)
- [x] **SEC-25**: guard.dangerousCommandBlock enforcement (2026-03-28)
- [x] **SEC-26**: guard.highRiskConfirmation enforcement (2026-03-28)
- [x] **SEC-27**: guard.maxOutputLength enforcement (2026-03-28)
- [x] **SEC-28**: Tool call audit logging (2026-03-28)
- [x] **SEC-29**: Wire ToolGateway audit log to PaaS `/api/v1/traces` endpoint
- [x] **SEC-30**: Add confirm_callback webhook — notify tenant on HIGH-risk tool calls via API

### P2 - Month 1 (Medium, defense in depth)

- [x] **SEC-13**: Upgrade API key hashing to PBKDF2 with salt
- [ ] **SEC-14**: Add audit logging for security operations
- [ ] **SEC-15**: Encrypt WeChat credentials file with master key
- [x] **SEC-16**: Add security response headers (HSTS, X-Frame-Options, CSP)
- [x] **SEC-17**: Add request ID tracking middleware
- [ ] **SEC-18**: Add LLM call timeout wrapper
- [ ] **SEC-19**: Migrate to PostgreSQL for production
- [ ] **SEC-31**: Expose ToolGateway stats in `/api/v1/status/agents/{id}/health`
- [ ] **SEC-32**: Per-tenant GatewayPolicy overrides (admin can force `strict()` for all agents)

### P3 - Ongoing (Low, best practices)

- [ ] **SEC-20**: Implement token rotation policy for WeChat bot tokens
- [ ] **SEC-21**: Add dependency vulnerability scanning (safety, pip-audit)
- [x] **SEC-22**: Platform-specific sandbox fallback when RLIMIT_NPROC unavailable (2026-03-28)
- [ ] **SEC-23**: API key format upgrade to `secrets.token_urlsafe(32)`
- [ ] **SEC-33**: ToolGateway per-agent rate limiting (cap tool calls/min)
- [ ] **SEC-34**: Integrate ToolGateway audit with OpenTelemetry distributed tracing
