One of Bolt's major strengths is speed. A useful application can go from an idea to a live URL in well under an hour.
We recently reviewed a Bolt-built SaaS product for freelancers that handled project management, time tracking and invoicing. It already had active users, and the builder was preparing to raise the subscription price when they decided to have the code reviewed.
The findings below are anonymized, but the technical details and severity ratings are unchanged from the audit.
The application
A project management and invoicing tool built entirely in Bolt. React frontend, Node.js backend, PostgreSQL database. Users create accounts, add clients, log time against projects, and generate invoices as PDFs. Payments are handled through a Stripe integration.
The application was well-structured at the surface level. Clean UI, logical navigation, features that worked as intended. The builder clearly had a strong product sense and had iterated on the user experience. Bolt had done a good job translating that vision into functional code.
The findings: 15 issues across four severity levels
Critical (3 findings)
Stripe secret key in client-side bundle. The Stripe secret key (not the publishable key, the secret key) was imported directly into a React component that handles payment processing. This key was included in the client-side JavaScript bundle served to every user. Anyone opening browser developer tools could extract it. With the secret key, an attacker could issue refunds, modify subscription plans, access complete payment history, and create charges on behalf of the business.
No authorization on data endpoints. Every API endpoint checked whether the user was authenticated (logged in) but none checked whether the user was authorized to access the specific resource. Any authenticated user could access any other user's projects, time entries, client information, and invoices by modifying the ID parameter in the API request. The entire user base's data was accessible to any single user.
Invoice PDF generation executes unsanitized input. The PDF generation feature passed client-supplied data (project names, client names, line item descriptions) directly into the PDF template without sanitization. This created a server-side injection vulnerability where specially crafted input could execute commands on the server.
High (5 findings)
No rate limiting on any endpoint. Authentication, API, payment processing: all endpoints processed unlimited requests with no throttling. The login endpoint could be brute-forced without detection.
Session tokens never expire. JWT tokens issued at login had no expiration set. A token obtained once (through any means) would work indefinitely.
Password reset tokens predictable and reusable. Reset tokens were generated using a timestamp-based method that made them guessable. Tokens also remained valid after use, meaning a single intercepted reset link could be used repeatedly.
Database connection string in committed code. The PostgreSQL connection string (including host, username, and password) was committed to the repository in a configuration file. The repository was private, but the credentials were accessible to anyone with repo access and were present in the full git history.
No input validation on API endpoints. None of the 23 API endpoints validated incoming data. String fields accepted any length. Numeric fields accepted strings. Required fields could be omitted entirely. This produced both security vulnerabilities and application stability issues.
Medium (5 findings)
CORS configured to allow all origins. The API accepted requests from any domain, enabling cross-site request forgery against authenticated users.
Error responses include stack traces. Unhandled errors returned full stack traces to the client, exposing internal file paths, library versions, and database query structures.
No HTTPS enforcement. The application accepted HTTP connections without redirecting to HTTPS. Authentication credentials and session tokens could be intercepted on unencrypted connections.
Client-side route guards without server verification. Admin functionality was hidden from the UI using client-side JavaScript, but the underlying API endpoints were accessible to any authenticated user who knew the URL pattern.
No request logging. The application produced no access logs, authentication logs, or audit trail of any kind.
Low (2 findings)
Dependencies not pinned. Package versions used ranges rather than exact versions, meaning a dependency update could introduce breaking changes or vulnerabilities without any code change.
No health check endpoint. No endpoint for monitoring services to verify the application was running and connected to its database.
What was specific to the Bolt build
The findings aren't unusual for a Bolt-built application; they're the standard pattern we see across the platform. Bolt produces functional applications with well-organized code. It doesn't produce hardened applications.
Three characteristics of Bolt specifically contribute to the pattern:
The single-environment model. Bolt builds and deploys from one workspace. There's no concept of separate development and production environments within the tool. This makes the development experience smooth but means there's no natural checkpoint where production concerns get addressed.
Frontend-first architecture. Bolt excels at building reactive frontends. The backend logic it generates is functional but minimal: it serves the frontend rather than enforcing its own security model. This leads to the consistent pattern of security checks existing in the UI but not on the server.
Speed as a feature. Bolt's core value proposition is going from idea to deployed app in minutes. Production hardening is inherently a slow, deliberate process. These two priorities are in tension, and Bolt resolves the tension by optimizing for what its users value most: shipping.
None of this makes Bolt a bad tool. It makes Bolt exactly what it says it is: a fast way to build working applications. The production hardening step is a separate scope of work, and that's fine as long as you do it.
What happened next
The builder chose a hardening sprint after the audit. Over eight days, we resolved all three Critical findings and all five High findings, while leaving the Medium and Low items documented for follow-up.
The Stripe key was moved server-side. Authorization checks were added to every endpoint. All 23 API routes received input validation. Session management was rebuilt with expiration and refresh logic, and the application gained rate limiting, restricted CORS and audit logging.
Users didn't see a redesign or a changed workflow afterward. The work was concentrated in the security and operational behavior behind the interface.
The builder proceeded with the planned subscription price increase the following month.