The 2023 edition of the CWE Top 25 Most Dangerous Software Weaknesses classification sees the same top 3 weaknesses as last year – all veterans of the list since its inception in 2009. The list is ranked according to the impact and frequency of the resulting vulnerabilities in 2021 and 2022, giving a pretty good idea of where the biggest dangers lie. We haven’t looked at the SANS/CWE Top 25 since 2021, so let’s go through the methodology, the biggest movers (spoiler: includes SQL injection), and ways to use the list in practice, especially in web security.
The full CWE database is compiled and maintained by the MITRE Corporation. The top 25 project was called the SANS/CWE Top 25 in previous years, but the involvement or name of the SANS Institute is no longer mentioned on the CWE site.
Top 10 of the CWE Top 25
- #1: Out-of-bounds Write (CWE-787, score 63.72)
- #2: Cross-site Scripting (XSS, officially Improper Neutralization of Input During Web Page Generation, CWE-79, score 45.54)
- #3: SQL Injection (officially Improper Neutralization of Special Elements used in an SQL Command, CWE-89, score 34.27)
- #4: Use After Free (CWE-416, score 16.71)
- #5: OS Command Injection (officially Improper Neutralization of Special Elements used in an OS Command, CWE-78, score 15.65)
- #6: Improper Input Validation (CWE-20, score 15.50)
- #7: Out-of-bounds Read (CWE-125, score 14.60)
- #8: Path Traversal (officially Improper Limitation of a Pathname to a Restricted Directory, CWE-22, score 14.11)
- #9: Cross-Site Request Forgery (CSRF, CWE-352, score 11.73)
- #10: Unrestricted Upload of File with Dangerous Type (CWE-434, score 10.41)
Memory management errors and web vulnerabilities top the list
The most impactful weakness by far is Out-of-bounds Write, which can allow for buffer overflows and other attacks that overwrite memory, typically to achieve code execution. While only possible in programs that use a language with direct memory management (most often C/C++), this weakness is a clear #1 both in terms of the aggregated score and prevalence in known exploited vulnerabilities (see below for the CWE Top 25 methodology). In total, five types of memory management errors have made the list, including three in the top 10.
The #2 and #3 spots are occupied by cross-site scripting (XSS) and SQL injection – two of the oldest web security flaws that are clearly not going away. In terms of scores, the top three are way ahead of anything else on the list, with SQL injection scoring 34.27 and the next weakness less than 17. Again, this indicates that reported vulnerabilities (CVEs) resulting from these flaws are both numerous and severe. There are a total of four web-specific weaknesses on the list (also CSRF and SSRF) and at least 10 other flaws that are commonly exploited in web application attacks.
Notable changes since our last look at the list in 2021 include big upward moves for several flaws typical of web applications, with SQL injection moving up from #6 to #3, server-side request forgery (SSRF) jumping five places to #19, and command injection advancing from #25 to #16 as the biggest single mover. Towards the end of the list, four CWEs have dropped off, including XML external entity injection (XXE), while four others have moved into the top 25, most notably code injection. Overall, only the ordering has changed in the top 10, indicating that very similar attack patterns are used, targeting similar weaknesses.
CWE vs. CVE – what’s the difference?
Items in the CWE database are various software and hardware weaknesses that, if implemented in production, can lead to vulnerabilities. The CVE database, on the other hand, lists known and reported vulnerabilities in specific products. A common security weakness like SQL injection (CWE-89) will be listed as the cause of hundreds of different CVEs involving an SQL injection attack (such as CVE-2023-34362 for MOVEit Transfer).
Tl;dr: CWEs are what could go wrong. CVEs are what did go wrong.
Methodology: How the CWE Top 25 scores are calculated
Work on the Top 25 for 2023 started by mapping each of the 43,996 CVE records for vulnerabilities reported in 2021 and 2022 to one or several CWEs as root causes. Each time a specific CWE was a root cause for a CVE, the score for that CWE was increased based on the prevalence and severity of the CVE. The formula used ensures that weaknesses only get a high score if they lead to vulnerabilities that are both frequent and severe. Special focus was given to issues from the Known Exploited Vulnerabilities (KEV) Catalog created in November 2021 by the Cybersecurity and Infrastructure Security Agency (CISA).
One important aspect of the methodology is that, where relevant, entire attack chains are counted, not just single root causes. If a reported CVE includes an attack that exploits more than one type of weakness, that CVE will be counted for all the CWEs. Most real-world attacks rely on chaining to escalate from initial access to final compromise, and every step along the way is required for the attack to work – see our analysis of the MOVEit Transfer attack for a recent example. Treating each weakness in a chain as the root cause provides a more realistic picture of how software flaws translate to vulnerabilities.
CWE Top 25 vs. OWASP Top 10
Both the CWE Top 25 and the OWASP Top 10 are compiled by analyzing CWEs and CVEs but differ in scope and methodology. The CWE Top 25 applies to all types of software and lists CWEs based on the frequency and severity of resulting CVEs. The OWASP Top 10 is only for web applications and aims to group CWEs into broader categories that are then ranked. Recent years have seen the OWASP Top 10 risk categories become increasingly high-level.
The big picture: Three common themes to look out for
There are many ways to slice and dice the top CWEs, but all the listed weaknesses fall into one of three broad categories:
- Memory management (6 CWEs): Programming in any language that allows direct memory access (most commonly C/C++) always carries some risk of memory management flaws that attackers could exploit, usually with severe consequences. This category includes CWE-787, CWE-416, CWE-125, CWE-476, CWE-190, and CWE-119.
- Untrusted inputs (11 CWEs): Any input that originates outside the application or could be otherwise controlled by an attacker poses a security risk that could allow for a successful attack. This includes not only input strings but also all uploads and all deserialized data. CWE-79, CWE-89, CWE-78, CWE-20, CWE-22, CWE-352, CWE-434, CWE-502, CWE-77, CWE-918, and CWE-94 fall into this bucket.
- Access management (8 CWEs): Authorization, authentication, permissions, privileges – all these are about various types of access to systems, resources, or operations. Fine-grained access control is extremely hard to design, implement, and match to actual usage, and any failures can open the way for attackers. This class of weaknesses includes CWE-862, CWE-287, CWE-798, CWE-306, CWE-362, CWE-269, CWE-863, and CWE-276.
Applying the CWE Top 25 to improve application security
Because the CWE scores are directly correlated with CVEs from 2021 and 2022, the Top 25 reflects the major vulnerabilities reported during that period. Accordingly, the list is skewed in favor of the most severe and widespread vulnerabilities, which are most likely to be reported. If you browse the CVE database or (even better) CISA’s KEV catalog, you will notice that the majority of severe vulnerabilities are for various network appliances, with buffer overflows and other memory-access attacks commonly listed as the root cause. This explains the (continued) top position of out-of-bounds writes, as such weaknesses are both severe and reported in a relatively large proportion of CVEs.
The major practical takeaways for software developers correspond to the three overarching themes across the top 25:
- If you write in C/C++, make checking memory management routines a separate item in your code reviews, QA, and security testing. This goes double for software and firmware for embedded systems and network devices, which makes a high-value target while also being harder to patch.
- For all software, treat all data coming into your application as untrusted and validate it before use. This includes not only expected user inputs and uploads but also internal databases (to avoid SQL injection) and local files such as logs (to avoid deserialization attacks).
- For all applications and especially for all APIs, make fine-grained access control a critical part of design and testing, covering data, application objects, and functions. This needs to start with authentication and continue with multi-level authorization that (ideally) spans all possible access paths and flows.
For web applications, the clear takeaway is to make sure you test for and eliminate at the very least SQL injection and cross-site scripting flaws. With major CVEs currently under exploitation for both SQLi (like CVE-2023-34362 in MOVEit) and XSS (like CVE-2023-24488 in Citrix Gateway), systematic security testing from development through staging and into production is a must.
To learn how to build security testing into your application security program, read the free Invicti white paper on enterprise web security best practices.