← All docs

Security

What DataEgress never has access to

  • Your production database. DataEgress only calls the HTTP endpoint you expose via defineDataset(...).handler() — it never holds database credentials, never opens a DB connection, never sees your schema.
  • Raw destination credentials at rest. secretAccessKey values are encrypted (AES-256-GCM) before being stored, and are never returned by any API response — GET/POST /api/destinations always mask them.

What DataEgress does have access to, and for how long

  • Row data, transiently, while generating an export file. Rows pass through DataEgress's process to be written to CSV/Parquet and uploaded; they are not retained beyond the local temp file, which is deleted after a successful upload.
  • The generated export file itself, for up to 7 days, for signed_url destinations (stored in DataEgress's own storage — local disk in dev, R2 in production if configured) or as a preview mirror alongside s3 deliveries. An hourly automated sweep (sweepExpiredExportObjects) deletes the object after that window; the export's row count/checksum/manifest metadata is kept in the database regardless, for delivery history. Files delivered directly to a customer-owned S3/R2 bucket are not covered by this — once delivered, they're entirely under that bucket's own retention, outside DataEgress's control. See limitations.md.

Authentication

Two independent mechanisms, both resolving to the same server-side organizationId scoping — never trusted from the request body:

  • Cookie session (dashboard, human operations): password hashed with scrypt, opaque random session token stored in Postgres, httpOnly/secure cookie. Logging out deletes the session row — it stops authenticating immediately, not just client-side.
  • API key (Authorization: Bearer dte_live_..., SDK / server-to-server): 192 bits of random entropy; only its SHA-256 hash is ever persisted, never the full key. Shown once, at creation. Revoking a key is immediate — the hash lookup simply stops matching an active row.

A basic, single-instance in-memory rate limit slows down repeated failed Bearer attempts. It is not a distributed rate limiter (that would need Redis/Upstash — deliberately out of scope for now) and resets on cold start.

Encryption

  • Destination credentials: AES-256-GCM, key derived from DATARELAY_ENCRYPTION_KEY.
  • Local signed download URLs: HMAC-SHA256 tokens (DATARELAY_SIGNING_SECRET), time-limited (1 hour).
  • In transit: all destination uploads use HTTPS (AWS SDK default); the fetchPage HTTP call to your dataset endpoint should be HTTPS in production (the SDK doesn't enforce this in V1 — see limitations.md).

Change both DATARELAY_ENCRYPTION_KEY and DATARELAY_SIGNING_SECRET to real random values before deploying anywhere beyond local dev. The defaults are intentionally insecure placeholders.

GDPR / data retention

  • Generated export files in DataEgress-controlled storage are automatically deleted after 7 days (lib/retention.ts's EXPORT_OBJECT_RETENTION_DAYS, enforced by an hourly Inngest sweep — not a manual or best-effort process). Run metadata (row counts, checksums, manifests) is retained in the database after that, for delivery history.
  • Files delivered directly to a customer-owned S3/R2 bucket are outside this policy entirely — DataEgress never deletes anything from a destination bucket it doesn't own.

Not yet implemented as product features:

  • No per-destination data residency controls.
  • No formal DPA/subprocessor documentation (this is a codebase, not a company with a legal entity yet).

If you're evaluating DataEgress for a compliance-sensitive use case today, treat V1 as infrastructure you operate yourself, not a vetted subprocessor.

SOC 2

Not pursued yet, deliberately — see the "why" in the product's own research: a SOC 2 Type II engagement costs real money and takes a 6–12 month observation period, and the customer-callback architecture (DataEgress never touches your database) meaningfully lowers what a security reviewer needs to approve without it. Revisit once a real deal is blocked on it.

Reporting a security issue

This is an early-stage internal project without a public disclosure program yet. File an issue in this repo, or contact the maintainer directly.

Security — DataEgress