| Version | Supported |
|---|---|
| 0.1.x | ✅ |
Only the latest minor release receives security patches. Upgrade to the current version before reporting.
Do not open a public GitHub issue for security vulnerabilities.
Email security@bymax.one with:
- A clear description of the vulnerability and its impact
- Steps to reproduce (minimal reproduction preferred)
- The affected versions and component (
StorageService,KeyResolverService, signed URLs, etc.) - Any relevant code, logs, or CVE references
You will receive an acknowledgement within 72 hours. Coordinate disclosure timeline with the maintainers before publishing. Credit is given in the release notes upon fix.
The following properties are designed to hold in every supported release.
KeyResolverService normalises every caller-supplied key before it reaches the AWS SDK:
- Rejects keys containing
..segments (STORAGE_KEY_INVALID/ HTTP 400) - Rejects keys that start with
/after normalisation - Rejects keys that are empty after normalisation
- Prepends
keyPrefixto enforce multi-tenant isolation — callers cannot escape their own prefix
Validate user-controlled input before passing it to StorageService; the library provides the last line of defence, not the only one.
- Per-request
ttlSecondsvalues abovesignedUrls.maxTtlSecondsare silently clamped, not rejected (avoids leaking the server ceiling to the caller). signedUrls.maxTtlSecondsis clamped to 604 800 s (the SigV4 7-day absolute ceiling) at module initialisation.ttlSeconds≤ 0 is rejected withSTORAGE_SIGNED_URL_TTL_INVALID(HTTP 400).- A signed URL is a temporary credential — never log it (a logged signed URL is accessible to anyone with access to your log system). Never include a signed URL in
detailsof aStorageException.
A presigned PUT bypasses the library's local MIME/size validation — bytes go directly to the provider. Mitigate by:
- Setting
maxSizeBytesingetUploadUrl()(maps to a Content-Length-Range presigner policy). - Running a
HEADcheck on the uploaded object to verify size and content-type. - Using a post-upload
IFileScannerto scan for malware after the bytes land.
- Pass AWS credentials via environment variables or AWS SDK credential providers, never hard-code them.
- Use AWS Secrets Manager, HashiCorp Vault, or Doppler in production.
- Prefer IAM roles with STS temporary credentials (
credentials.sessionToken) over long-lived access keys. - The
detailsfield ofStorageExceptionnever carries a credential or signed URL. - Never put PII (email addresses, government IDs) in object keys — keys appear in provider logs, CDN access logs, and distributed traces.
- Enable
serverSideEncryption: 'AES256'at a minimum in production environments. - For sensitive data, use
'aws:kms'and ensure the IAM policy allowskms:Encryptandkms:Decrypton the target KMS key. serverSideEncryption: 'NONE'is a library-only sentinel — it omits the SSE header without sending the string'NONE'to the provider.
- The
mimeWhitelistcheck is based on theContent-Typeheader supplied by the client; it is header-only and cannot detect a file whose true type differs from its declared type. - Plug an
IUploadValidatorthat usesreadBytes(n)for magic-byte verification when the content source is untrusted.
@aws-sdk/client-s3 ≥ 3.729.0 sends x-amz-checksum-crc32 integrity headers by default (requestChecksumCalculation: 'WHEN_SUPPORTED'). Cloudflare R2, Backblaze B2, MinIO, DigitalOcean Spaces, and Wasabi reject these headers. Every non-AWS provider recipe included in this library sets:
requestChecksumCalculation: 'WHEN_REQUIRED',
responseChecksumValidation: 'WHEN_REQUIRED',If you build a custom configuration instead of using a recipe, you must add this opt-out manually. See README.md — Provider Compatibility for the full explanation.
publicRead: true (or defaultPublicRead: true) sends ACL: 'public-read' on PutObject. This fails on modern AWS S3 buckets (Object Ownership = "Bucket owner enforced") with HTTP 400 AccessControlListNotSupported, and is a silent no-op on Cloudflare R2. Use a bucket policy, a CDN, or signed URLs for public object delivery.
The following files have elevated security relevance and warrant close review on any change:
| File | Concern |
|---|---|
src/server/services/key-resolver.service.ts |
Path-traversal guard; keyPrefix isolation |
src/server/utils/ttl-clamp.ts |
Signed-URL TTL clamping and SigV4 ceiling |
src/server/utils/mime-match.ts |
MIME wildcard matching (mismatches could allow disallowed types) |
src/server/utils/idempotency-cache.ts |
In-memory LRU; per-instance (not shared across replicas) |
src/server/services/signed-url.service.ts |
Presigned URL generation; never log the output |
src/server/config/validate-options.ts |
Module-options validation; malformed config must fail closed |