Live

Veld running on
veld-ai/sample

These are real catches from the review engine โ€” every finding is linked to the actual commit and verifiable on GitHub.

auto-updates on every push 7 findings github.com/veld-ai/sample โ†—
CRITICAL ๐Ÿค– semantic middleware/auth.js :8

JWT secret falls back to hardcoded default

middleware/auth.js
8 - const JWT_SECRET = process.env.JWT_SECRET || 'changeme';
Veld ยท Review Comment

process.env.JWT_SECRET || "changeme" means any deployment that forgets to set the env var silently uses a public, predictable secret. An attacker who knows this default can forge valid tokens for any user ID. Remove the fallback entirely โ€” fail fast on startup if JWT_SECRET is missing.

Fix: Replace with: if (!process.env.JWT_SECRET) throw new Error("JWT_SECRET env var required"); const JWT_SECRET = process.env.JWT_SECRET;

HIGH ๐Ÿ”Ž pattern middleware/auth.js :8

Hardcoded Credentials

middleware/auth.js
8 - const JWT_SECRET = process.env.JWT_SECRET || 'changeme';
Veld ยท Review Comment

Potential hardcoded password, API key, or secret found in code. The string "changeme" is a well-known default that will end up in version control and any CI logs.

HIGH ๐Ÿ”Ž pattern
PR #12 โ€” feat: add search endpoint for user lookup @b2c3d4e
routes/search.js :14

SQL Injection Risk

routes/search.js
14 - const rows = await db.query(`SELECT * FROM users WHERE name ILIKE '%${q}%'`);
Veld ยท Review Comment

Template literal used in SQL query construction. User-controlled input in search query is interpolated directly. Send a single quote or UNION SELECT and you own the table.

Fix: Use parameterized queries: db.query("SELECT * FROM users WHERE name ILIKE $1", [`%${q}%`])

MEDIUM ๐Ÿค– semantic
PR #12 โ€” feat: add search endpoint for user lookup @b2c3d4e
routes/search.js

Missing rate limiting on search endpoint

Veld ยท Review Comment

The search route has no rate limiting. A script can enumerate all users by cycling through single-character queries. Even if SQL injection is fixed, unrestricted search is a data-exfiltration vector. Add express-rate-limit or a per-IP throttle.

Fix: Wrap router with: const rateLimit = require("express-rate-limit"); router.use(rateLimit({ windowMs: 60_000, max: 30 }));

CRITICAL ๐Ÿค– semantic
PR #17 โ€” feat: wallet withdrawal endpoint @c3d4e5f
services/wallet.js :32

TOCTOU race condition in balance check

services/wallet.js
32 - const balance = await getBalance(userId);
Veld ยท Review Comment

Balance is read, then checked, then debited in three separate operations. Two concurrent withdrawal requests both read the same balance, both pass the check, and both debit โ€” spending funds twice. Collapse into a single atomic UPDATE ... WHERE balance >= amount RETURNING balance to make double-spend structurally impossible.

Fix: const { rows } = await db.query("UPDATE wallets SET balance = balance - $2 WHERE id = $1 AND balance >= $2 RETURNING balance", [userId, amount]); if (!rows.length) throw new InsufficientFundsError();

HIGH ๐Ÿค– semantic controllers/auth.js :58

Unhandled rejection silently swallows email failures

controllers/auth.js
58 - sendWelcomeEmail(user);
Veld ยท Review Comment

sendWelcomeEmail() is called with no await and no .catch(). If the SMTP call throws โ€” rate limit, bad credentials, DNS failure โ€” the error vanishes. The caller has no idea delivery failed, no retry is scheduled, and the user never gets the email. Either await it inside a try/catch or attach a .catch() that logs and enqueues a retry.

Fix: sendWelcomeEmail(user).catch(err => { logger.error("Welcome email failed", { userId: user.id, err }); retryQueue.add({ type: "welcome_email", userId: user.id }); });

MEDIUM ๐Ÿค– semantic
PR #23 โ€” feat: order checkout flow @e5f6a1b
routes/checkout.js :24

Pricing and tax logic embedded in HTTP controller

Veld ยท Review Comment

Tax calculation, discount application, and order-limit enforcement all live in the Express handler. This logic cannot be unit tested without spinning up the HTTP layer, and it cannot be reused from a background job or admin CLI. Controllers should translate HTTP into service calls โ€” nothing more. Move the business rules into an OrderService.

Fix: const order = await OrderService.create({ userId, items, couponCode }); res.json({ orderId: order.id, total: order.total });

Put Veld on your repo

2 minutes to connect. Catches appear on the next push.

Install on a repo โ†’