24observe
checking… Sign in Start free
Security posture

Your monitor shouldn't be the thing that attacks your VPC.

Monitoring tools are unique: you give them URLs and they make requests. That's an attacker's dream — make the monitor fetch http://169.254.169.254/latest/meta-data/iam/... and it's your infra's problem. We closed that door before we opened the front door.

SSRF defense · packages/security/src/ssrf.ts

Every check resolves DNS first, validates every returned address, then connects by IP.

Zero TOCTOU window. Zero DNS rebinding window. Zero "we only check the hostname."

RFC1918 private
10.0.0.0/8 · 172.16.0.0/12 · 192.168.0.0/16
Loopback
127.0.0.0/8 · ::1
Link-local
169.254.0.0/16 · fe80::/10
Cloud metadata
169.254.169.254 (AWS/GCP/Azure/DO)
CGNAT
100.64.0.0/10
Multicast
224.0.0.0/4
Reserved
240.0.0.0/4
Zero-net / anycast-leak
0.0.0.0/8 · ::
IPv6 ULA
fc00::/7 · fd00::/7
IPv4-mapped IPv6
::ffff:a.b.c.d unwrapped → IPv4 blocklist

For HTTP/HTTPS/keyword checks the validation runs pre-request. For TCP/port/SSL/ping, the resolved IP is used directly as the connect target — the hostname is only supplied as SNI on the SSL check. The ICMP ping uses execFile('ping', [args]) — no shell interpolation, ever.

Everything else

Defensible defaults, verifiable in the source.

argon2id password hashing

Industry-standard memory-hard hashing with per-password salts. No MD5, no SHA1, no "we rolled our own."

HS256 JWT with Redis-backed revocation

15-minute access tokens. Every logout writes the JTI to a Redis blacklist with the token's remaining TTL — revocation is instant, not eventual.

AES-256-GCM for stored headers

Any custom headers you set on a monitor (API keys, auth tokens) are encrypted at rest with a key derived via scrypt from your master ENCRYPTION_KEY. Rotate the key; re-encrypt on next update.

Process-level crash handlers

unhandledRejection and uncaughtException both log fatal and process.exit(1). Your orchestrator restarts a broken process in seconds, not minutes.

CORS allowlist, default-deny

Production refuses cross-origin requests unless explicitly allowlisted via CORS_ORIGINS. No wildcard fallback.

Rate limiting per-IP

100 req/min default, keyed by real client IP when behind nginx/Caddy (trustProxy honored). Scoped per-instance — move to a distributed counter when you scale the API horizontally.

Transactional audit log

Every mutation writes to audit_logs within the same transaction as the entity write. Rollback rolls back both — you can't have an unaudited change.

Strict TypeScript + Zod at every boundary

strict + exactOptionalPropertyTypes + noUncheckedIndexedAccess. Zod parse on every API body, every queue payload, every env var. Malformed input fails fast.

What we don't (yet) have

Things we'll have by the time you ask for them.

Honest inventory, because enterprise buyers check: no SOC 2 today, no ISO 27001, no HIPAA BAA. Self-host is the compliance story until then — you keep your data in your jurisdiction, under your controls, audited by your auditors.

Read the source. It's all there.

The defense is in the code, not a PDF behind a sales call.