Skip to content

security: harden backend API (SSRF, CORS, rate limiting, Helmet, Stripe HTTP redirect)#1

Draft
Copilot wants to merge 1 commit intomainfrom
copilot/review-code-for-security
Draft

security: harden backend API (SSRF, CORS, rate limiting, Helmet, Stripe HTTP redirect)#1
Copilot wants to merge 1 commit intomainfrom
copilot/review-code-for-security

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 7, 2026

Summary

Full security audit of the codebase. The following issues were found and fixed in the backend (needl-driver-api):


🔴 Critical: SSRF via unrestricted MongoDB URI

File: backend/src/mongo.ts

The server accepted arbitrary MongoDB URIs from authenticated clients and opened connections to them, allowing abuse to probe internal network resources (private IP ranges, AWS metadata endpoint 169.254.169.254, etc.).

Fix: Added validateMongoUri(), called inside withMongoClient() before every connection:

  • Rejects any URI that doesn't use mongodb:// or mongodb+srv:// scheme
  • Blocks loopback, private RFC-1918, link-local, and IPv6 ULA/link-local host literals

🔴 Critical: CORS allows all origins by default

File: backend/src/index.ts

When CORS_ORIGINS was not set, the server used cors({ origin: true }) which allows any origin to make cross-origin requests to the API.

Fix: Changed fallback to cors({ origin: false }) (deny-all). A startup warning is logged when CORS_ORIGINS is not configured. Updated .env.example to document this required variable.


🟠 High: No rate limiting

File: backend/src/index.ts

No rate limiting existed on any endpoint, enabling DoS and abuse of the MongoDB proxy.

Fix: Added express-rate-limit — 60 requests per minute per IP on all /v1/ routes, with standard RateLimit-* headers.


🟠 High: Missing HTTP security headers

File: backend/src/index.ts

No security headers (CSP, X-Frame-Options, HSTS, etc.) were set.

Fix: Added helmet middleware.


🟡 Medium: http:// allowed as Stripe checkout redirect URL

File: backend/src/stripeDonate.ts

When DONATE_REDIRECT_ALLOWLIST was unset, plain http:// URLs were accepted as Stripe success/cancel redirect targets, which could be used to redirect users to insecure pages.

Fix: Removed http:// from the default-allowed schemes. Only https://, exp://, exps://, and custom app schemes (e.g. needl://) are now permitted without an explicit allowlist.


🟡 Medium: Unbounded skip parameter

File: backend/src/mongo.ts

The skip offset in findDocuments had no upper bound, allowing a client to send arbitrarily large skip values and cause performance degradation.

Fix: Capped skip at 100_000.


Changes

  • backend/src/index.ts — add helmet, express-rate-limit, fix CORS default
  • backend/src/mongo.ts — add validateMongoUri() (SSRF guard), cap skip
  • backend/src/stripeDonate.ts — remove http:// from default redirect allowlist
  • backend/.env.example — document CORS_ORIGINS
  • backend/package.json / package-lock.json — add helmet@8.1.0, express-rate-limit@8.3.2

Notes (not fixed — design-level or low risk)

  • MongoDB connection strings stored in AsyncStorage (frontend): URIs with embedded credentials are stored in AsyncStorage (not SecureStore) on mobile. This is a design decision; fixing it would require a significant migration.
  • MongoDB error messages forwarded to client: Error strings from MongoDB are returned verbatim in API responses. In a future hardening pass, consider stripping driver-internal details from error messages before returning them.

…t, restrict Stripe HTTP redirect, cap skip parameter

Agent-Logs-Url: https://github.com/AnousAlma/needl/sessions/c96eaee9-4a0d-4b4f-8d11-a651b1a956fa

Co-authored-by: AnousAlma <112284235+AnousAlma@users.noreply.github.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
needl Ready Ready Preview, Comment Apr 7, 2026 5:11am
needl-backend Error Error Apr 7, 2026 5:11am

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants