docs: add security audit doc
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
# Security
|
||||
|
||||
## Audit Result
|
||||
|
||||
**Grade: A+ — 30/30 checks passed** (last run: 2026-05-31)
|
||||
|
||||
Zero findings. All checks pass.
|
||||
|
||||
---
|
||||
|
||||
## Security Checklist
|
||||
|
||||
### Authentication
|
||||
| Check | Status |
|
||||
|---|---|
|
||||
| Server.php calls Auth::validate() on every request | ✅ |
|
||||
| Bearer token extraction in Auth::extractToken() | ✅ |
|
||||
| HTTPS enforcement code path in Auth::validate() | ✅ |
|
||||
| HTTPS enforcement ENABLED in settings | ✅ |
|
||||
| Rate limiting via transients (60 req/min) | ✅ |
|
||||
| Scope enforcement per tool | ✅ |
|
||||
|
||||
### Cryptography
|
||||
| Check | Status |
|
||||
|---|---|
|
||||
| hash_equals() for timing-safe HMAC comparison | ✅ |
|
||||
| HMAC-SHA256 used for JWT signing | ✅ |
|
||||
| JWT expiry (exp) checked on every verify | ✅ |
|
||||
| JWT issuer (iss) validated against site URL | ✅ |
|
||||
| JTI revocation list implemented | ✅ |
|
||||
| JWT secret rotation supported | ✅ |
|
||||
| JWT secret is 64 hex chars (256-bit) | ✅ |
|
||||
|
||||
### Admin Forms
|
||||
| Check | Status |
|
||||
|---|---|
|
||||
| wp_verify_nonce on 3+ admin actions | ✅ |
|
||||
| 47+ esc_*() calls in AdminMenu | ✅ |
|
||||
|
||||
### SQL Injection
|
||||
| Check | Status |
|
||||
|---|---|
|
||||
| wpdb->prepare() used in TokenManager key lookups | ✅ |
|
||||
| (int) casts on post_id in PostTools | ✅ |
|
||||
| SELECT-only enforcement in RawSqlTools | ✅ |
|
||||
| Raw SQL disabled by default in settings | ✅ |
|
||||
|
||||
### File / CLI Safety
|
||||
| Check | Status |
|
||||
|---|---|
|
||||
| FileManager sandboxed to wp_upload_dir() | ✅ |
|
||||
| CLI command allowlist + injection block | ✅ |
|
||||
| escapeshellarg() on all CLI args | ✅ |
|
||||
| --allow-root flag set (container runs as root) | ✅ |
|
||||
|
||||
### Logging & Privacy
|
||||
| Check | Status |
|
||||
|---|---|
|
||||
| Rate limit configured (60 req/min) | ✅ |
|
||||
| Request logging ENABLED | ✅ |
|
||||
| Audit log table exists | ✅ |
|
||||
| Log table stores key_id only (not raw token) | ✅ |
|
||||
| Active API keys present | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
Enforced via WP transients, keyed per API key:
|
||||
|
||||
```
|
||||
transient key: asktam_mcp_rate_{key_id}
|
||||
value: request count in current window
|
||||
expiry: 60 seconds (configurable)
|
||||
default limit: 60 requests/minute
|
||||
```
|
||||
|
||||
Configure in WP Admin → AskTam MCP → Settings.
|
||||
|
||||
---
|
||||
|
||||
## HTTPS Enforcement
|
||||
|
||||
When enabled (default), requests over plain HTTP are rejected with:
|
||||
```json
|
||||
{"error": "https_required", "message": "HTTPS required"}
|
||||
```
|
||||
|
||||
Configured in WP Admin → AskTam MCP → Settings → Require HTTPS.
|
||||
|
||||
---
|
||||
|
||||
## Raw SQL
|
||||
|
||||
Disabled by default. When enabled (Settings tab), only `SELECT` statements are accepted. The following patterns are blocked regardless:
|
||||
|
||||
- `INSERT`, `UPDATE`, `DELETE`, `DROP`, `TRUNCATE`, `ALTER`, `CREATE`, `GRANT`, `REVOKE`
|
||||
- Multiple statements (`;` separator)
|
||||
- Stored procedure calls
|
||||
|
||||
Enable only temporarily when needed. Disable immediately after.
|
||||
|
||||
---
|
||||
|
||||
## CLI Sandboxing
|
||||
|
||||
`CliTools.php` enforces two layers:
|
||||
|
||||
**1. Command allowlist** — only specific WP-CLI commands permitted (defined in `ALLOWED_COMMANDS` constant).
|
||||
|
||||
**2. Injection block** — `BLOCKED_PATTERNS` array prevents shell injection characters.
|
||||
|
||||
**3. Arg escaping** — all arguments passed through `escapeshellarg()`.
|
||||
|
||||
**4. Root flag** — `--allow-root` appended automatically (container runs as root).
|
||||
|
||||
---
|
||||
|
||||
## Audit Log
|
||||
|
||||
Every tool call is logged to `mwp_asktam_mcp_log`:
|
||||
|
||||
```
|
||||
key_id, tool_name, ip_address, status, duration_ms, created_at
|
||||
```
|
||||
|
||||
Raw API keys and JWT tokens are never stored. Only `key_id` is logged.
|
||||
|
||||
View last 1000 entries in WP Admin → AskTam MCP → Audit Log.
|
||||
|
||||
---
|
||||
|
||||
## Running the Security Audit
|
||||
|
||||
Test script at `/tmp/security_audit_v2.php` on the VPS. Run via:
|
||||
|
||||
```bash
|
||||
docker cp /tmp/security_audit_v2.php mainwp:/tmp/security_audit_v2.php
|
||||
docker exec mainwp php /tmp/security_audit_v2.php
|
||||
```
|
||||
|
||||
Expected output: `SCORE: 30/30 — Grade: A+`
|
||||
Reference in New Issue
Block a user