Protecting web applications from cyber attacks has moved from a secondary concern to a fundamental requirement for any software project. In 2025, OWASP updated its famous Top 10 list, including two new risk categories and consolidating others, showing that the threat landscape is constantly evolving. If you develop or maintain any internet-facing system, you need to understand these vulnerabilities and, more importantly, know how to defend against them in practice.
I have been working with web development for over 8 years, and during that time, I have seen applications get compromised by flaws that seemed trivial — a form field without sanitization, an API route without proper authentication, a forgotten security header. The worst part is that most of these breaches could have been prevented with basic practices that many teams simply ignore due to rushing or lack of awareness. Over the past two years, I have adopted a security checklist for all projects, and the difference in code quality and confidence is remarkable.
What Changed in OWASP Top 10:2025
The OWASP Top 10:2025 analyzed over 175,000 CVE records to determine the most critical risks. The list brought significant changes compared to the 2021 edition, reflecting how attacks adapt to new technologies and development practices.
The main novelty is the inclusion of two unprecedented categories: Software Supply Chain Failures (A03), which addresses risks in the software supply chain — such as compromised dependencies and malicious packages on npm or PyPI —, and Mishandling of Exceptional Conditions (A10), which focuses on unsafe error handling, unexpected logical conditions, and failure scenarios that open gaps. Additionally, Server-Side Request Forgery (SSRF) was consolidated within Broken Access Control (A01), which maintained its position as the number one risk.
Security Misconfiguration rose from fifth to second position, affecting approximately 3% of tested applications. This includes everything from excessive permissions on cloud storage buckets to missing HTTP headers and insecure default configurations in frameworks. It is a clear warning: writing secure code is not enough — infrastructure and configuration must keep up.
| Position 2025 | Category | Change vs 2021 |
|---|---|---|
| A01 | Broken Access Control | Maintained #1 (absorbed SSRF) |
| A02 | Security Misconfiguration | Rose from #5 |
| A03 | Software Supply Chain Failures | New category |
| A04 | Cryptographic Failures | Dropped from #2 |
| A05 | Injection | Dropped from #3 |
| A06 | Insecure Design | Dropped from #4 |
| A07 | Authentication Failures | Maintained position |
| A08 | Software and Data Integrity Failures | Maintained position |
| A09 | Security Logging and Monitoring Failures | Maintained position |
| A10 | Mishandling of Exceptional Conditions | New category |
Broken Access Control: The Number One Risk
Broken Access Control continues to be the most prevalent vulnerability, with an average of 3.73% of tested applications presenting at least one flaw in this category. The problem occurs when a user can access resources or perform actions for which they do not have permission — and this is more common than it seems.
In practice, this includes scenarios such as: URL ID manipulation to access other users' data (IDOR), API endpoints that do not validate the user's role, privilege escalation due to lack of backend verification, and direct access to administrative pages without authentication. The consolidation of SSRF into this category reinforces the severity: an attacker can make the server send internal requests, accessing services that should not be exposed.
How to Mitigate
- Deny by default: every route and resource should be inaccessible until explicit permission is granted. Never assume the frontend protects access.
- Validate on the backend: all authorization checks should happen on the server. Client-side checks are complementary, not substitutes.
- Use Role-Based Access Control (RBAC): define clear roles and associate granular permissions to each one.
- Test with automated tools: use scanners like OWASP ZAP or Burp Suite to identify access control flaws in routes and endpoints.
- Log and monitor: every unauthorized access attempt should generate an alert log for later analysis.
Injection and XSS: Persistent Old Acquaintances
Despite modern frameworks offering native protection against many types of injection, these vulnerabilities remain in the Top 10 (now at A05). SQL Injection, NoSQL Injection, Command Injection, and Cross-Site Scripting (XSS) still affect thousands of applications, especially those that concatenate user input directly into queries or templates.
XSS, in particular, continues to be exploited in applications that render dynamic HTML without escaping special characters. Stored XSS attacks can compromise every user who accesses an affected page, allowing session cookie theft, redirection to malicious sites, and arbitrary JavaScript execution in the victim's browser.
Practical Defenses Against Injection
- Use parameterized queries: never concatenate variables directly into SQL. Use prepared statements or ORMs that do this automatically.
- Sanitize and validate inputs: all user input should be validated on the server for expected type, size, and format. Reject what does not fit.
- Escape output: when rendering data in HTML, use the framework's escape functions (React does this by default with JSX, but
dangerouslySetInnerHTMLnullifies the protection). - Implement Content Security Policy (CSP): the
Content-Security-Policyheader limits where scripts can be loaded from, blocking injected code execution. - Use sanitization libraries: for cases where user HTML is allowed (rich text editors), use libraries like DOMPurify to clean content before rendering.
Web Application Firewall: The Extra Layer of Protection
A Web Application Firewall (WAF) works as a shield between the internet and your application, filtering and monitoring HTTP traffic to block known attacks before they reach your code. According to the OWASP documentation on WAFs, this layer is especially useful for protecting against SQL injection, XSS, and known vulnerability exploitation attempts.
In 2026, the best WAF solutions combine two security models: the negative model (blacklisting), which blocks what is known to be malicious, and the positive model (whitelisting), which allows only what is explicitly valid. The combination of managed rules with custom rules specific to your application offers the best balance between security and usability.
WAF Best Practices
- Virtual Patching: when a code vulnerability is discovered and the fix has not been implemented yet, the WAF can block exploitation attempts directly, buying time for the development team.
- Rate Limiting: configure request limits per IP for sensitive endpoints (login, password reset, data APIs), mitigating brute force attacks and application-layer DDoS.
- Continuous tuning: a poorly configured WAF can block legitimate requests. Regularly review blocking logs and adjust rules to minimize false positives without compromising security.
- Infrastructure as code: configure the WAF using tools like Terraform or Ansible to ensure rules are versioned, auditable, and replicable across environments.
Services like Cloudflare WAF offer free plans that include basic protection against common attacks, making this layer accessible even for smaller projects.
Authentication and Session Management
Authentication Failures (A07) covers issues such as weak passwords being allowed, lack of multi-factor authentication (MFA), predictable session tokens, and flaws in password recovery flows. The good news is that the growing use of standardized authentication frameworks (such as NextAuth, Auth0, Clerk, and Supabase Auth) has reduced the incidence of these failures — but only when properly configured.
- Implement MFA: multi-factor authentication should be mandatory for administrative accounts and available for all users. TOTP (Google Authenticator) and WebAuthn (security keys) are the most secure options.
- Manage sessions properly: tokens should be generated with sufficient cryptographic entropy, have a defined expiration time, and be invalidated on logout. Use cookies with
HttpOnly,Secure, andSameSite=Strictflags. - Limit login attempts: implement temporary lockout or CAPTCHA after a defined number of failed attempts to prevent brute force attacks.
- Protect the recovery flow: password reset links should be single-use, have short expiration (maximum 1 hour), and not reveal whether the email exists in the database.
HTTP Security Headers: Free and Underutilized Protection
One of the simplest and most effective ways to protect a web application is to properly configure HTTP security headers. Many developers simply do not know they exist or underestimate their impact. According to MDN Web Docs on web security, these headers provide a defense layer with zero performance impact.
| Header | Purpose | Recommended Value |
|---|---|---|
| Content-Security-Policy | Controls script, style, and resource origins | Restrictive, app-specific |
| Strict-Transport-Security | Forces HTTPS on all requests | max-age=31536000; includeSubDomains |
| X-Content-Type-Options | Prevents MIME type sniffing | nosniff |
| X-Frame-Options | Prevents clickjacking | DENY or SAMEORIGIN |
| Referrer-Policy | Controls information sent in Referer | strict-origin-when-cross-origin |
| Permissions-Policy | Restricts access to browser APIs | camera=(), microphone=(), geolocation=() |
In frameworks like Next.js, these headers can be configured in next.config.js or in middleware. In Express applications, the helmet package configures most of them with a single line of code. There is no excuse not to implement them.
Supply Chain Security: The New Attack Vector
The inclusion of Software Supply Chain Failures as A03 in the OWASP Top 10:2025 reflects a concerning reality: software supply chain attacks have exploded in recent years. Malicious packages on npm, PyPI, and other registries, compromised dependencies, and even tampered CI/CD plugins represent an attack vector that many teams overlook.
According to the GitLab blog about OWASP 2025 changes, this category encompasses everything from using dependencies with known vulnerabilities to the lack of integrity verification in build pipelines. Blind trust in third-party packages is, in itself, a vulnerability.
Protection Measures
- Audit dependencies regularly: use
npm audit,pip audit, orsnykto identify known vulnerabilities in your dependencies. - Pin versions: use lockfiles (
package-lock.json,poetry.lock) and avoid open ranges like^or~in production. - Verify integrity: enable
npm config set audit-level=highand block installations that fail integrity checks. - Review new dependencies: before adding a package, check its download count, maintainers, last update, and whether it has open security issues.
- Use Software Bill of Materials (SBOM): generate and maintain an updated inventory of all dependencies and their versions for traceability.
Monitoring and Incident Response
Security Logging and Monitoring Failures (A09) addresses the capability — or lack thereof — to detect and respond to ongoing attacks. Without adequate logs and real-time monitoring, an application can be under attack for weeks before anyone notices. And by the time they do, the data has already been exfiltrated.
- Log security events: logins, authentication failures, unauthorized access attempts, permission changes, and administrative operations should generate structured logs.
- Centralize logs: use tools like ELK Stack, Grafana Loki, or Datadog to aggregate logs from all services in a single searchable location.
- Configure alerts: define thresholds for suspicious events — multiple failed login attempts from the same IP, access to administrative routes from unknown IPs, abnormal request spikes.
- Have a response plan: document the procedure to follow when an incident is detected: who is notified, how the attack is contained, how communication is handled, and how recovery proceeds.
- Test your detection: periodically simulate controlled attacks to verify whether your monitoring and alerting systems work as expected.
Practical Security Checklist For Your Project
I have compiled a checklist based on what I apply in my own projects that covers the most common vulnerabilities from the OWASP Top 10:2025. It is not exhaustive, but it covers the basics that every web project should have before going to production:
- All routes and endpoints have authorization verification on the backend
- User inputs are validated and sanitized on the server
- Database queries use prepared statements or ORM with parameterization
- HTTP security headers are configured (CSP, HSTS, X-Frame-Options, etc.)
- Multi-factor authentication is available and active for admin accounts
- Sessions have defined expiration and are invalidated on logout
- Dependencies have been audited and lockfiles are committed
- WAF or rate limiting is configured for sensitive endpoints
- Security logs are generated and centralized
- Automatic alerts are configured for suspicious events
- HTTPS is enforced on all connections (HSTS enabled)
- Sensitive data is encrypted at rest and in transit (AES-256 / TLS 1.3)
- Backups are performed regularly and tested for restoration
- Automated security tests run in the CI/CD pipeline
Conclusion
Protecting web applications is not a one-time event — it is a continuous process that demands constant attention to new threats and defense updates. The OWASP Top 10:2025 makes clear that, while classic vulnerabilities like injection and authentication failures persist, new vectors such as software supply chain attacks gain relevance each year. Defense in depth — multiple layers of protection instead of a single solution — remains the most effective approach. In my experience, the biggest differentiator between secure and vulnerable projects is not the sophistication of tools used, but rather the team's discipline in consistently applying basic practices. Start with the checklist, implement the simplest defenses first (headers, parameterization, basic WAF), and evolve gradually. Perfect security does not exist, but negligence is a choice.

