real catches

Bugs Veld caught
this week.

Not demos. Not toy examples. This is what the engine flags in real codebases — with the diff, the explanation, and the fix. Want this on yours? Install Veld →

Want to see Veld running live on a real repo? Live demo →

Security Race Condition Auth Logic Architecture
JavaScript Security CRITICAL db/user-queries.js

SQL injection via raw string interpolation

db/user-queries.js
14 async function getUserByEmail(email) {
15 const db = getConnection();
16 - const q = `SELECT * FROM users WHERE email = '${email}'`;
17 - return db.query(q);
16 + return db.query(
17 + "SELECT * FROM users WHERE email = $1",
18 + [email]
19 + );
20 }
Veld · Review Comment

Veld flagged this. User-controlled input is concatenated directly into a SQL string. An attacker sends `' OR 1=1 --` and reads every row. Parameterized queries make injection structurally impossible — the driver handles escaping, not your code.

* Illustrative example — mirrors the v2 engine output format.
TypeScript Race Condition HIGH handlers/payment.ts

TOCTOU race in balance check

handlers/payment.ts
31 async function processPayment(userId, amount) {
32 - const balance = await getBalance(userId);
33 - if (balance < amount) throw new Error("Insufficient funds");
34 - await deductBalance(userId, amount);
32 + const updated = await db.query(
33 + `UPDATE accounts SET balance = balance - $2
34 + WHERE id = $1 AND balance >= $2
35 + RETURNING balance`, [userId, amount]);
36 + if (!updated.rows.length) throw new Error("Insufficient funds");
37 }
Veld · Review Comment

Veld flagged this. Two concurrent requests both pass the balance check before either deduction runs. Result: funds spent twice. The fix collapses read-check-write into a single atomic UPDATE with a WHERE guard — no window for a second request to slip through.

* Illustrative example — mirrors the v2 engine output format.
JavaScript Auth CRITICAL routes/admin.js

Admin route missing authentication middleware

routes/admin.js
08 const router = express.Router();
09
10 - router.get("/users", async (req, res) => {
10 + router.get("/users", requireAdmin, async (req, res) => {
11 const users = await db.getAllUsers();
12 res.json(users);
13 });
Veld · Review Comment

Veld flagged this. `GET /admin/users` returned the full user table — no session check, no role check, nothing. The `requireAdmin` middleware already existed in the codebase. It just wasn't applied here. One line, full data exposure closed.

* Illustrative example — mirrors the v2 engine output format.
Python Logic MEDIUM api/pagination.py

Off-by-one drops last page of results

api/pagination.py
22 def get_page(items, page, page_size):
23 total = len(items)
24 - total_pages = total // page_size
24 + total_pages = math.ceil(total / page_size)
25 start = (page - 1) * page_size
26 return items[start:start + page_size]
Veld · Review Comment

Veld flagged this. With 25 items and page_size=10, `25 // 10` returns 2 — the third page silently vanishes. Any list whose length isn't a clean multiple loses its tail. `ceil` fixes it in one character.

* Illustrative example — mirrors the v2 engine output format.
JavaScript Security CRITICAL config/database.js

Hardcoded credentials committed to repo

config/database.js
03 module.exports = {
04 - host: "prod-db.internal",
05 - password: "Pr0d$ecretP@ssw0rd!",
06 - database: "app_production",
04 + host: process.env.DB_HOST,
05 + password: process.env.DB_PASSWORD,
06 + database: process.env.DB_NAME,
07 };
Veld · Review Comment

Veld flagged this. Production credentials in source = credentials in every clone, fork, and CI log. Rotate immediately, then use environment variables. Git history will still contain the old value — consider that credential compromised regardless.

* Illustrative example — mirrors the v2 engine output format.
TypeScript Architecture MEDIUM controllers/order.ts

Business logic embedded in HTTP controller

controllers/order.ts
19 export async function createOrder(req, res) {
20 const { userId, items } = req.body;
21 - const total = items.reduce((s, i) => s + i.price * i.qty, 0);
22 - if (total > 10000) throw new Error("Order exceeds limit");
23 - const tax = total * 0.08;
24 - await db.insertOrder({ userId, items, total, tax });
21 + const order = await orderService.create({ userId, items });
22 res.json({ orderId: order.id });
23 }
Veld · Review Comment

Veld flagged this. Pricing, tax calculation, and order limits live inside the HTTP handler. That logic can't be tested without spinning up Express, and it can't be reused from a background job or CLI. Controllers translate HTTP — that's it. Move the business rules into a service layer.

* Illustrative example — mirrors the v2 engine output format.

Want this on your repo?

Set up takes under 2 minutes. No Slack message required.

Install on a repo →