Skip to content

Security review packet

For a security engineer deciding whether a Wayscribe pilot may run in their environment. Every statement links to its source; the threat model is SECURITY.md.

  • Self-hosted, with no hosted service and no account (../SECURITY.md). All state is in your own PostgreSQL, with an ordinary role and no extensions (OPERATIONS §1, ADR-037).
  • The running services send no telemetry. Building the images downloads packages; Next.js build telemetry is disabled (../SECURITY.md).
  • The API’s only outbound requests are replays to admin-configured destinations on REPLAY_ALLOWED_HOSTS (send.ts, SECURITY §9).

Capture mode is per environment, and new environments get redacted-payload (migration 002). metadata-only stores no input or output payloads; full-payload also needs ALLOW_FULL_PAYLOAD_CAPTURE, off by default (INGESTION_CONTRACT §7).

Stored as What
plain jsonb, after redaction payloads; error, runtime, deployment and custom metadata
plain text event names, timings, trace ids, entity type
plain text, by the host’s choice journey labels; copies of aliases marked displayable
AES-256-GCM entity identifiers and alias values (searched by HMAC tokens), replay destination headers

Sources: ingest-event.ts, SECURITY §6, SECURITY §7, ADR-053, ADR-054. Error messages are masked by shape, and stacks are dropped unless full capture is on (ADR-046).

  • By field name at any depth, including header shapes, in the SDK and again on the server; a match becomes [REDACTED] (ADR-035, SECURITY §4). The built-in list includes eight webhook signature headers (default-secrets.ts).
  • Not caught: a credential under a name no rule knows. The SDK and doctor warn about secret-looking names but do not redact them (SECURITY §4, ADR-055).
  • One admin token (at least 32 characters) reads any project and can delete and replay. There are no user accounts, no roles, and no record of who used it (ADR-029, schema.ts).
  • API keys carry 192 random bits, are stored as a prefix and an HMAC, and are scoped to one project and one environment. They cannot delete, or write into another environment’s journey (api-key.ts, SECURITY §2, SECURITY §14).
  • Throttle: five failed credentials a minute from one address locks it for five minutes, per process. Ingestion is not throttled (OPERATIONS §9).
  • Web session: a cookie signed with a key derived from the admin token; HttpOnly, SameSite=Strict, Secure in the image, 12 hours (login route, web Dockerfile). A nonce-based CSP and anti-framing headers are set on every page (SECURITY §2).
  • Retention is per environment, swept hourly (OPERATIONS §7). Deletion is hard and audited without the value, and erasure does not search payload contents (OPERATIONS §8).
  • Deleted or masked data stays in dead row versions until vacuum, and in WAL, replicas and backups (OPERATIONS §8).
  • Key rotation has a grace period with the old key read alongside the new one (OPERATIONS §6, ADR-044).

CI blocks on pnpm audit, gitleaks and Trivy. Nothing is published yet, and releases will be 0.x. Images will be signed with Sigstore keyless signing and carry a CycloneDX SBOM per platform; the npm package will be published through GitLab OIDC with provenance (OPERATIONS §11, ROADMAP). To verify, with your tag (full steps):

Terminal window
cosign verify registry.gitlab.com/jojithedev/wayscribe/api:vX.Y.Z \
--certificate-identity 'https://gitlab.com/jojithedev/wayscribe//.gitlab-ci.yml@refs/tags/vX.Y.Z' \
--certificate-oidc-issuer https://gitlab.com
  • API on 8080, web on 3000, published on 127.0.0.1 only; terminate TLS at a proxy (OPERATIONS §9).
  • Metrics are off unless METRICS_PORT is set (OPERATIONS §13). X-Forwarded-For is ignored unless TRUSTED_PROXY_COUNT is set (OPERATIONS §9).
  • Not there: SSO, user accounts, roles, per-user audit, and encryption of payloads beyond the database’s own (ROADMAP, ROADMAP).
  • audit_events is never swept, and the login limiter is per process (ROADMAP). The development secrets are published, and propagated context is not authenticated (../SECURITY.md).
  • The pre-release security review of 2026-09-16, done by an AI review agent at the maintainer’s direction and not an independent audit, found no Critical, High or Medium issues. No outside party has reviewed the code. Among its low notes: a dry run holds row locks for the whole batch (INGESTION_CONTRACT §8), and a text search that matches nothing scans its whole window, bounded only by the statement timeout (OPERATIONS §10).

Email security@wayscribe.dev, or open a confidential issue at https://gitlab.com/jojithedev/wayscribe/-/issues/new. Expect an acknowledgement within a week (../SECURITY.md).