Skip to content

Validate and scope S3 presigned URL generation to prevent path traversal and over-broad access #286

Description

@mikewheeleer

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.

Metadata

Metadata

Assignees

No fields configured for Feature.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions