DEV Community

Unicorn Developer
Unicorn Developer

Posted on

OWASP Top 10 2025—from code to supply chain: Expanding boundaries of security

This article covers changes in the OWASP Top 10 for 2025 with examples and breaks down how SAST can help avoid vulnerabilities.

1343_OWASP_top_ten_2025/image1.png

The OWASP Top 10 is a list of ten most critical security risks to web applications. It serves as a guide for developers, architects, and information security professionals, helping them focus on the most severe risks when building web applications.

Since the previous list version was released in 2021, the threat landscape has changed significantly. In 2025, OWASP presented its updated edition: OWASP Top 10:2025.

This article tells about the new vulnerability categories in the updated list and demonstrates how to detect some of these threats using PVS-Studio static analyzer. For OWASP, there is a separate category of diagnostic rules. You can read more about it in the documentation.

We have already written about the previous version of OWASP Top 10 (2021)—you are welcome to read the article via this link.

What has changed?

As mentioned earlier, the OWASP Top 10 is updated not only for the sake of novelty—changes to the list reflect the evolution of real-world threats. Compared to the 2021 version, the new list retains most categories but revises their priorities and introduces two new ones: A03:2025 Software Supply Chain Failures and A10:2025 Mishandling of Exceptional Conditions.

Besides, some descriptions have been refined to better align with modern practices. For example, the emphasis in logging has shifted from passive event recording to the need for proactive alerting and response, and the focus on authentication has become more precise.

A01: Broken Access Control

This category includes vulnerabilities that lead to unauthorized information disclosure, modification, or destruction of all data, or the execution of business functions outside the user's intended privileges.

In OWASP Top 10:2025, this category additionally includes risks previously listed separately as Server-Side Request Forgery (SSRF)—in the previous version (2021), SSRF has taken the A10 position. This consolidation emphasizes the common nature of these threats—uncontrolled access to resources: internal files, network services, or other users' data.

Broken Access Control remains in first place, confirming that access control errors are among the most critical and widespread problems in modern web applications.

Look at this code fragment from the Power-Fx project:

public static void Check(Engine engine, string pathInput)
{
  EngineSchema schema;
  if (pathInput != null)
  {
    var json = File.ReadAllText(pathInput);
    schema = JsonSerializer.Deserialize<EngineSchema>(json);
  }
  ....
}
Enter fullscreen mode Exit fullscreen mode

The PVS-Studio warning: V5609 Possible path traversal vulnerability. Potentially tainted data from the 'pathInput' variable is used as path.

Here, the file path comes directly from a user via the pathInput parameter, is only checked for null and is immediately used to read the file. This is a classic path traversal vulnerability: an attacker could pass a value like ../../../etc/passwd and gain unauthorized access to any files on the server.

Broken Access Control problems aren't limited to the file system. They also occur, for instance, at the authorization logic level.

In Spring, the vote method from AccessDecisionVoter can be implemented as follows:

@Override
public int vote(Authentication authentication, 
                FilterInvocation filterInvocation, 
                Collection<ConfigAttribute> attributes) {
  boolean isAdmin = hasAdminRole(authentication);
  String requestMethod = filterInvocation.getRequest().getMethod();
  if ("DELETE".equals(requestMethod) && !isAdmin) {
    return ACCESS_GRANTED;
  }
  return ACCESS_GRANTED;
}
Enter fullscreen mode Exit fullscreen mode

Here, the method always returns ACCESS_GRANTED, including cases where a regular user attempts to perform a privileged operation. This is a direct violation of the least privilege principle.

For such an error, PVS-Studio analyzer would trigger diagnostic rule V5328: Using non-restrictive authorization checks could lead to security violations.

Complete list of CWEs for category A01:2025 Broken Access Control

A02 Security Misconfiguration

This category combines vulnerabilities related to insecure configuration: enabling unnecessary ports or services, insecure configuration, using external data to define system properties, etc.

Since the previous version, this category has risen from 5th to 2nd place in the list. This signals that even minor configuration errors are increasingly becoming an entry point for attacks on applications.

For example, a configuration problem may occur due to external data.

public void ExecuteSqlQuery(....)
{
  ....
  string catalog = Request.QueryString["catalog"];
  using (SqlConnection dbConnection = IO.GetDBConnection())
  {
    dbConnection.ConnectionString = $"Data Source=....; " +
                                    $"Initial Catalog={catalog}; " +
                                    $"User ID=....; " +
                                    $"Password=....;";
    ....
  }
  ....
}
Enter fullscreen mode Exit fullscreen mode

In this example, a connection string for the database is being formed. Data that hasn't undergone any prior validation is written into the Initial Catalog parameter, allowing an attacker to pass any catalog name and obtain data they shouldn't have access to.

We could fix this by checking the user-provided data:

public void ExecuteSqlQuery(...., HashSet<string> validCatalogNames)
{
  ....
  string catalog = Request.QueryString["catalog"];

  if(!validCatalogNames.Contains(catalog))
    return;

  using(SqlConnection dbConnection = IO.GetDBConnection())
  {
    dbConnection.ConnectionString = $"Data Source=....; " +
                                    $"Initial Catalog={catalog}; " +
                                    $"User ID=....; " +
                                    $"Password=....;";
    ....
  }
  ....
}
Enter fullscreen mode Exit fullscreen mode

Here, before using the obtained value, we check that catalog exists in the validCatalogNames collection. This allows the user access only to a limited set of catalogs.

PVS-Studio analyzer detects such defects using the diagnostic rule V5624: Use of potentially tainted data in configuration may lead to security issues.

Configuration problems can also lead to the risk of an XXE attack. For instance, an XML parser receiving data from an external source can be configured insecurely.

Let's take this XML file format as an example, which the application is supposed to work with:

<?xml version="1.0" encoding="utf-8" ?>
<shop>
  <itemID>62</itemID>
</shop>
Enter fullscreen mode Exit fullscreen mode

Let's suppose the following code handles the processing:

public static void processItemWithID(String pathToXmlFile) {
  DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  DocumentBuilder builder = factory.newDocumentBuilder();
  var document = builder.parse(pathToXmlFile);    // <= 
  var nodeList = document.getElementsByTagName("itemID");
  String itemiD = nodeList.item(0).getTextContent();
  try {
    long itemIDvalue = Long.parseLong(itemiD);
    // process the item with 'itemIDvalue' value
    System.out.printf("An item with the %d ID was processed.%n", itemIDvalue);
  } catch (NumberFormatException e) {
    System.out.printf("%s is not valid 'itemID' value.%n", itemiD);
  }
}
Enter fullscreen mode Exit fullscreen mode

For the XML file above, the application will output this line:

An item with the '62' ID was processed.
Enter fullscreen mode Exit fullscreen mode

If we try to use an invalid value for the ID field, the application reports an error:

"Hello world" is not valid 'itemID' value.
Enter fullscreen mode Exit fullscreen mode

Although the code performs its assigned task, it is vulnerable to XXE attacks for several reasons.

  • The XML content comes from the user.
  • The XML parser is configured to process external entities.
  • The output may be sent back to the user.

To compromise this code, an attacker could use, for example, the following XML file:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file://D:/MySecrets.txt">
]>
<shop>
  <itemID>&xxe;</itemID>
</shop>
Enter fullscreen mode Exit fullscreen mode

This file declares an external entity, xxe, which the parser will process. As a result, the contents of the D:/MySecrets.txt file (for example, This is an XXE attack target), located on the machine running the application, will output to the user:

This is an XXE attack target. is not valid 'itemID' value.
Enter fullscreen mode Exit fullscreen mode

To protect against such an attack, you can disable external entity processing and ignore DTD processing. For the example above, we would do as follows:

String feature = "http://apache.org/xml/features/disallow-doctype-decl"; 
factory.setFeature(feature, true);
Enter fullscreen mode Exit fullscreen mode

PVS-Studio analyzer detects such security defects using the diagnostic rule V5335: Potential XXE vulnerability. Insecure XML parser is used to process potentially tainted data.

Complete list of CWEs for category A02:2025 Security Misconfiguration

A03 Software Supply Chain Failures

In OWASP Top 10 2025, the former category Vulnerable and Outdated Components (A06:2021) has evolved into A03:2025 – Software Supply Chain Failures. This change emphasizes that threats are no longer limited to using outdated libraries: today, attackers target the entire supply chain—from code repositories and CI/CD pipelines to final deployment artifacts.

However, the list of CWEs for this category still consists almost entirely of problems with used components:

  • using an outdated function (CWE-477);
  • using components with known vulnerabilities (CWE-1035);
  • using unsupported third-party components (CWE-1104);
  • using a component that cannot be updated (CWE-1329);
  • using a component that is not robust enough (CWE-1357);
  • dependency on a vulnerable third-party component (CWE-1395).

PVS-Studio can find vulnerable components in C# projects using rule V5625: Referenced package contains vulnerability. It uses the SCA mechanism and checks that the dependencies used in the project have no known vulnerabilities.

A04 Cryptographic Failures

This category combines a group of vulnerabilities related to incorrect encryption of confidential data: using outdated cryptographic algorithms or hash functions, passing unencrypted data, etc.

Compared to the previous version, this category has dropped from second to fourth position.

It includes errors related to using outdated encryption or hashing algorithms. For example, our tool has rule V5314: Use of an outdated hash algorithm is not recommended.

Here is an example of this rule triggering in the DBeaver project:

private boolean checkLockPassword() {
  BaseAuthDialog dialog = new BaseAuthDialog(....);
  if (dialog.open() == IDialogConstants.OK_ID) {
    final String userPassword = dialog.getUserPassword();
    if (!CommonUtils.isEmpty(userPassword)) {
      try {
        final byte[]
                md5hash = MessageDigest.getInstance("MD5") // <=
                .digest(userPassword.getBytes(....));
        final String hexString = CommonUtils.toHexString(md5hash)
                                            .toLowerCase(Locale.ENGLISH)
                                            .trim();
        if (hexString.equals(dataSource.getLockPasswordHash())) {
          return true;
        }
        UIUtils.showMessageBox(....);
      } catch (Throwable e) {
        DBWorkbench.getPlatformUI().showError(....);
      }
    }
  }
  return false;
}
Enter fullscreen mode Exit fullscreen mode

The PVS-Studio warning V5314. Use of the 'MD5' hash algorithm is not recommended. Such code may cause the exposure of sensitive data.

Here, the analyzer indicates that the MD5 encryption algorithm is outdated.

But there are other suspicious cases related to cryptography that can lead to application vulnerability. For example, as in this fragment from the same DBeaver:

public static String generateNewId(DBPDriver driver) {
  long rnd = new Random().nextLong();               // <=
  if (rnd < 0) rnd = -rnd;
  return driver.getId() + "-" 
                        + Long.toHexString(System.currentTimeMillis()) 
                        + "-" 
                        + Long.toHexString(rnd);
}
Enter fullscreen mode Exit fullscreen mode

The PVS-Studio warning V5307. Potentially predictable seed is used in pseudo-random number generator.

The problem here is that we create a new instance of the Random class each time, causing the generated numbers to be insufficiently random depending on the JDK. To fix this, we could move the creation of the Random instance to the class level and use the same object when needed.

Complete list of CWEs for category A04:2025 Cryptographic Failures

A05 Injection

Injection is a vulnerability that arises when untrusted data enters critical points of the application—for example, during SQL query execution. Such data causes the program to behave differently than originally intended. As a consequence, confidential data can be corrupted, disclosed, or program execution can be halted.

Compared to the previous version, this category has dropped from A3 to A5. Injection in the new version of the list still takes place between Cryptographic Failures and Insecure Design (see below). This category likely moved lower due to more extensive testing of applications using various tools. Today, no decent project goes without injection checks.

In our tool, there are quite a few rules that detect defects related to this category. An extensive list of various injections is well-detected by static analysis tools:

  • SQL injection – V5309 (Java), V5609 (C#);
  • Command injection – V5310 (Java), V5616 (C#);
  • Argument injection – V5311 (Java);
  • XPath injection – V5312 (Java), V5622 (C#);
  • LDAP injection – V5321 (Java), V5620 (C#);
  • Reflection injection – V5322 (Java);
  • XSS injection – V5330 (Java), V5610 (C#);
  • Cookie inkection – V5630 (C#).

For example, let's look at a Cookie injection:

public void ChangeCookie()
{
  String cookieValue = Request.Form["userRole"];

  Response.Cookies.Add(
    new HttpCookie(WebLocalizationConfiguration.CookieName, cookieValue)
    {
      Expires = Clock.Now.AddYears(2),
      Path = Request.ApplicationPath
    }
  );
  ....
}
Enter fullscreen mode Exit fullscreen mode

A new object of the HttpCookie class is added to HttpResponse, which is initialized based on data from an external source, Request.Form. Using data without any verification or validation can allow attackers to affect the application behavior.

We could fix the situation using, for example, the following check:

....
String cookieValue = Request.Form["userRole"];

if (!Regex.IsMatch(cookieValue, DataValidationPattern))
  return;
....
Enter fullscreen mode Exit fullscreen mode

Complete list of CWEs for category A05:2025 Injection

A06 Insecure Design

Insecure Design is a category that covers vulnerabilities that are baked in even before the first line of code is written. It deals with shortcomings in application architecture and design: lack of threat modeling, ignoring secure-by-design principles, weak business logic, or lack of integrity control for critical operations.

Unlike implementation errors, which can be fixed through refactoring or patches, architectural flaws can't be eliminated without redesigning the system. Even perfectly written code based on an initially insecure architecture will remain vulnerable.

The Insecure Design category first appeared in the OWASP Top 10 in 2021 as A04 and moved to position A06 in 2025. This doesn't mean the problem has become less relevant. Rather, other risks have come to the fore—such as those related to supply chains or exception handling.

Although static analysis can't directly see the absence of threat modeling, it can detect symptoms of insecure design.

Suppose a banking application implements a money transfer function as follows:

public void transferMoney(
  String fromAccountId, 
  String toAccountId, 
  BigDecimal amount
) {
    Account from = accountRepository.findById(fromAccountId);
    Account to = accountRepository.findById(toAccountId);
    from.debit(amount);
    to.credit(amount);
}
Enter fullscreen mode Exit fullscreen mode

At first glance, everything seems logical. However, the code lacks necessary checks.

  • Does the account have sufficient funds?
  • Isn't the account blocked?
  • Is the current user authorized to transfer from this account?
  • Is this a duplicate execution of an already processed request?

Such an architecture initially lacks protection against fraud, overdraft, or CSRF-like attacks. This is a classic case of Insecure Design.

PVS-Studio can help detect some manifestations of such design problems. But static analysis can't directly indicate that an application is incorrectly designed.

Complete list of CWEs for category A06:2025 Insecure Design

A07 Authentication Failures

This group of vulnerabilities related to errors in session or user authentication management. Typically, such vulnerabilities can lead to the compromise of passwords, security keys, or session tokens, and also allow an attacker to access someone else's data.

In the previous version of OWASP Top 10, this category was called Identification and Authentication Failures and took the same 7th position. In this version, as you may have noticed, the name has shifted towards authentication, to align more accurately with the list of CWEs for this category.

As an example of a defect from this category, look this abstract case:

public static void main(String[] arg)
{
  ....
  JSch jsch = new JSch();
  Session session = jsch.getSession(user, host, 22);
  session.setPassword("123fj");
  ....
}
Enter fullscreen mode Exit fullscreen mode

"Yeah, why not just save the password right in the code?.. Wait, you mean it's easy to extract it from there?.. And why am I suddenly responsible if someone exploits it?.."

To avoid hearing such questions, simply use secure storage where data is kept encrypted. And don't forget about access control for such storage. A regular user shouldn't be able to access it in any way.

public static void main(String[] arg)
{
  ....
  JSch jsch = new JSch();
  Session session = jsch.getSession(user, host, 22);
  session.setPassword(dataStorage.getPassword);
  ....
}
Enter fullscreen mode Exit fullscreen mode

PVS-Studio analyzer detects such errors using diagnostic rule V5305: Storing credentials inside source code can lead to security issues, and for C# projects there is a similar rule V5601.

Complete list of CWEs for category A07:2025 Authentication Failures

A08 Software or Data Integrity Failures

Software or Data Integrity Failures is a group of vulnerabilities that lead to a violation of software integrity. Updates without digital signatures, insecure deserialization, loading dependencies from insecure repositories, etc.

This category, like the previous one, hasn't changed its position in the list but slightly altered its name from Software and Data Integrity Failures for greater clarity.

Let's take insecure deserialization as an example.

Attacks carried out through deserialization of external data can have various goals and implementation options. For instance, an attacker can tamper with data in the deserialized object, which may lead to unauthorized privilege escalation or the assignment of an invalid value to some object field.

The best way to avoid such cases is to prevent users from sending data to the application for serialization. But if it's still necessary, they should use secure libraries for serialization/deserialization and also validate external data.

Let's take the following configuration:

public void notSecure(HttpServletRequest req, 
                      HttpServletResponse res) throws .... {
    ServletInputStream servletIS = req.getInputStream();
    ObjectInputStream  objectIS  = new ObjectInputStream(servletIS); // <=
    Object object = objectIS.readObject();
}
Enter fullscreen mode Exit fullscreen mode

It's not secure. The code below is much better:

class SecureObjectInputStream extends ObjectInputStream {
  public SecureObjectInputStream(InputStream in) throws IOException {
    super(in);
  }

  @Override
  protected Class<?> resolveClass(ObjectStreamClass osc) throws .... {
    List<String> allowedClasses = new ArrayList<>();
    allowedClasses.add(AllowedClass1.class.getName());
    allowedClasses.add(AllowedClass2.class.getName());
    if (!allowedClasses.contains(osc.getName())) {
      throw new InvalidClassException("Unauthorized deserialization", 
                                      osc.getName());
    }
    return super.resolveClass(osc);
  }
}

....

public void withCheck(HttpServletRequest req, 
                      HttpServletResponse res) throws .... {
  ServletInputStream servletIS = req.getInputStream();
  ObjectInputStream objectIS   = new SecureObjectInputStream(servletIS);
  Object object = objectIS.readObject();
}
Enter fullscreen mode Exit fullscreen mode

In this code version, we created the SecureObjectInputStream class, derived from ObjectInputStream. We overrode the resolveClass method, which enables us to check which type of the object we are about to deserialize. The behavior described in the method prevents us from deserializing an unsafe object.

PVS-Studio analyzer detects such defects using diagnostic rule V5333: Possible insecure deserialization vulnerability. Potentially tainted data is used to create an object during deserialization. For C# projects, there's a similar V5611 diagnostic rule.

Complete list of CWEs for category A08:2025 Software or Data Integrity Failures

A09 Security Logging & Alerting Failures

This category combines shortcomings in audit, monitoring, and alerting systems that hinder the detection, investigation, and response to security incidents. Unlike the previous OWASP Top 10 (2021), which discussed Security Logging and Monitoring Failures, in 2025 the emphasis shifted from passive event recording to active alerting and response, that's why the name changed to "Alerting."

The problem is not that logs aren't written. Here is the list of issues below.

  • Critical events—multiple failed login attempts, access to protected resources without rights, suspicious transactions—are not logged.
  • Logs lack sufficient details: no IP address, user agent, or session ID.
  • There is no receiver for a notification when anomalies occur—the system remains "silent" until it's too late.

A static analyzer won't configure logging in a project. Still there are cases where PVS-Studio can help with this category—at least with preserving log integrity.

For example, we need to log user input, but we do it without checking data:

public class InputHelper {
  private final Logger logger = LoggerFactory.getLogger(InputHelper.class);
  private String username;

  public void process(InputStream stream) {
    Scanner scanner = new Scanner(stream);
    String userInput = scanner.next();
    String logMessage = "User '" + userName + 
                        "' entered value: '" + userInput + "'.";
    logger.info(logMessage); // <=
  }
}
Enter fullscreen mode Exit fullscreen mode

In this case, an attacker can inject random data about events that never occurred and mislead the person analyzing the logs. For example, an attacker might enter this value:

2022/r/nINFO: User 'Admin' logged out.
Enter fullscreen mode Exit fullscreen mode

Then we'll see the following result in logs:

INFO: User 'SomeUser' entered value: '2022'.
INFO: User 'Admin' logged out.
Enter fullscreen mode Exit fullscreen mode

Detecting such situations is possible with rule V5319: Possible log injection. Potentially tainted data is written into logs, or the similar rule for C# projects, V5619.

Complete list of CWEs for category A09:2025 Security Logging & Alerting Failures

A10 Mishandling of Exceptional Conditions

Last but not least, here is another completely new category in the OWASP Top 10 2025. For the first time in OWASP Top 10 history, attention is given not only to what code does but also to what happens when it breaks. Situations where an application either ignores errors or reacts to them by creating new vulnerabilities are quite common.

Such defects can lead to the following consequences:

  • a disclosure of confidential information—stack traces in a user response;
  • a denial of service—uncaught exceptions terminate a thread or process;
  • a bypass of security mechanisms—an error in a check and jumping to the next step without authorization;
  • a loss of incident context—no logging for exceptions.

Static analysis is quite effective at detecting such problems because many of them manifest as anti-patterns in the code.

Here is a simple case as an example:

....
try {
  authService.authenticate(user, password);
} catch (AuthenticationException e) {}
....
Enter fullscreen mode Exit fullscreen mode

It seems like we just didn't handle the Exception, but because of this, a user suddenly might have been authorized by default.

Here is another unwanted scenario where we replace one exception with another:

....
try {
  processPayment();
} catch (Exception e) {
  throw new RuntimeException("Payment failed");
}
....
Enter fullscreen mode Exit fullscreen mode

In this case, we lose the stack trace of the original exception, hindering our ability to find the source of the problem.

The topic of exceptions is so vast that sometimes mistakes appear to be quite amusing. Look at the fragment from the Apache NiFi project:

public void finishTransferFlowFiles(
  final CommunicationsSession commSession
) throws IOException {
  if (postResult == null) {
    new IllegalStateException(....);
  }
  ....
}
Enter fullscreen mode Exit fullscreen mode

The PVS-Studio warning: V5303 The object was created but it is not being used. The 'throw' keyword could be missing. The 'throw' keyword could be missing.

We handled a specific situation when postResult is null and even created the IllegalStateException we needed. One problem—we forgot to throw it :).

So, the new category is a treasure trove of various interesting issues that a static analyzer, such as PVS-Studio, can help find.

Complete list of CWEs for category A10:2025 Mishandling of Exceptional Conditions

Conclusion

OWASP Top 10:2025 is more than just an updated list of threats. It reflects how the very nature of attacks is changing: from classic injections to supply chain compromise, from code errors to design failures, from silent logs to dangerously ignored failures.

The two new categories—Software Supply Chain Failures (A03) and Mishandling of Exceptional Conditions (A10)—particularly clearly show that security is no longer limited to just clean code. It encompasses the entire software lifecycle: from choosing dependencies and architectural decisions to reacting to exceptions.

Static analysis remains one of the most effective tools for early risk detection. Of course, not all OWASP Top 10 categories can be covered directly by SAST—especially those related to configuration, CI/CD, or human processes. But even where the analyzer doesn't give a direct answer, it helps detect symptoms of poor security practices: lack of validation, weak checks, unprotected entry points.

You can try PVS-Studio static analyzer using a free license, available here. We've looked at various scenarios where the analyzer helps find security defects described in the OWASP Top 10, so why not try checking your project for them? :)

Security is not a feature you can turn on. It's a discipline built into every stage of development. The later we start introducing it, the more expensive this neglecting becomes.

Memento Securitatis.

Top comments (0)