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.
Data location
Section titled “Data location”- 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).
What is stored
Section titled “What is stored”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).
Redaction
Section titled “Redaction”- 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
doctorwarn about secret-looking names but do not redact them (SECURITY §4, ADR-055).
Authentication and authorisation
Section titled “Authentication and authorisation”- 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,Securein the image, 12 hours (login route, web Dockerfile). A nonce-based CSP and anti-framing headers are set on every page (SECURITY §2).
Deletion, retention, key rotation
Section titled “Deletion, retention, key rotation”- 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).
Supply chain
Section titled “Supply chain”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):
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.comNetwork
Section titled “Network”- API on 8080, web on 3000, published on
127.0.0.1only; terminate TLS at a proxy (OPERATIONS §9). - Metrics are off unless
METRICS_PORTis set (OPERATIONS §13).X-Forwarded-Foris ignored unlessTRUSTED_PROXY_COUNTis set (OPERATIONS §9).
Known gaps
Section titled “Known gaps”- Not there: SSO, user accounts, roles, per-user audit, and encryption of payloads beyond the database’s own (ROADMAP, ROADMAP).
audit_eventsis 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).
Reporting a vulnerability
Section titled “Reporting a vulnerability”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).