The OWASP Top 10 is a globally recognized standard awareness document for developers and web application security professionals. It represents a broad consensus on the most critical security risks facing web applications. Understanding and mitigating these risks is a fundamental requirement for building secure and resilient digital services.
At Code 0, we use the OWASP Top 10 as a cornerstone of our security services, helping organizations implement practical controls to protect against these prevalent threats.
A01:2021 - Broken Access Control

Broken Access Control is a critical vulnerability that occurs when restrictions on what authenticated users are allowed to do are not properly enforced. Attackers can exploit these flaws to gain unauthorized access to functionality or data, such as accessing other users' accounts, viewing sensitive files, or performing administrative functions.
Insecure Direct Object Reference (IDOR) Example
This Node.js/Express route is intended to allow an administrator to delete users. However, it only checks if a user is logged in, failing to verify if the authenticated user has the necessary administrative privileges.
// Flaw: This Node.js/Express route for an admin panel fails to check if
// req.user.isAdmin. It only checks if a user is logged in.
app.get('/admin/deleteUser', (req, res) => {
if (!req.session.user) {
return res.status(401).send('Unauthorized');
}
// Missing role check! Any authenticated user can access this.
const userIdToDelete = req.query.id;
deleteUser(userIdToDelete);
res.send(`User ${userIdToDelete} deleted.`);
});
Unauthorized Administrative Action
A regular, non-admin user who is authenticated can simply browse to the URL or use a tool like `curl` to perform administrative actions they are not authorized for. This is a classic example of an Insecure Direct Object Reference (IDOR) combined with broken function-level access control.
# A regular user with a valid session cookie can delete user 123
curl -X GET "https://example.com/admin/deleteUser?id=123" \
--cookie "session=your_valid_user_session_cookie"
Enforcing Role-Based Access Control (RBAC)
The solution is to implement a server-side check or middleware that verifies the user's role or permissions on every sensitive request. This ensures that only authorized users can perform specific actions.
// Fix: A middleware function properly checks the user's role.
const requireAdmin = (req, res, next) => {
if (req.session.user && req.session.user.role === 'admin') {
return next();
}
res.status(403).send('Forbidden: Insufficient privileges.');
};
app.get('/admin/deleteUser', requireAdmin, (req, res) => {
const userIdToDelete = req.query.id;
deleteUser(userIdToDelete);
res.send(`User ${userIdToDelete} deleted.`);
});
A02:2021 - Cryptographic Failures

This category, previously known as Sensitive Data Exposure, relates to failures in protecting data in transit and at rest. This includes using weak encryption or hashing algorithms, improper key management, or exposing sensitive data through insecure communication channels (e.g., lack of TLS). The impact of cryptographic failures can be severe, leading to data breaches, identity theft, and regulatory non-compliance.
Weak Hashing and Insecure Data Storage
Consider a scenario where user passwords are hashed using an outdated, fast hashing algorithm like MD5 or SHA-1, and stored directly in a database. Additionally, sensitive user data might be stored without encryption.
// Flaw: Storing passwords with weak hashing (MD5)
$password = "user_password_123";
$hashedPassword = md5($password);
$sensitiveData = "CreditCardNumber: 1234-5678-9012-3456";
// Storing directly in database
// INSERT INTO users (username, password_hash, sensitive_info)
// VALUES ('testuser', '$hashedPassword', '$sensitiveData');
Offline Brute-Forcing and Data Exposure
If an attacker gains access to the database, they can easily crack the MD5 hashes using rainbow tables or brute-force attacks due to the algorithm's speed and known weaknesses. The unencrypted sensitive data is immediately exposed.
# Attacker uses hashcat to crack MD5 hashes
hashcat -m 0 hashes.txt wordlist.txt
# Result: Passwords recovered, sensitive data read directly.
Strong Cryptography and Secure Key Management
The fix is always to use strong, industry-standard, and up-to-date cryptographic algorithms (like AES-256 for encryption and Argon2, bcrypt, or scrypt for password hashing). Crucially, enforce TLS 1.2 or higher everywhere for data in transit, and implement robust key management practices for data at rest.
// Fix: Using a strong, modern password hashing algorithm
$password = "user_password_123";
$hashedPassword = password_hash($password, PASSWORD_ARGON2ID);
// Encrypt sensitive data before storage
$sensitiveData = "CreditCardNumber: 1234-5678-9012-3456";
$encryptedData = openssl_encrypt($sensitiveData, 'aes-256-cbc',
$encryptionKey, 0, $iv);
// Store hashed password and encrypted data
// INSERT INTO users (username, password_hash, encrypted_info)
// VALUES ('testuser', '$hashedPassword', '$encryptedData');
A03:2021 - Injection

Injection flaws occur when untrusted data is sent to an interpreter as part of a command or query. This can lead to the interpreter executing unintended commands or accessing data without proper authorization. This category includes SQL Injection, NoSQL Injection, OS Command Injection, LDAP Injection, and more.
Unsanitized User Input Leading to OS Command Injection
This PHP script uses `shell_exec()` to run the `ping` command, directly concatenating user-supplied input (`$_GET['host']`) without proper sanitization. This creates a critical vulnerability where an attacker can inject arbitrary operating system commands.
// Flaw: This script uses shell_exec() with user input.
// The input is not sanitized, allowing command injection.
$host = $_GET['host'];
$output = shell_exec("ping -c 1 " . $host);
echo "$output
";
Chaining Commands
An attacker can append a semicolon (`;`) or other command separators to the input, allowing them to chain a new command that will be executed by the server's operating system. In this example, the attacker forces the server to execute the `whoami` command.
# The server will execute 'ping -c 1 8.8.8.8' AND 'whoami'.
curl "http://example.com/ping.php?host=8.8.8.8; whoami"
# The server's response will be the ping output,
# followed by 'www-data'
Input Validation and Safe API Usage
The best fix for injection flaws is to avoid calling the OS shell or database directly with user input. Instead, use safe APIs that parameterize queries or functions that strictly validate and sanitize input. If shell execution is absolutely necessary, use functions that safely escape shell arguments.
// Fix: Use escapeshellarg() to treat the input as a single,
// safe argument. This prevents command chaining.
$host = $_GET['host'];
$output = shell_exec("ping -c 1 " . escapeshellarg($host));
echo "$output
";
// Better: Avoid shell_exec. Use a native PHP function.
// For SQL Injection, use prepared statements.
A04:2021 - Insecure Design

Insecure Design is a new category representing weaknesses related to design and architectural flaws. It emphasizes that security must be integrated into the software development lifecycle from the very beginning, rather than being an afterthought. This category highlights the importance of threat modeling and secure design patterns.
Lack of Threat Modeling and Secure Design Patterns
An application designed without considering potential threats can be inherently vulnerable. For example, a password reset mechanism that relies solely on a user-supplied email address without multi-factor verification or rate limiting is an insecure design.
Exploiting Design Flaws
Attackers can exploit these design flaws by understanding the application's logic and identifying weak points. In the password reset example, an attacker could initiate numerous password resets, potentially leading to account takeover through brute-force or social engineering if the design doesn't adequately protect against such attacks.
Integrating Security into Design
Addressing Insecure Design requires a cultural shift towards "Security by Design" and "Privacy by Design." This involves: Systematically identifying potential threats and vulnerabilities early in the design phase (e.g., using STRIDE or DREAD methodologies); Implementing established secure design patterns and architectural principles; and Conducting regular security reviews of the application's architecture and design.
A05:2021 - Security Misconfiguration

Security Misconfiguration is a very common vulnerability, often the result of insecure default configurations, incomplete or ad hoc configurations, open cloud storage, misconfigured HTTP headers, or verbose error messages containing sensitive information. It can occur at any level of the application stack.
Verbose Error Messages Exposing Sensitive Information
Consider a web application that, when encountering an error, displays a detailed stack trace or internal error message directly to the user. This can inadvertently reveal sensitive information about the application's internal structure, database schema, or server environment.
// Flaw: A script that outputs the full error message.
try {
$conn = new PDO("mysql:host=localhost;dbname=nonexistent_db",
"root", "wrong_password");
} catch (PDOException $e) {
// Insecure: Directly exposing database connection errors
echo "Database Error: " . $e->getMessage();
}
Information Gathering for Further Attacks
An attacker can intentionally trigger errors to gather information. A detailed error message might reveal the database type and version, file paths, or even credentials, which can then be used to craft more targeted exploits.
# Example of a verbose error message
Database Error: SQLSTATE[HY000] [2002] php_network_getaddresses:
getaddrinfo for nonexistent_db failed: Name or service not known
# This tells the attacker:
# 1. The application uses MySQL.
# 2. The database host is 'localhost'.
Secure Configuration and Custom Error Handling
The fix involves a rigorous hardening process for all parts of the application stack. This includes changing default passwords, running with minimum privileges, keeping software updated, and implementing custom, generic error pages that do not reveal internal system details.
// Fix: Implement custom error handling that logs details
// but shows a generic message to the user.
try {
$conn = new PDO("mysql:host=localhost;dbname=nonexistent_db",
"root", "wrong_password");
} catch (PDOException $e) {
// Secure: Log the detailed error for administrators
error_log("Database connection failed: " . $e->getMessage());
// Display a generic, user-friendly error message
http_response_code(500);
echo "An unexpected error occurred. Please try again later.";
}
A06:2021 - Vulnerable and Outdated Components

This vulnerability highlights the risk of relying on libraries, frameworks, and other software components that have known security flaws. As modern applications heavily rely on third-party components, managing their security posture is critical. Attackers frequently exploit publicly known vulnerabilities in these components.
Unpatched Vulnerabilities in Third-Party Libraries
Consider a web application using an older version of a popular JavaScript library or a server-side framework that contains a publicly disclosed vulnerability (CVE). If the application is not regularly updated or scanned for such issues, it remains exposed.
{
"name": "frontend-app",
"version": "1.0.0",
"dependencies": {
"jquery": "3.3.1" // Known XSS vulnerabilities in older versions
}
}
Leveraging Publicly Available Exploits
Attackers can easily find and use publicly available exploits for known vulnerabilities in outdated components. For instance, if a web server uses an old version of Apache Struts with a Remote Code Execution (RCE) vulnerability, an attacker can execute arbitrary commands on the server.
Continuous Component Management
The fix involves a proactive and continuous approach to managing software components. This includes inventory management, automated scanning (SCA) in CI/CD pipelines, regular updates, vulnerability monitoring, and maintaining a Software Bill of Materials (SBOM).
# Fix: Developers should regularly run audit tools to find and fix vulnerable dependencies.
# For Node.js projects:
npm audit
# Running 'npm audit fix' can automatically update many of the vulnerable packages to safe versions.
npm audit fix
A07:2021 - Identification and Authentication Failures

This category encompasses weaknesses in session management, credential handling, and authentication processes. It includes issues like weak password policies, lack of multi-factor authentication (MFA), insecure session IDs, and improper handling of credential recovery mechanisms.
Weak Password Policy and Lack of MFA
Many applications still allow weak, easily guessable passwords and do not enforce Multi-Factor Authentication (MFA). This makes accounts highly susceptible to brute-force attacks, credential stuffing, or simple guessing.
Brute-Force and Credential Stuffing
Attackers can use automated tools to rapidly guess passwords (brute-force) or use lists of compromised credentials from other breaches (credential stuffing) to gain unauthorized access to user accounts. Without MFA, a stolen or guessed password is often all an attacker needs.
# Example: Brute-forcing a login form with Hydra
hydra -L users.txt -P passwords.txt example.com http-post-form \
"/login.php:username=^USER^&password=^PASS^:Login Failed"
Robust Authentication Mechanisms
Implementing robust authentication mechanisms is crucial. This includes: strong password policies, Multi-Factor Authentication (MFA), secure session management, account lockout mechanisms, and storing passwords using strong, slow hashing algorithms (Argon2, bcrypt, scrypt).
A08:2021 - Software and Data Integrity Failures

This modern vulnerability relates to failures in protecting against integrity violations, especially within CI/CD pipelines, software supply chains, and critical data. It includes insecure deserialization and relying on dependencies without verifying their integrity.
Vulnerable Dependencies in the Software Supply Chain
A common and increasingly exploited flaw is the use of components with known vulnerabilities. A `package.json` file with a dependency pinned to a known vulnerable version is a prime example. Attackers actively scan public repositories for projects using these vulnerable dependencies.
{
"name": "vulnerable-app",
"version": "1.0.0",
"dependencies": {
"express": "4.17.0",
"lodash": "4.17.15"
}
}
Leveraging Publicly Known Vulnerabilities
An attacker doesn't need to attack the target directly. They can scan public repositories for projects using vulnerable dependencies and then use known public exploits against any server running that code. This is a supply chain attack, where the vulnerability is introduced indirectly.
Automated Dependency Scanning and SBOM
The fix is to implement automated tooling within the CI/CD pipelines to continuously check for vulnerable dependencies. Tools like `npm audit`, `pip-audit`, GitHub's Dependabot, Snyk, or OWASP Dependency-Check are essential. Furthermore, maintaining a Software Bill of Materials (SBOM) helps track all components.
# Fix: Developers should regularly run audit tools.
# For Node.js projects:
npm audit
# 'npm audit fix' can automatically update many vulnerable packages.
npm audit fix
# For Python projects:
pip install pip-audit
pip-audit -r requirements.txt
A09:2021 - Security Logging and Monitoring Failures

This category highlights the critical importance of effective logging and monitoring for detecting, escalating, and recovering from security incidents. Without sufficient logging and monitoring, security incidents can go undetected for extended periods, leading to greater damage.
Insufficient Logging and Alerting
Many applications and systems either do not generate sufficient security-relevant logs, or these logs are not properly collected, stored, analyzed, or monitored. For example, failed login attempts might not be logged, or critical security alerts might not trigger notifications to the security team.
Undetected Attacks and Persistence
Attackers thrive in environments with poor logging and monitoring. They can exploit vulnerabilities, gain access, and maintain persistence for extended periods without being detected. This allows them to exfiltrate data, deploy ransomware, or cause significant damage before any alarm is raised.
Comprehensive Logging, Centralized Monitoring, and Alerting
Addressing this vulnerability requires a holistic approach to security operations: comprehensive logging of all security-relevant events, a centralized SIEM (e.g., Splunk, Elastic Stack, Wazuh) for log management, proactive monitoring and alerting for suspicious activities, regular log reviews, and tight integration with the incident response process.
A10:2021 - Server-Side Request Forgery (SSRF)

Server-Side Request Forgery (SSRF) flaws occur when a web application fetches a remote resource without validating the user-supplied URL. This allows an attacker to coerce the server into making requests to an arbitrary domain of the attacker's choosing, potentially accessing internal, protected resources.
Unvalidated URL Input
Consider a web application that allows users to provide a URL for fetching an image or a file. If the application does not properly validate or sanitize this URL input, an attacker can manipulate it to point to internal network resources.
// Flaw: PHP script fetching content from a user-supplied URL without validation
$url = $_GET['url'];
$content = file_get_contents($url); // This function will fetch content from any URL
echo $content;
Accessing Internal Resources
An attacker can craft a malicious URL that, when processed by the vulnerable server, causes the server to make a request to an internal IP address or a local service. This can be used to scan internal networks or access sensitive internal APIs.
# Make the server request its own metadata endpoint
curl "http://example.com/fetch.php?url=http://169.254.169.254/latest/meta-data/"
# Scan internal ports
curl "http://example.com/fetch.php?url=http://192.168.1.1:8080/"
Strict URL Validation and Whitelisting
The primary defense against SSRF is strict validation of user-supplied URLs. This involves whitelisting allowed domains, parsing URL components to ensure the host is a legitimate external domain, disabling redirects, and implementing network segmentation.
// Fix: PHP script with strict URL validation (simplified example)
$allowed_domains = ['example.com', 'api.external.com'];
$url = $_GET['url'];
$parsed_url = parse_url($url);
if (isset($parsed_url['host']) && in_array($parsed_url['host'], $allowed_domains)) {
$content = file_get_contents($url);
echo $content;
} else {
http_response_code(400);
echo "Error: Invalid URL provided.";
}