> Markdown version of [/magazine/598-security-basics-for-vibe-coders](https://www.wearedevelopers.com/magazine/598-security-basics-for-vibe-coders). Every page supports `.md` or `Accept: text/markdown`. Links point to the HTML versions so they work for humans too. Agent guide: [/agents.md](https://www.wearedevelopers.com/agents.md). --- # Security Basics for Vibe Coders **By:** Christina Schaireiter **Published:** June 25, 2025 Vibe coding has become a popular trend in the tech world. With so many tools now available for both developers and non-developers, it’s easier than ever to build projects using natural language, in some cases without touching a line of code along the way. The problem is, speed often comes at the expense of security. There have been [numerous reports of vibe coders facing attacks on their applications](https://medium.com/@armen_andreasian/vibe-coding-is-scam-29f8d0972554), with little understanding of the root causes or how to resolve them. With this in mind we thought we’d put together five essential security practices to make your applications a little more secure. It’s certainly not an exhaustive list, but it’s a quick reference you can use to avoid the most obvious vibe-killing pitfalls. ## 1. Don’t Trust User Input Even if you’re not writing raw SQL, your tools often are. Whether you’re using SQL databases directly, through ORMs or via calls to third-party APIs, SQL often plays a role along the way. If that input is inserted into the query without proper safeguards, it can be manipulated by an attacker. One common example is SQL injection, where malicious input alters the structure of the query to give unauthorised access to your database. Here’s an example of something you’re likely to do, **Unsafe example (manual query):** // 🚨 Vulnerable to SQL injection const result = await db.query( `SELECT * FROM users WHERE email = '${req.body.email}'` ); If a user sends a malicious email like `' OR '1'='1`, the resulting SQL becomes: `SELECT * FROM users WHERE email = '' OR '1'='1'` This would return all users, completely bypassing any intended filters (as 1 is 1, so it’s always true). Instead, we could use a parameterised query, like so: // ✅ Parameterized query const result = await db.query( 'SELECT * FROM users WHERE email = $1', [req.body.email] ); In our second example, the database engine sees the structure of the query first `(SELECT * FROM users WHERE email = $1)`, receives the actual user input `(req.body.email)` as a separate value and treats that value only as data, never as part of the SQL code. As an additional side-note, some platforms support **Row-Level Security (RLS)**, which lets you define rules at the database level to control which rows a user can access. Enabling RLS gives you an added layer of protection, so we would also recommend using them where possible. ## 2. Secure Your Secrets Despite being a well-known pitfall among developers, you would be surprised how often people push secrets like API keys or database credentials to GitHub, pass them to LLMs or even hard-code them in their code. If exposed, these secrets can be misused and cost you money, with the attacker able max out quotas and rate limits and run up a huge bill in the process. This can be avoided so easily. First of all, add an `.env` file to store your secrets in (otherwise known as environment variables). Secondly, add your `.env` to the your `.gitignore` file. As the file-name suggests, this file tells GitHub which files it should ignore, so you don’t accidentally upload your `.env` file to GitHub. Finally, make sure you keep your secrets secure. Whether you use a secret manager or tools like [git-secrets](https://github.com/awslabs/git-secrets), store the API key in an offline location, or even write them down in a notepad, just make sure you keep them safe. ## 3. Always Sanitise Inputs Attackers can exploit inputs like form fields, URLs, or query parameters to inject scripts (XSS), break your application, or manipulate behavior. Here’s an example of how this works. In this scenario, you allow users to add comments to a page, and you then render the comment without sanitising it first: // User-submitted comment res.send(`<div>${req.body.comment}</div>`); Now imagine a bad actor submits the following text (code) as a comment, with it then being rendered: <script>alert('hacked');</script> This would then run in the browser of anybody who accessed the page, which could cause all kinds of issues. To deal with this, validate and sanitise input on the server side, use schema validation libraries like Zod to make sure forms and inputs expect specific data types, and if rendering user-generated HTML, sanitise it using libraries like DOMPurify. ## 4. Add Rate Limits APIs are surprisingly sensitive. Even with sanitised inputs, parameterised queries and secure secrets warding off the majority of attacks, unsophisticated techniques like abusing rate limits can put your application out of action. Without basic limits in place, attackers or bots can overwhelm your endpoints by spamming forms, brute-forcing login attempts, or making excessive API calls. To deal with this, you should apply rate limiting to all public-facing endpoints to limit the frequency that users can make calls to them. For example, if you were using an Express server, you could use [express-rate-limit](https://www.npmjs.com/package/express-rate-limit) like so: const rateLimit = require('express-rate-limit'); const limiter = rateLimit({ windowMs: 60 * 1000, // 1 minute max: 20, // limit each IP to 20 requests per windowMs }); app.use(limiter); ## 5. Don’t Roll Your Own Auth Learning how to build your own authentication system might seem like a great way to learn more about the relationship between server and client, and how to handle tokens, cookies and sessions. However, there’s a reason so many people stick to well-established auth libraries to handle authentication. Doing it manually can introduce serious vulnerabilities - from broken access control to session hijacking or token theft. With this in mind, we recommend you use established authentication libraries or services like NextAuth.js, Supabase Auth, Clerk, or Auth0, with each one allowing you to confidently handle cookies, sessions and tokens, abstracting away a lot of the complexity that leads to errors and vulnerabilities. ## Wrapping Up When we think about vibe coding, security is a vibe-killer. With so much focus on building projects quickly, slowing down to add rate limits or refactor some non-parameterised queries can feel like a waste of time. However, taking the time to apply these basics early will help you avoid unnecessary risks and technical debt later. Security doesn’t have to be complex — it just needs to be part of your development process from the start so you can enjoy the vibes. ## Related Articles - [Lessons for Vibe Coders and Developers](https://www.wearedevelopers.com/magazine/614-lessons-for-vibe-coders-and-developers) - [Understanding and Mitigating Common Web Vulnerabilities](https://www.wearedevelopers.com/magazine/565-understanding-and-mitigating-common-web-vulnerabilities) - [How to Avoid Over-Engineering](https://www.wearedevelopers.com/magazine/546-how-to-avoid-over-engineering) - [Vibe coding, creativity, craft and professionalism… are we making ourselves redundant?](https://www.wearedevelopers.com/magazine/579-vibe-coding-creativity-craft-and-professionalism-are-we-making-ourselves-redundant) ## Related Videos - [10 commandments for vibe coding](https://www.wearedevelopers.com/videos/1453-10-commandments-for-vibe-coding) - [Software Security 101: Secure Coding Basics](https://www.wearedevelopers.com/videos/220-software-security-101-secure-coding-basics) - [Slopquatting, API Keys, Fun with Fonts, Recruiters vs AI and more - The Best of LIVE 2025 - Part 2](https://www.wearedevelopers.com/videos/1765-slopquatting-api-keys-fun-with-fonts-recruiters-vs-ai-and-more-the-best-of-live-2025-part-2) - [GenAI Is a Junior Dev With Root Access](https://www.wearedevelopers.com/videos/100191-genai-is-a-junior-dev-with-root-access) ## Related Jobs - [Principal Software Engineer, Identity](https://www.wearedevelopers.com/jobs/ext/1469181-principal-software-engineer-identity) at **GitHub** - [Staff Developer Advocate, GitHub Security Lab](https://www.wearedevelopers.com/jobs/ext/1921051-staff-developer-advocate-github-security-lab) at **GitHub** - [Software Engineer II, Security](https://www.wearedevelopers.com/jobs/ext/131510-software-engineer-ii-security) at **GitHub** - [Senior Software Engineer](https://www.wearedevelopers.com/jobs/ext/15942-senior-software-engineer) at **GitHub** - [Principal Software Engineer, Database Infrastructure](https://www.wearedevelopers.com/jobs/ext/1465908-principal-software-engineer-database-infrastructure) at **GitHub** - [Senior Software Engineer, Client Apps Platform](https://www.wearedevelopers.com/jobs/ext/1773893-senior-software-engineer-client-apps-platform) at **GitHub**