Without spam detection, a single automated account can flood a community feed with duplicate or rapid-fire posts, drowning legitimate content and degrading the user experience to the point where real users leave. This is a CWE-770 (Allocation of Resources Without Limits) failure: uncapped post creation burns database storage and CDN bandwidth at attacker-controlled rates. Beyond quality, spam floods can mask coordinated manipulation campaigns — link farms, referral abuse, or coordinated inauthentic behavior — that are invisible without rate tracking.
Low because spam degrades platform quality and inflates infrastructure costs but does not expose user data or enable direct account compromise.
Implement per-user rate limiting and content-hash deduplication on all post/comment submission handlers. In src/middleware/rateLimiter.ts:
import rateLimit from 'express-rate-limit';
export const postLimiter = rateLimit({
windowMs: 5 * 60 * 1000, // 5 minutes
max: 5,
keyGenerator: (req) => req.user.id,
message: 'Too many posts. Please wait before posting again.'
});
Pair rate limiting with a content-hash check: compute sha256(content) per user and reject exact duplicates submitted within the last hour. Reject at the API level before writing to the database.
ID: community-moderation-safety.content-filtering.spam-detection
Severity: low
What to look for: Check for logic that detects spam: rapid repeated posting, duplicate content, suspicious patterns (many links, excessive hashtags), or third-party spam detection services. Look for rate limiting on post/comment submissions, or duplicate content comparison before save.
Pass criteria: The system detects and handles spam: either rejects rapid postings from the same user, deduplicates identical content, or uses a third-party spam detection service. Count all post/comment submission handlers and verify that at least 1 spam-detection mechanism (rate limit, dedup, or spam API) is applied. Actions are taken before or immediately after content creation. Report the ratio of spam-protected endpoints to total submission endpoints even on pass.
Fail criteria: No spam detection is implemented. Users can flood the platform with duplicate or rapid-fire content. A TODO comment or disabled spam check does not count as pass.
Skip (N/A) when: Platform has <500 active users AND uses manual-only moderation.
Detail on fail: "No spam detection implemented. A user can post identical content repeatedly or flood the platform with rapid postings."
Remediation: Implement rate limiting and duplicate detection on post submissions:
import { rateLimit } from 'express-rate-limit';
// Rate limiting: 5 posts per 5 minutes per user
const postLimiter = rateLimit({
windowMs: 5 * 60 * 1000,
max: 5,
keyGenerator: (req) => req.user.id,
message: 'Too many posts. Please wait before posting again.'
});
app.post('/api/posts', postLimiter, async (req, res) => {
const { content } = req.body;
const userId = req.user.id;
// Check for duplicate content in the last hour
const recentPost = await db.posts.findOne({
content,
userId,
createdAt: { $gte: new Date(Date.now() - 3600000) }
});
if (recentPost) {
return res.status(400).json({ error: 'You already posted this content recently' });
}
// Check for similar content using simple hash-based deduplication
const contentHash = require('crypto').createHash('md5').update(content).digest('hex');
const similar = await db.postHashes.findOne({ hash: contentHash, userId });
if (similar) {
return res.status(400).json({ error: 'Similar content already posted' });
}
// Save post
const post = await db.posts.create({ content, userId, createdAt: new Date() });
await db.postHashes.create({ hash: contentHash, userId, postId: post.id });
res.status(201).json(post);
});
Reject posts that exceed the rate limit and flag exact duplicates.