Security Posture
This document describes exactly what insightral reads, what leaves your infrastructure, and how to shut it off immediately. It is written for security and compliance review, not marketing.
Last reviewed: 2026-09-04 — Contact: [email protected]
What we read
The collector executes SELECT queries against the system statistics views listed below. No DML, no DDL, no superuser privileges. Your application tables are never queried. Equivalent read-only views exist for all supported engines: Oracle uses V$ dynamic performance views, MySQL uses performance_schema, and SQL Server uses DMVs (Dynamic Management Views) — the same read-only access model applies across all four engines.
pg_stat_activity
Active and idle sessions: state (active, idle, idle in transaction), wait event type, query start time, and elapsed duration. Used to detect long-running transactions, idle-in-transaction pressure, and connection saturation. Literal query text is never stored or forwarded — only aggregate counts and duration thresholds are evaluated.
pg_stat_bgwriter
Background writer and checkpoint counters (buffers_clean, buffers_checkpoint, maxwritten_clean). Used to detect checkpoint pressure and dirty-page write amplification.
pg_stat_replication
Replication slot lag and standby send/flush/replay byte positions. Used to detect replication lag exceeding configurable thresholds. No data payload is read — only byte offsets.
pg_stat_user_tables
Per-table statistics: seq_scan, n_dead_tup, last_autovacuum, last_analyze, n_mod_since_analyze. Used by autovacuum-lag, bloat estimation, and sequential-scan rules.
pg_stat_user_indexes
Per-index statistics: idx_scan, idx_tup_read, idx_tup_fetch. Used to find unused indexes (zero scans) and redundant index pairs.
pg_locks
Lock wait graph: granted, mode, relation OID, transactionid. Used to detect lock contention and deadlock risk. No row-level data values are read — only lock metadata.
pg_database
Per-database statistics: datname, pg_database_size(), transaction wraparound distance via age(datfrozenxid). Used to detect XID wraparound risk.
Required role and grant SQL
Run this block as a superuser on Postgres 15+. The pg_monitor built-in role grants read access to all pg_stat_* views without superuser. No write privileges are granted or required.
CREATE ROLE insightral_readonly WITH LOGIN PASSWORD 'change_me'; GRANT CONNECT ON DATABASE your_database TO insightral_readonly; GRANT USAGE ON SCHEMA public TO insightral_readonly; GRANT SELECT ON ALL TABLES IN SCHEMA public TO insightral_readonly; GRANT pg_monitor TO insightral_readonly;
Replace change_me with a strong password from your secrets manager. your_database is the name of the database insightral will monitor.
What leaves your infrastructure
The following fields are the complete set of data that may be transmitted from the collector to the insightral dashboard. Nothing else is sent.
target.fingerprint
SHA-256 hashDerived from DSN host + schema name + object identifier. The original values are not transmitted. The hash is one-way and cannot be reversed to recover a host, database, or table name.
rule_id
StringA stable rule code such as "PG-I01" or "PG-V03". No customer data is embedded.
severity
EnumOne of: critical, warning, info. Rule-defined. No customer data.
aggregate counts
IntegerStatistical values only — for example, the number of idle-in-transaction sessions, or dead-tuple count as a percentage of live tuples. Raw row data, query text, schema names, and table names are never included.
collector version
Semver stringUsed for rule-compatibility checks only.
Never transmitted
- Query text, SQL literals, or query plans
- Table names, column names, or schema identifiers
- Row data or column values of any kind
human_label— the plain-text alias you assign to a connection in the dashboard- DSN, host, port, or database name
- Credentials of any kind
Kill switch
Revoking the role or removing its access to pg_catalog stops all data emission immediately. The collector will receive an authentication error on its next polling cycle (default: 60 seconds) and stop emitting findings. No restart is required.
-- Option A: revoke catalog access — stops emission without dropping the role REVOKE ALL ON SCHEMA pg_catalog FROM insightral_readonly; -- Option B: drop the role entirely REASSIGN OWNED BY insightral_readonly TO postgres; DROP OWNED BY insightral_readonly; DROP ROLE insightral_readonly;
Option A is reversible: re-granting pg_monitor restores operation without restarting the collector. Option B (drop role) is permanent.
You can also stop emission by halting the Docker container or by revoking the collector ingest token in the insightral dashboard under Settings → Collector tokens.
Network shape
Direction
Outbound only
The collector initiates all connections. No inbound ports are opened on your network by insightral.
Protocol
WebSocket (wss://)
Findings are submitted over an outbound-only WebSocket connection (TLS 1.2+). Plaintext is rejected.
Destination
app.insightral.com (443)
Single destination hostname. You can allowlist this in your egress firewall to limit scope.
Inbound ports
None
No server process on your infrastructure. No webhook receiver. No reverse shell.
Agent process
Container only
insightral runs as a Docker container that you start and stop. Nothing is installed on the database host itself.
Container image
Distroless, non-root, cosign-signed
CGO_ENABLED=0 — statically linked binary. No shell, no package manager, no shared libraries inside the image.
Authentication & access controls
Password reset TTL
30-minute OTP
Password resets use Clerk's email OTP, which expires after 30 minutes. No hardware 2FA (TOTP/WebAuthn) is enforced today — that is on the roadmap for Enterprise tier.
CORS posture
Origin-restricted
API routes under /api/* accept requests only from the dashboard origin. No wildcard CORS. The collector ingest endpoint is server-to-server only and does not set CORS headers.
Row-level security
All tenant tables
Every table that stores tenant data is protected by Postgres RLS. Queries run as insightral_app and must set app.tenant_id for the session; cross-tenant reads return zero rows by policy, not application logic.
Connection DSN encryption
App-layer AES-256-GCM
DSNs are encrypted with AES-256-GCM before persistence (INSIGHTRAL_ENCRYPTION_KEY). This is application-layer encryption, not envelope encryption with a KMS. Enterprise BYOK lets you supply your own 256-bit key; insightral never stores the plaintext key.
Sub-processors
insightral uses the following sub-processors to deliver the service. Each processes data only as described.
| Processor | Purpose | Data |
|---|---|---|
| AWS (RDS, S3, Bedrock) | Hosted database, object storage, AI inference | Finding records, connection metadata (encrypted DSNs), AI prompt context |
| Clerk | Authentication & user management | Email, name, session tokens |
| Stripe | Billing & subscription management | Payment card data (Stripe-held), subscription status |
| Sentry | Error monitoring & performance tracing | Stack traces, request metadata — no finding payloads |
| Postmark | Transactional email | Email address, notification content |
A DPA with the full sub-processor schedule and EU SCCs Module 2 reference is available on request — email [email protected].
SOC 2 status
Type I
Target: 2026-07-25 (Day 90)
Type II
Target: Day 180
Penetration test
Target: Day 60
To request the current trust report, a DPA, or ask about audit scope, email [email protected]. Vulnerability reports receive a response within 2 business days.