10 Common Web Security Vulnerabilities
Don’t wait for a data breach to happen before making security a priority. This article explains how to set up a proactive web app defense and avoid the top 10 most common security pitfalls.
Don’t wait for a data breach to happen before making security a priority. This article explains how to set up a proactive web app defense and avoid the top 10 most common security pitfalls.
For all too many companies, it’s not until after a security breach has occurred that web security best practices become a priority. During my years working as an IT security professional, I saw—time and time again—how obscure the world of web development security issues can be to so many of my fellow programmers and how many website vulnerabilities go unnoticed.
An effective approach to web security threats must, by definition, be proactive and defensive. Toward that end, we aim to spark a security mindset and to inject the reader with a healthy dose of paranoia. Businesses in highly regulated industries may also consider partnering with an application security agency to identify vulnerability gaps and strengthen their security posture.
This guide focuses on developing an awareness of and mitigating 10 common and significant web security pitfalls, ranging from common vulnerabilities in web applications to browser vulnerabilities.
Authentication and Authorization: A Cyber Security Primer
Programmers and IT professionals often express confusion regarding the distinction between authorization and authentication. The use of the abbreviation auth for both terms increases the haziness that surrounds them.
Let’s define and clarify the distinction:
- Authentication: Verifying that a user is (or at least appears to be) the person they say they are.
- Authorization: Granting a user access to a specific resource, or permission to perform a particular action.
Stated another way, authentication is knowing who an entity is, while authorization is what a given entity can do. With this in mind, let’s explore 10 common internet vulnerability issues.
Injection Flaws
Injection flaws result from a classic failure to filter untrusted input. Injection flaws can happen when we pass unfiltered data to the SQL server (SQL injection), to the browser (via Cross Site Scripting), to the LDAP server (LDAP injection), or anywhere else. The problem here is that the attacker can inject commands to hijack clients’ browsers, resulting in loss of data.
Anything that your application receives from an untrusted source must be filtered, preferably according to an allowlist. Using a denylist to this end is not recommended, as it is difficult to configure properly. A denylist is also considered easy for a hacker to bypass. Antivirus software products typically provide stellar examples of failing denylists. Pattern matching does not work.
When integrating applications with large language models (LLMs), you should also consider prompt injection risks. Much like traditional injection attacks, untrusted input may manipulate an AI system into revealing sensitive information or performing unintended actions through connected tools and APIs.
Prevention: Protecting against injection is “simply” a matter of filtering our input and considering which senders can be trusted. Filtering is quite an undertaking because we need to process all input unless it can unquestionably be trusted.
If we filter 999 inputs in a system with 1,000 inputs, we still have one field that can be the Achilles’ heel that brings down our system.
Using Second Order SQL Injection to inject one SQL query result into another is also considered dangerous. It could seem like a good idea because the database is trusted. But if the perimeter is not, our input could originate indirectly from a malicious source.
Since filtering is pretty hard to get right, it is advisable to rely on our framework’s filtering functions. They are proven to work and thoroughly scrutinized. If you do not already use a framework, consider the server security benefits of moving to one.
Broken Authentication
Problems that might occur during broken authentication don’t necessarily stem from the same root cause. Rolling your own authentication code is not recommended, as it is hard to get right. There are myriad possible pitfalls, and here are a few:
- The URL might contain the session ID and leak it in the referer header.
- Passwords might not be encrypted in storage and/or transit.
- Session IDs might be predictable, making it a little too easy to gain unauthorized access.
- Session fixation might be possible.
- Session hijacking could occur if timeouts are not implemented correctly, or if using HTTP (no SSL security), etc.
Prevention: The most straightforward way to avoid the web security vulnerabilities related to broken authentication is to implement a framework. If you roll your own code, be extremely paranoid and educate yourself on web security considerations and the potential issues that could arise.
Cross-Site Scripting (XSS)
An attacker sends on input JavaScript tags to your web application. When this input is returned to the user unsanitized, the user’s browser would execute it. This is a fairly widespread input sanitization failure, essentially a subcategory of injection flaws. XSS can be as simple as crafting a link and persuading a user to click it, or it can be something much more sinister. For example, on page load, the script would run and be used to post your cookies to the attacker.
Prevention: Simply put, don’t return HTML tags to the client. This would also protect you from HTML injection, which is when an attacker injects plain HTML content (such as hidden iframes or malicious embedded content). To implement this solution, convert all HTML entities to return something else. For example, convert <script> to return <script>. Alternatively, you can use regular expressions to strip away HTML tags using regular expressions on < and >. But this is dangerous because some browsers may not interpret severely broken HTML. Better to convert all characters to their escaped counterparts.
Broken Access Control
Broken access control vulnerabilities occur when applications fail to properly enforce authorization rules. Insecure Direct Object References (IDOR) are a common example, where internal object identifiers such as file names or database keys are exposed to users without sufficient authorization checks. This is a classic case of trusting user input and paying the price with a resultant security vulnerability.
For example, the code has a download.php module that lets the user download files, using a query parameter to specify the file name (e.g., download.php?file=something.txt). If the developer omitted authorization from the code, the attacker can now use it to download system files accessible to the user running PHP (e.g., the application code or random server data like backups).
Another example of broken access control is a password reset function that relies on user input to determine identity. After clicking the valid URL, an attacker could modify the username field in the URL to say something like “admin.”
Developers often assume that since the server side generates the UI, the client would not be able to access functionality that is not supplied by the server. It is not as simple as that, as an attacker can always forge a request to “hidden” functionality. Imagine there’s an /admin panel, and the button is only present in the UI if the user is actually an admin. Nothing keeps an attacker from discovering and misusing this functionality if authorization is missing.
Incidentally, I have seen all of these examples often “in the wild.”
Prevention: Perform user authorization properly and consistently, and allowlist the choices. More often than not, the vulnerability can be avoided altogether by storing data internally and not relying on data being passed from the client via query parameters. Session variables in most frameworks are well-suited to this purpose. On the server side, authorization must always be performed.
Security Misconfiguration
In my experience, it is common to encounter misconfigured web servers and applications. Here are some web application security examples related to misconfiguration:
- Running an application with debug enabled in production
- Having directory listing (which leaks valuable information) enabled on the server
- Running outdated software (think WordPress plugins, old versions of PhpMyAdmin)
- Running unnecessary services
- Not changing default keys and passwords (which happens more frequently than you’d believe)
- Revealing error handling information (e.g., stack traces) to potential attackers
Prevention: Have a good (preferably automated) “build and deploy” process, which can run tests on deploy. The quick fix for security misconfiguration is post-commit hooks, to prevent code from going out with default passwords and/or development stuff built in.
Cryptographic Failures
This web security vulnerability category focuses on failures in cryptography and the protection of sensitive data. Sensitive data should be encrypted at all times, without exception, including in transit and at rest. Credit card information and user passwords should never travel or be stored unencrypted, and passwords should always be hashed. Obviously, the crypto/hashing algorithm must not be a weak one. When in doubt, use modern, industry-standard cryptographic algorithms and protocols such as AES-256 and RSA-2048.
It cannot be overemphasized that session IDs and sensitive data should not travel in URLs. Cookies with sensitive data should have the “secure” flag on.
Modern applications should also ensure secrets management is handled securely, particularly in cloud-native environments where credentials, API keys, and signing tokens are frequently distributed across services.
Prevention:
- In transit: Use HTTPS with a proper certificate and PFS (Perfect Forward Secrecy). Do not accept anything over non-HTTPS connections. Have the “secure” flag on cookies.
- In storage: Reduce your exposure to this vulnerability. If you don’t need sensitive data, virtually shred it. The data you don’t have can’t be stolen. Do not store credit card information, and you will not need to have to deal with PCI compliance. Sign up with a payment processor like Stripe or Braintree. Store and encrypt sensitive data, and ensure all passwords are hashed using bcrypt. If you don’t use bcrypt, educate yourself on salting and rainbow tables.
And at the risk of stating the obvious, do not store the encryption keys near their protected data. That’s like storing your bike with a lock that has the key in it. Protect your backups with encryption and keep your keys private—and don’t lose them.
Cross-site Request Forgery (CSRF)
In a CSRF—also referred to as a confused deputy attack—a malicious third party fools the browser into misusing its authority to do something for the attacker.
In the case of CSRF, a third-party site uses your browser, cookies, and session to issue a request to a target site (e.g., your bank). If on one browser tab you are logged in to your bank, and if your bank is vulnerable to this type of attack, then another tab can be controlled to make your browser misuse its credentials on the attacker’s behalf, which results in the confused deputy problem. The deputy is the browser that misuses its authority (session cookies) to perform the attacker’s instructions.
Consider this example: Attacker Alice wants to lighten target Todd’s wallet by transferring some of his money into her account.
To send money, Todd accesses the following URL: https://example.com/app/transferFunds?amount=1500&destinationAccount=4673243243 at his bank which, incidentally, is vulnerable to CSRF attacks. After Todd performs his transaction, a success page displays and the transfer is complete.
Alice is aware that Todd frequently visits a site she controls at https://blog.aliceisawesome.com, so Alice places the following snippet on her site: <img src=https://example.com/app/transferFunds?amount=1500&destinationAccount=4673243243 width=0 height=0 />.
When Todd next visits Alice’s website, his browser wrongly thinks the snippet links to an image. The browser automatically issues an HTTP GET request to fetch the picture. But instead of getting an image to display in the browser, the request instructs Todd’s bank to transfer $1,500 to Alice.
Incidentally, in addition to demonstrating the CSRF vulnerability, this example also demonstrates altering the server state with a supposedly safe HTTP GET request. This is in itself a serious vulnerability. HTTP GET requests should not alter the resource that is accessed. Never use HTTP GET requests to change the server state.
Prevention: Store a secret token in a hidden form field, inaccessible to a third-party site. This, of course, requires you to verify the hidden field. Some sites may ask for a password before allowing you to modify sensitive settings (like a password reminder email). I suspect this could be to prevent the misuse of your abandoned sessions on public computers.
Server-side Request Forgery (SSRF)
In a Server-side Request Forgery (SSRF) attack, an attacker tricks the server into making requests to unintended locations. We often see this type of web security vulnerability in functionality that fetches or validates remote resources based on user input. If input validation is weak, attackers may be able to force the server to access internal services, cloud metadata endpoints, or administrative interfaces that are not publicly exposed.
For instance, consider a site that allows users to import profile pictures from external URLs. An attacker may discover that instead of supplying an image URL, they can provide a URL pointing to an internal administrative service running on the company’s private network. The server fetches the resource on the attacker’s behalf, potentially exposing sensitive internal data that would otherwise be inaccessible from the public internet.
In cloud environments, SSRF attacks have been used to retrieve temporary credentials and sensitive infrastructure metadata from internal endpoints.
Prevention: Validate and allowlist outbound destinations whenever possible, and treat all user-supplied URLs as untrusted input. As a general rule, you should also prevent application servers from accessing internal services and cloud metadata endpoints directly.
Using Components With Known Vulnerabilities
The title says it all. I’d classify this one as more of a maintenance/deployment issue. Before incorporating new code, do some research, and possibly some auditing. Using code from a random person on GitHub, for example, may be convenient, but it is not without risk of serious web security vulnerability.
I have seen many instances where sites got owned (i.e., where an outsider gains administrative access to a system), because third-party software (e.g., WordPress plugins) remained unpatched for years in production. If you think they will not find your hidden phpmyadmin installation, let me introduce you to DirBuster.
The lesson here is that software development does not end when the application is deployed. There has to be documentation, tests, and plans on how to maintain and keep the application updated, especially if it contains third-party or open source components.
This is even more important today, as applications increasingly depend on extensive third-party package ecosystems and AI-generated code. Dependency scanning and automated vulnerability monitoring have become common ways to identify vulnerable components before they make it into production.
Prevention:
- Do not be a copy-paste coder. Carefully inspect the piece of code you are about to put into your software, as it might be broken or, in some cases, intentionally malicious. Web security attacks are sometimes unwittingly invited in this way.
- Stay up-to-date with the latest versions of everything that you trust, and have a plan to update regularly. To stay on top of new security vulnerabilities, subscribe to your products’ newsletters.
Unvalidated Redirects and Forwards
This is yet another input filtering issue. Suppose that the target site has a redirect.php module that takes a URL as a GET parameter. Manipulating the parameter can create a URL on targetsite.com that redirects the browser to malwareinstall.com. A user would see the link as targetsite.com/blahblahblah, which looks innocuous enough to trust and click. But clicking this link could transfer the user to a malware drop (or any other malicious) page. Alternatively, the attacker might redirect the browser to targetsite.com/deleteprofile?confirm=1.
It is worth mentioning that stuffing unsanitized user-defined input into an HTTP header might lead to header injection, which is pretty bad.
Prevention:
- Don’t do redirects; these are seldom necessary.
- When a redirect is necessary, have a static list of valid redirect locations.
- Allowlist the user-defined parameter. Note this can be tricky.
Trusted Security Methods Yield Trusted Software Solutions
Developers and companies alike can benefit from a healthy dose of paranoia and website security vulnerability awareness. Modern security practices must be done proactively—and not reactively—to preserve data integrity, boost user trust, and prevent revenue loss.
The core takeaway here is that age-old software practices exist for a reason. What applied back in the day for buffer overflows still applies for pickled strings in Python today. Security protocols help us write better and safer programs, which we should aspire to do. For further reading, see specific server side attacks and OWASP’s Attacks page.
Further Reading on the Toptal Blog:
Understanding the basics
Internet security threats are methods of abusing web technology to the detriment of a website, its users, or even the internet at large. Threats arise from websites that are misconfigured, were inadvertently programmed with vulnerabilities, or rely on components that are themselves vulnerable.
The top internet security threats are always evolving, with injection and authentication flaws often at the top of the list. Open Web Application Security Project (OWASP), an international nonprofit organization, compiles and publishes its OWASP Top 10 annually.
Make sure that any redirects your site makes (e.g., via HTTP headers, meta tags, JavaScript) do not rely on user input, or that any user input is sanitized (e.g., via an allowlist).
A cross-site request forgery (CSRF) token lets a server know that a request is coming from auser on that site and not from another website the user is visiting. This is because the token is passed with every request via a hidden form field, preventing malicious sites from acting on behalf of their viewers via CSRF attacks.
Also known as “dirty” or “untrusted” input, unvalidated input may be any input that is sent to your server. Using such input without sanitizing it first is a security vulnerability that can be turned against you or your users.
SQL injection is when your code adds unvalidated input directly into an SQL statement, instead of using a parameterized query. Fortunately, parameterized query support is built into every database library, so SQL injection attacks are some of the easiest to mitigate.
XSS (cross-site scripting) exploits misguided implementations of a common web application feature: the ability to receive HTML from one user and present it to others. Because unfiltered HTML can contain JavaScript, an attacker can receive it, then run code on behalf of another user (or users) when the other user returns to the web application.
Security misconfiguration refers to undesired defaults in an application that’s in production. Misconfiguration also refers to failing to install security updates in a timely manner.
This is when the server is not programmed to verify authorization for a given function. Broken access control may result from a “security through obscurity” mindset: a false assumption that if a sensitive feature isn’t prominently displayed, potential attackers will never find it.
Sensitive data exposure is when an app (either by its own flaw or by an attacker’s abuse of a vulnerability) reveals a user’s private data (e.g., credit card numbers) to an unauthorized third party.
Security vulnerabilities are weaknesses and flaws in an information system that allow unauthorized third parties to access and manipulate certain aspects of the system, creating an opportunity for malicious activity.

