To secure a Bolt.new + MongoDB stack, you need to: (1) validate all query inputs to prevent NoSQL injection attacks where user input can be objects instead of strings, (2) store connection strings in environment variables rather than code, (3) implement application-level authorization since MongoDB lacks row-level security, and (4) restrict network access to your MongoDB instance. This blueprint covers the unique security patterns required for document databases.
TL;DR
Bolt-generated MongoDB apps often have NoSQL injection vulnerabilities and missing authorization checks. Key fixes: validate all query inputs (user input can be objects, not just strings), store connection strings in environment variables, implement application-level authorization, and never expose MongoDB connection strings in client code.
MongoDB Security with Bolt.new
MongoDB requires different security patterns than SQL databases:
| Common Bolt Pattern | Security Issue | Fix |
|---|---|---|
| Direct user input in queries | NoSQL injection | Input validation with Zod/Joi |
| Connection string in code | Credential exposure | Environment variables |
| No authorization checks | Data leakage | App-level auth middleware |
| Find without filters | Full collection exposure | Always scope to user |
Part 1: Preventing MongoDB NoSQL Injection
The Problem
Bolt-generated queries often use user input directly:
// Bolt might generate this
app.get('/api/user', async (req, res) => {
const user = await db.collection('users').findOne({
username: req.query.username // Can be an object!
});
res.json(user);
});
// Attack: ?username[$ne]=null returns first user
// Attack: ?username[$gt]= returns users alphabetically
The Fix
import { z } from 'zod';
const usernameSchema = z.string().min(1).max(50);
app.get('/api/user', async (req, res) => {
// Validate input is a string
const result = usernameSchema.safeParse(req.query.username);
if (!result.success) {
return res.status(400).json({ error: 'Invalid username' });
}
const user = await db.collection('users').findOne({
username: result.data // Guaranteed string
});
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
// Remove sensitive fields
const { password, ...safeUser } = user;
res.json(safeUser);
});
Critical: In Express/Node.js, query parameters can be objects if formatted as ?key[$operator]=value. Always validate type before using in MongoDB queries.
Part 2: MongoDB Connection String Security
Check for Exposed Credentials
# Look for hardcoded connection strings
grep -r "mongodb" . --include="*.ts" --include="*.js"
grep -r "mongodb+srv" .
# Should find only:
# process.env.MONGODB_URI or similar
Proper Configuration
import { MongoClient } from 'mongodb';
const uri = process.env.MONGODB_URI;
if (!uri) {
throw new Error('MONGODB_URI environment variable not set');
}
const client = new MongoClient(uri);
let db: Db | null = null;
export async function getDb() {
if (!db) {
await client.connect();
db = client.db(); // Uses database from connection string
}
return db;
}
Part 3: Authorization Middleware
MongoDB doesn't have row-level security. Implement it in your application:
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
export interface AuthRequest extends Request {
user?: { id: string; email: string };
}
export function requireAuth(
req: AuthRequest,
res: Response,
next: NextFunction
) {
const token = req.headers.authorization?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET!);
req.user = decoded as { id: string; email: string };
next();
} catch {
return res.status(401).json({ error: 'Invalid token' });
}
}
Using Auth in Routes
import { Router } from 'express';
import { ObjectId } from 'mongodb';
import { requireAuth, AuthRequest } from '../middleware/auth';
import { getDb } from '../lib/mongodb';
const router = Router();
// Get user's own posts only
router.get('/', requireAuth, async (req: AuthRequest, res) => {
const db = await getDb();
const posts = await db.collection('posts')
.find({ userId: req.user!.id })
.toArray();
res.json(posts);
});
// Update with ownership check
router.put('/:id', requireAuth, async (req: AuthRequest, res) => {
const db = await getDb();
const post = await db.collection('posts').findOne({
_id: new ObjectId(req.params.id)
});
if (!post) {
return res.status(404).json({ error: 'Post not found' });
}
if (post.userId !== req.user!.id) {
return res.status(403).json({ error: 'Not authorized' });
}
await db.collection('posts').updateOne(
{ _id: new ObjectId(req.params.id) },
{ $set: { title: req.body.title, content: req.body.content } }
);
res.json({ success: true });
});
export default router;
Security Checklist
Post-Export Checklist for Bolt + MongoDB
No hardcoded connection strings
MONGODB_URI in environment variables
Input validation on all query parameters
Authorization middleware on protected routes
Queries scoped to authenticated user
Sensitive fields excluded from responses
MongoDB user has minimal permissions
Network access restricted (Atlas/cloud)
Alternative Stacks to Consider
**Bolt.new + Supabase**
PostgreSQL with built-in RLS protection
**Bolt.new + PlanetScale**
MySQL with branching workflows
**Bolt.new + Convex**
TypeScript-native database alternative
What's NoSQL injection?
Unlike SQL injection (which uses strings), NoSQL injection exploits MongoDB's query operators. Attackers send objects like {$ne: null} instead of strings, modifying query logic.
Should I use Mongoose with Bolt-generated code?
Mongoose adds schema validation which helps prevent injection. If Bolt generated native MongoDB driver code, consider adding Mongoose or Zod validation to ensure type safety.
How do I restrict MongoDB network access?
In MongoDB Atlas, go to Network Access and remove 0.0.0.0/0. Add only your deployment server's IP addresses. This prevents direct database access even if credentials leak.