Security
PDFPipe is built with security as a foundational requirement. This page describes the measures we have in place to protect your data.
For questions about our data processing practices, see our Data Processing Agreement. To report a security concern, email security@pdfpipe.dev.
Encryption
- All API traffic is encrypted in transit with TLS 1.2+ (HTTPS only). HTTP connections are rejected. The .dev TLD enforces HSTS by default.
- Data at rest is encrypted in DynamoDB using AWS-managed encryption keys (AES-256).
- PDF files stored in S3 are encrypted with server-side encryption (SSE-S3 minimum, SSE-KMS preferred).
API Key Security
- API keys are stored as bcrypt hashes — the raw key is only shown once at creation and never stored.
- Key lookup uses a SHA-256 hash prefix for fast retrieval without exposing the full key.
- Keys can be scoped to specific IP addresses via an allowlist when creating a key in the dashboard, blocking requests from unauthorised origins.
- Keys can be revoked instantly from the dashboard, and revoked keys are rejected immediately.
Authentication & Sessions
- Dashboard sessions use signed JWT tokens with a 24-hour expiry.
- JWT tokens contain only the minimum claims needed (userId, accountId, memberRole).
- Suspended accounts are blocked at the authentication middleware layer before any processing occurs.
Ephemeral Data Storage
- Converted PDF output is stored temporarily in S3 and served via presigned URLs scoped to the exact object path.
- Primary cleanup: an asynchronous Lambda deletes the S3 object as soon as the presigned URL response is delivered.
- Backstop cleanup: an S3 lifecycle policy automatically deletes all objects after 48 hours, regardless of other cleanup.
- Presigned URL expiry varies by tier — 1 hour (Free), 24 hours (Starter), 7 days (Pro/Business).
- There is no long-term storage of PDF content. PDFPipe does not retain your documents.
Data Isolation
- Every request is assigned a unique UUID v4 request ID.
- S3 objects are namespaced to /{userId}/{requestId}/ — cross-user access is impossible by design.
- Presigned URLs are scoped to the exact S3 object path and cannot be used to access other objects.
- DynamoDB records are partitioned by user/account with composite keys preventing cross-tenant queries.
Input Validation & SSRF Prevention
- All incoming requests are validated at the API boundary using Zod schemas. Invalid requests are rejected before processing.
- Request body size is limited to 64 KB to prevent abuse.
- URL validation blocks private and reserved IP ranges (10.x, 172.16-31.x, 192.168.x, 127.x, 169.254.x) to prevent SSRF attacks.
- Only HTTP and HTTPS protocols are accepted — no file://, ftp://, or other schemes.
- URLs are limited to 2,048 characters.
Infrastructure
- Hosted on AWS EU (London) — eu-west-2 — using SST v3 (Ion) with infrastructure-as-code. All resources are defined declaratively and version-controlled.
- Compute runs on AWS Lambda with IAM least-privilege policies — each function has only the permissions it needs.
- The S3 bucket has no public access. All file access goes through presigned URLs.
- Processing queues use AWS SQS FIFO with dead letter queues (DLQ). Failed jobs are retried up to 3 times before moving to the DLQ.
- API Gateway enforces a 30-second timeout and CORS policies restricting origins to production domains.
- CloudFront CDN serves the web application globally from edge locations, with the origin in eu-west-2.
Monitoring & Audit
- Structured JSON logging with request ID, hashed user ID, tier, duration, and outcome for every request.
- Admin audit logging tracks all administrative actions (account suspension, tier changes, etc.).
- AWS CloudWatch captures Lambda invocation logs, errors, and latency metrics.
Responsible Disclosure
If you discover a security vulnerability, please email security@pdfpipe.dev with details. We will acknowledge receipt within 48 hours and provide an initial assessment within 5 business days.