Yevhen Klymentiev
dark
light
console
darkness
y.klymentiev@gmail.com
Coding Standards|Rules, conventions, and best practices I follow and recommend to teams

Security

Follow secure coding practices to protect applications from common vulnerabilities and attacks.

This includes input validation, authentication, access control, safe use of third-party dependencies, and secure handling of sensitive data. A secure codebase protects both users and business integrity.

Avoid storing sensitive data in plaintext

Never store passwords, tokens, or other sensitive user data in plaintext. Always hash passwords (e.g., using bcrypt, argon2), encrypt sensitive fields, and avoid logging sensitive values in error traces or logs.

JavaScript
Copied!
1const hashed = await bcrypt.hash(user.password, 10);
2db.insert({ ...user, password: hashed });

Escape and encode user input

Escape input before outputting it into HTML, attributes, URLs, or query strings to prevent injection attacks. Use well-tested libraries like DOMPurify, xss, or encodeURIComponent as appropriate for the context.

JavaScript
Copied!
1const cleanComment = xss(req.body.comment);
2res.send(`<p>${cleanComment}</p>`);

Never trust the client

Client-side logic and validation can be bypassed. Always revalidate and sanitize everything on the server, regardless of front-end checks. This is essential to maintain integrity and security.

Set secure HTTP headers

Configure secure HTTP headers to reduce attack surfaces. Use libraries like helmet (Express) or equivalent frameworks for Next.js, Fastify, etc.

Recommended headers include:

JavaScript
Copied!
1import helmet from "helmet";
2app.use(helmet());

Implement proper CORS policies

Don't allow unrestricted CORS. Always specify allowed origins and methods. Avoid setting Access-Control-Allow-Origin: * unless strictly necessary and safe (e.g. for public GET-only APIs).

JavaScript
Copied!
app.use(cors()); // Default: allows everything
JavaScript
Copied!
1app.use(cors({
2  origin: "https://myapp.com",
3  methods: ["GET", "POST"]
4}));

Set the appropriate flags on cookies to prevent session hijacking or cross-site attacks:

  • HttpOnly: Prevents access via JS

  • Secure: Only over HTTPS

  • SameSite: Controls cross-origin sending

JavaScript
Copied!
1res.cookie("token", token, {
2  httpOnly: true,
3  secure: true,
4  sameSite: "strict"
5});

Protect against CSRF attacks

Use anti-CSRF tokens for any state-changing requests (POST, PUT, DELETE) — especially when using cookies for authentication. Also consider setting SameSite cookie flag where possible.

JavaScript
Copied!
1// Express + csurf
2import csurf from "csurf";
3app.use(csurf({ cookie: true }));

Use rate limiting and throttling

Protect routes from abuse or brute-force attempts with IP- or token-based rate limiting. Especially important for auth, registration, and public APIs.

JavaScript
Copied!
1import rateLimit from "express-rate-limit";
2const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100 });
3app.use(limiter);

Avoid information leakage

Don’t expose stack traces, internal errors, environment variables, or implementation details to clients. Log detailed errors on the server, but return only minimal error messages to the client.

JavaScript
Copied!
res.status(500).json({ error: err }); // Leaks internal structure
JavaScript
Copied!
1res.status(500).json({ error: "Something went wrong." });
2log.error(err); // Safe internal logging

Keep dependencies up to date

Regularly update third-party packages and monitor them for known vulnerabilities. Use tools like npm audit, yarn audit, or GitHub's Dependabot to stay informed. Outdated packages are a major source of exploits.

  • Enable auto-security updates

  • Review changelog before major bumps

  • Lock down versions for reproducibility

Avoid using 'eval', 'new Function', or unsafe 'Regex'

Avoid using eval, Function, or dynamic code execution — they expose your app to injection risks. Similarly, use ReDoS-safe regular expressions and validate untrusted patterns.

JavaScript
Copied!
eval(userInput); // Vulnerable to injection
JavaScript
Copied!
const safeOptions = JSON.parse(input); // Safe if schema-validated

Use parameterized queries to prevent injection

Never build SQL or NoSQL queries via string interpolation. Always use parameterized statements or query builders (e.g., Prisma, Knex, Mongoose) to prevent injection attacks.

JavaScript
Copied!
const result = db.query(`SELECT * FROM users WHERE name = '${name}'`);
JavaScript
Copied!
const result = db.query("SELECT * FROM users WHERE name = $1", [name]);

Secure secrets and configuration

Never hardcode secrets, tokens, API keys, or credentials in your codebase. Use environment variables or a secure secrets manager (e.g., Vault, AWS Secrets Manager, Doppler). Limit access based on roles or environments.

JavaScript
Copied!
const jwtSecret = "supersecret123"; // hardcoded
JavaScript
Copied!
const jwtSecret = process.env.JWT_SECRET;

Validate file uploads and limit size/type

Check file type (MIME & extension), limit upload size, and store files securely (e.g., not publicly accessible without auth). Always assume uploads may be malicious.

JavaScript
Copied!
1upload.single("avatar", {
2  limits: { fileSize: 5 * 1024 * 1024 },
3  fileFilter: (req, file, cb) => {
4    if (!["image/png", "image/jpeg"].includes(file.mimetype)) {
5      return cb(new Error("Unsupported file type"));
6    }
7    cb(null, true);
8  },
9});

Log security events separately

Track security-related events (e.g., failed logins, permission denials, rate-limit hits) in dedicated logs. These should be tamper-proof and monitored regularly for suspicious patterns.

Note: Avoid logging sensitive payloads (like full auth headers or tokens).

JavaScript
Copied!
logger.security.warn("Failed login for userId: %s", userId);
Styleguide: Security | Yevhen Klymentiev