Visibility is the foundation of Zero-Trust. ThornGuard writes an asynchronous audit log for every significant action processed through the proxy.
These logs are stored in a highly durable, globally distributed Cloudflare D1 (SQLite) database.
Database Schema
Every event is recorded in the audit_logs table with the following schema:
| Column | Type | Description |
|---|
id | INTEGER | Internal primary key (auto-incrementing). |
log_id | TEXT | Public-facing UUID identifier (crypto.randomUUID()). Used by the dashboard. |
trace_id | TEXT | Correlation ID shared with client-visible x-thornguard-trace-id headers. |
timestamp | DATETIME | UTC timestamp (defaults to CURRENT_TIMESTAMP). |
license_hash | TEXT | A SHA-256 hash of the x-thornguard-license used to authenticate the request. |
target_url | TEXT | The upstream server requested (e.g., api.githubcopilot.com). |
rpc_method | TEXT | The specific MCP tool being called (e.g., get_issue). |
action | TEXT | The categorization of the event (see Action Types below). |
details | TEXT | Extended context, errors, or reasons for blocking. |
details_json | TEXT | Structured JSON metadata for richer event context. |
policy_rule_id | TEXT | The matched policy rule identifier when a policy event is involved. |
response_time_ms | INTEGER | Time in milliseconds from request receipt to response completion. |
client_ip | TEXT | Client IP address (captured from CF-Connecting-IP header). |
The id field is the internal auto-incrementing primary key. The log_id UUID is the public-facing identifier used by the dashboard and API. Older rows may not have a log_id — the dashboard falls back to id in those cases.
Action Types
Every audit log entry is classified with one of the following action values:
| Action | Description |
|---|
PROXY_SUCCESS | Request was successfully scrubbed and proxied to upstream. |
SSE_STREAM_ESTABLISHED | An SSE stream was successfully opened to the client. |
BLOCKED_MALICIOUS | Destructive command intercepted (e.g., rm -rf, sudo). |
BLOCKED_AUTH | Authentication failure — license invalid, missing, or expired. |
BLOCKED_INSECURE_TARGET | Target URL was rejected because it was not HTTPS. |
BLOCKED_ORIGIN | Request origin was rejected by the configured allowlist. |
BLOCKED_SSRF | SSRF attempt blocked — target URL or resolved DNS address was restricted. |
BLOCKED_RATE_LIMIT | Request dropped because the per-license rate limit was exceeded. |
BLOCKED_IP_WHITELIST | Client IP was not in the enterprise IP whitelist. |
BLOCKED_CUSTOM_DOMAIN | Target domain matched a per-license custom blocklist entry. |
BLOCKED_CUSTOM_COMMAND | Command pattern matched a per-license custom command blocklist. |
BLOCKED_POLICY | A structured tenant policy rule blocked the request. |
POLICY_AUDIT | A structured tenant policy rule matched in audit mode. |
BLOCKED_APPROVAL | A tool call was halted pending explicit approval. |
PII_REDACTED | PII or secrets were detected and scrubbed from request or response. Details include the types found (e.g., EMAIL, AWS_KEY). |
CUSTOM_REDACTION_AUDIT | A custom enterprise redaction rule matched in audit mode. |
UPSTREAM_ERROR | The upstream MCP server returned an error (timeout, non-JSON response, etc.). |
AUDIT_PURGE | Logs were purged via a GDPR deletion request. |
PII_REDACTED counts as a threat in the dashboard metrics — it increments the Threats Blocked counter and can appear in the Recent Blocked Threat card.
Querying Logs
Successful proxied responses and ThornGuard-generated error responses include:
x-thornguard-log-id
x-thornguard-trace-id
These values map directly to audit_logs.log_id and audit_logs.trace_id, making it easy to correlate user-visible failures with backend logs and webhook deliveries.
Via the Dashboard
The ThornGuard Dashboard provides a graphical interface for browsing audit logs with filtering by action type, date range, and search — plus 10-second auto-polling for real-time updates. See Dashboard for details.
Via the Wrangler CLI
You can also query logs directly using the Wrangler CLI.
View the 10 most recent events:
npx wrangler d1 execute thornguard-audit --remote \
--command="SELECT log_id, timestamp, action, rpc_method, client_ip, details FROM audit_logs ORDER BY id DESC LIMIT 10;"
View all blocked malicious attempts:
npx wrangler d1 execute thornguard-audit --remote \
--command="SELECT log_id, timestamp, target_url, details FROM audit_logs WHERE action = 'BLOCKED_MALICIOUS' ORDER BY id DESC;"
View PII redaction events:
npx wrangler d1 execute thornguard-audit --remote \
--command="SELECT log_id, timestamp, rpc_method, details FROM audit_logs WHERE action = 'PII_REDACTED' ORDER BY id DESC LIMIT 20;"
Log Retention
ThornGuard supports configurable log retention periods per license tier.
- Default retention: 90 days (Individual), 365 days (Enterprise).
- Cleanup schedule: A daily cron job runs at 3:00 AM UTC to delete expired logs.
- Custom retention: Current dashboard controls allow retention changes within your allowed tier limits.
Data Export
Audit logs can be exported for compliance, reporting, or analysis:
- CSV Export: Download your audit logs as a CSV file from the dashboard Settings page.
- JSON Export: Available via the ThornGuard API for programmatic access.
GDPR Compliance
ThornGuard supports right-to-deletion requests through a one-click audit log purge:
- Accessible from the dashboard Settings page under Danger Zone.
- Purging deletes all audit logs associated with your license.
- A final
AUDIT_PURGE action is logged to maintain a record of the deletion event itself.
Purging audit logs is irreversible. All historical data for your license will be permanently deleted.