Harden S3 presigned URL generation
Description
The storage service in src/services/storage.js generates presigned upload/download URLs with MIME allowlisting, size limits, tenant scoping, and path-traversal prevention, consumed by the invoice file routes in src/routes/invoiceFile.js. This issue tightens object-key construction and expiry bounds so a caller cannot escape their tenant prefix or request an excessive URL lifetime.
Requirements and context
- Repository scope: Liquifact/Liquifact-backend only.
- Enforce that every object key is rooted under the caller's
tenantId prefix and reject keys containing .., absolute paths, or path separators after normalization.
- Clamp upload/download expiry to the documented bounds (
DEFAULT_UPLOAD_URL_EXPIRY_SEC, MAX_DOWNLOAD_URL_EXPIRY_SEC) and reject out-of-range requests.
- Re-validate MIME against
ALLOWED_MIME_TYPES server-side, never trusting client-supplied content type alone.
- Ensure presigned URLs are never logged in full.
Suggested execution
- Fork the repo and create a branch
git checkout -b security/storage-24-presigned-url-scoping
- Implement changes
- Test and commit
Test and commit
- Run
npm test and npm run lint.
- Cover edge cases: traversal attempt, cross-tenant key, over-limit expiry, disallowed MIME, valid request.
- Include the full
npm test output and a short security-notes section in the PR description.
Example commit message
fix(security): scope presigned S3 keys to tenant and clamp URL expiry
Guidelines
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
Community & contribution rewards
- 💬 Join the Liquifact community on Discord for questions, reviews, and faster merges: https://discord.gg/JrGPH4V3
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward.
Harden S3 presigned URL generation
Description
The storage service in
src/services/storage.jsgenerates presigned upload/download URLs with MIME allowlisting, size limits, tenant scoping, and path-traversal prevention, consumed by the invoice file routes insrc/routes/invoiceFile.js. This issue tightens object-key construction and expiry bounds so a caller cannot escape their tenant prefix or request an excessive URL lifetime.Requirements and context
tenantIdprefix and reject keys containing.., absolute paths, or path separators after normalization.DEFAULT_UPLOAD_URL_EXPIRY_SEC,MAX_DOWNLOAD_URL_EXPIRY_SEC) and reject out-of-range requests.ALLOWED_MIME_TYPESserver-side, never trusting client-supplied content type alone.Suggested execution
git checkout -b security/storage-24-presigned-url-scopingsrc/services/storage.jsandsrc/routes/invoiceFile.js.tests/sme.upload.test.js.README.md.Test and commit
npm testandnpm run lint.npm testoutput and a short security-notes section in the PR description.Example commit message
fix(security): scope presigned S3 keys to tenant and clamp URL expiryGuidelines
Community & contribution rewards