Summary
The piik.me README's own "Security" section explicitly lists rate limiting under "Recommended Additions" with a code snippet showing it is not yet implemented. The /api/shorten endpoint and all /api/track/* endpoints are currently unprotected by any rate limit — an automated script can create thousands of short links per minute or artificially inflate any link's analytics counters.
Problem
POST /api/shorten has no request rate limit. A script can call it in a loop and exhaust the Firestore write quota, costing real money on the Firebase billing plan.
POST /api/track/impression/:shortCode and POST /api/track/share/:shortCode have no rate limit — a single IP can inflate any link's analytics by making thousands of requests, making the analytics dashboard meaningless.
GET /:shortCode (the redirect endpoint) has no rate limit — it is the most publicly exposed endpoint and the most likely to be abused.
- The README's production checklist explicitly has an unchecked item:
[ ] Implement rate limiting.
- The
memory.service.js in src/services/ implies some in-memory state management — if this is used for analytics, flooding it could cause memory exhaustion.
Proposed Solution
Install express-rate-limit and apply per-route limits in server.js:
npm install express-rate-limit
// server.js — add after existing middleware setup
const rateLimit = require('express-rate-limit');
// General API rate limit: 100 requests per 15 minutes per IP
const apiLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false,
message: {
error: 'Too many requests. Please try again in 15 minutes.',
},
});
// Strict limit for link creation: 10 new short links per hour per IP
const createLimiter = rateLimit({
windowMs: 60 * 60 * 1000,
max: 10,
message: {
error: 'You have created too many links. Please try again in an hour.',
},
});
// Analytics tracking: 30 requests per minute per IP (allows legitimate traffic bursts)
const trackingLimiter = rateLimit({
windowMs: 60 * 1000,
max: 30,
message: {
error: 'Too many tracking requests.',
},
});
// Apply limits
app.use('/api/', apiLimiter);
app.use('/api/shorten', createLimiter);
app.use('/api/track/', trackingLimiter);
Additionally, add security headers using helmet (also listed as "Recommended" in the README):
// server.js — add before any route definitions
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: false, // disable CSP on API — set it on the frontend CDN instead
}));
Additional Notes
express-rate-limit uses in-memory storage by default — for a single-server Vercel deployment, this is sufficient. A Redis store (rate-limit-redis) can be added later if horizontal scaling is needed.
- The Vercel deployment may impose its own rate limits, but these cannot be relied on for application-level protection.
- Both
express-rate-limit and helmet are the most downloaded npm security packages in their categories — they are well-maintained and require zero configuration beyond the above.
- The 10 links/hour
createLimiter applies to unauthenticated requests; authenticated users (Firebase Auth token present) could be given a higher limit in a follow-up.
Could you assign this issue to me?
Labels: security, enhancement, backend, GSSoC 2026
Summary
The piik.me README's own "Security" section explicitly lists rate limiting under "Recommended Additions" with a code snippet showing it is not yet implemented. The
/api/shortenendpoint and all/api/track/*endpoints are currently unprotected by any rate limit — an automated script can create thousands of short links per minute or artificially inflate any link's analytics counters.Problem
POST /api/shortenhas no request rate limit. A script can call it in a loop and exhaust the Firestore write quota, costing real money on the Firebase billing plan.POST /api/track/impression/:shortCodeandPOST /api/track/share/:shortCodehave no rate limit — a single IP can inflate any link's analytics by making thousands of requests, making the analytics dashboard meaningless.GET /:shortCode(the redirect endpoint) has no rate limit — it is the most publicly exposed endpoint and the most likely to be abused.[ ] Implement rate limiting.memory.service.jsinsrc/services/implies some in-memory state management — if this is used for analytics, flooding it could cause memory exhaustion.Proposed Solution
Install
express-rate-limitand apply per-route limits inserver.js:Additionally, add security headers using
helmet(also listed as "Recommended" in the README):Additional Notes
express-rate-limituses in-memory storage by default — for a single-server Vercel deployment, this is sufficient. A Redis store (rate-limit-redis) can be added later if horizontal scaling is needed.express-rate-limitandhelmetare the most downloaded npm security packages in their categories — they are well-maintained and require zero configuration beyond the above.createLimiterapplies to unauthenticated requests; authenticated users (Firebase Auth token present) could be given a higher limit in a follow-up.Could you assign this issue to me?
Labels:
security,enhancement,backend,GSSoC 2026