Aikido

10 Common Web Application Security Threats

Joel HansJoel Hans
|
#

Why are you here?

You know your applications are vulnerable to all kinds of attacks. Overall, cybercrime was forecast to cost $9.5tn in 2025, according to Cybersecurity Ventures - that’s a threefold increase on 2015. And last year, web application attacks accounted for 12% of all data breaches, up from 9% the previous year. This steady rise coupled with the fact that failing to secure web applications can violate numerous regulations, means that developers are keen to better understand the threats that impact them the most. 

So we’re going to reduce the noise around common vulnerabilities and focus on three essential details:

  • The TL;DR, which will better inform you of what the type of attack is. 
  • A concise answer to the question, “Does this affect me?” with a clear yes or no (✅ or 🙅) and brief explanation.
  • Quick tips in response to “How can I fix it?” that don’t involve expensive tools or costly refactors.

1. SQL injection & NoSQL injection

TL;DR: This classic vulnerability is made possible by unsanitized and unvalidated user input, which allows attackers to run queries directly against your database. From there, they can extract data, modify records, or delete at will.

Does this affect me?

✅ if your app interacts with a SQL or NoSQL database at any point. Injection attacks have been around for decades, and automated attacks will immediately start to probe your endpoints with common exploits.

🙅 if you have no dynamic content based on database records. This could be because you’re entirely client-side, using a static site generator (SSG), or doing server-side rendering with a database but never accepting input from users.

How do I fix it? First and foremost, sanitize and validate all user input to eliminate unwanted characters or strings. Leverage open-source libraries and frameworks that allow for parameterized queries, and never concatenate user input into a database query. If you’re using Node.js, consider our open-source security engine Runtime, which autonomously projects you from SQL/NoSQL injection attacks and more.

2. Cross-site scripting (XSS)

TL;DR: XSS is another injection attack that allows an attacker to send a malicious script to another, potentially gathering their authentication credentials or confidential data.

Does this affect me?

✅ if your app accept user input and outputs it elsewhere as dynamic content.

🙅 if you don’t accept user input at all.

How do I fix it? As with SQL/NoSQL injection attacks, you should validate user input when you include said input inside the href attribute of anchor tags to ensure the protocol isn’t javascript. Take care when using JavaScript methods like innerHTML or React’s dangerouslySetInnerHTML, which can arbitrarily execute any code embedded into the string during output. Regardless of your approach, sanitize HTML output with open-source sanitizers like DOMPurify to send only clean, non-executable HTML to your users.

3. Server-side request forgery (SSRF)

TL;DR: SSRF attacks happen when a malicious actor abuses your app to interact with its underlying network, operating it like a proxy to jump to potentially more vulnerable or lucrative services.

Does this affect me?

✅ if your app interfaces with another service or API that performs a specific operation with user data—even if you’ve used allow lists to restrict traffic between only known and trusted endpoint.🙅 if you’re truly static.

How do I fix it? While a regex to validate IP addresses or hostnames is an okay start, it’s usually prone to bypasses like octal encoding. Two more reliable solutions are to use an allowlist and your platform’s native URL parser to restrict input to only safe and known hosts, and disabling redirects in the fetch requests. Depending on your framework, you can also freely leverage open-source projects—like ssrf-req-filter for Node.js—to properly refuse any requests to internal hosts.

4. Path traversal

TL;DR: This security flaw lets attackers access files and directories on your web server by reference files using ../ sequences or even absolute paths. Using sneaky tactics like double encoding, attackers can use framework-specific folder-file hierarchies or common filenames to find valuable information.

Does this affect me?

✅ Your app runs on a web server and includes references to the filesystem—no skirting around this one.

How do I fix it? Your first step is to remove any sensitive files, like any containing environment variables or secrets, from your web server’s root directory, and establish a process to prevent further slip-ups. 

be to never store sensitive files, like those containing environment variables or secrets, in your web server’s root directory. Also, don’t store these files in any folder meant to be publicly accessible, like the /static and /public folders of a Next.js project. Finally, strip ../ path separators and their encoded variants from user input.

Runtime also works fantastically well for path traversal… just saying.

5. XML eXternal Entity (XXE) injection

TL;DR: XXE attacks leverage a weakness in XML parsers that allows external entities, referenced by a document type definition (DTD), to be fetched and processed without validation or sanitization. The type and severity of the attack are limited mostly by the attacker’s skills and any OS-level security/permissions from your infrastructure provider.

Does this affect me?

✅ if you parse XML for any reason, including single sign-on authentication flows using SAML.

🙅 if you don’t have to deal with XML in your app!

How do I fix it? Disable external DTD resolving in your XML parser. You likely can’t refuse DTDs entirely, as it’s normal for some XML payloads to contain them—just don’t let your XML parser do anything with them.

6. Deserialization

TL;DR: Attackers can send malicious data through a deserialization function built into your app (like unserialize() from node-serialize) to execute code remotely, run a denial-of-service, or even create a reverse shell.

Does this affect me?

✅ if your app deserializes data directly from user interaction or through background functions/services like cookies, HTML forms, third-party APIs, caching, and more.

🙅 if you’re running a fully-static app with none of the above.

How do I fix it? In general, avoid deserializing user input (aka untrusted) data. If you must, only accept said data from authenticated and authorized users based on trusted signatures, certificates, and identity providers.

7. Shell injection/command injection

TL;DR: Your app passes user input directly to the underlying shell of the OS on which your web server and app executes, allowing attackers to execute arbitrary commands or traverse the filesystem, often with sufficient privileges to extract data or pivot to another system.

Does this affect me?

✅ if your app interacts with the filesystem or shell directly, such as a UNIX command like cat.

🙅 if you already use a framework API or method to safely pass arguments to the command you need to execute, or don’t need to interact with the filesystem/shell, such as in an SSG.

How do I fix it? Avoid accepting user input directly into commands or calling them directly. Instead, use your framework’s API/method, like child_process.execFile() in Node.js, which lets you pass arguments in a list of strings. Even with that protection, always run your apps with the least privileges necessary for the required business logic to prevent an attacker from “escaping” the web server and accessing root-only folders and files.

And yes, we’re back for one more friendly reminder to add Runtime to any Node.js project with one command (npm add @aikidosec/runtime || yarn install @aikidosec/runtime) to instantly protect your app against common shell/command injection attacks.

8. Local file inclusion (LFI)

TL;DR: LFI attacks involve tricking your app into exposing or running files on the system running your web server, which allows attackers to extract information or execute code remotely. While path traversal only allows attackers to read files, LFI attacks execute those files within your app, opening you up to a laundry list of vulnerabilities like remote code execution (RCE).

Does this affect me?

✅ if your app uses the path to a file as user input.

🙅 if your app doesn’t require users to supply paths to complete any action.

How do I fix it? Always sanitize user input to prevent the path traversal methods discussed above. If you must include files on the local filesystem beyond those typically found in “safe” /public or /static folders, use an allowlist to file names and locations that your app is permitted to read and execute.

9. Prototype pollution

TL;DR: This JavaScript-specific vulnerability lets an attacker manipulate your app’s global objects using __proto__. The new object is then inherited across your app, potentially giving them access to confidential data or further escalating their privileges.

Does this affect me?

✅ if you’re using JavaScript.

🙅 if you’re using anything but JavaScript! 

How do I fix it? Start by sanitizing keys from user input using allowlists or an open-source helper library. You can extend your protection by using Object.freeze() to prevent changes to a prototype, or even using the --disable-proto=delete flag offered with Node.js.

10. Open redirects

TL;DR: In this common vector for phishing, attackers craft a custom URL like https://www.example.com/abc/def?&success=false&redirectURL=https://example.phishing.com to trick your app into redirecting unsuspecting users to a malicious website. In addition, attackers can chain redirects together with other vulnerabilities for even more impact, leading to account takeovers and more.

Does this affect me?

✅ if your app redirects users to another page/view after completing an action, like sending them to example.app/dashboard after successful authentication.

🙅 if you’re still living that static-generated life.

How do I fix it? First, remove parameter-based redirects from your app and replace them with fixed redirects based on an allowlist of trusted domains and paths to which you can redirect users after they take specific actions. This might slightly degrade the user experience, but it’s a meaningful compromise to provide a secure experience, not one that leaves them blaming you for the strange expenses on their credit card statement.

What’s next?

If you’re feeling overwhelmed by the scope of attacks and all the work required to protect against them, know you’re not alone.

No one expects you to solve all these security problems and possible vulnerabilities yourself. SQL injection attacks alone have existed for decades, and folks are still finding CVEs in sophisticated apps, frameworks, and libraries all the time. That’s not to say you should also take these security problems with a grain of salt—if your app meets the ✅ for any of these top 10 security problems, you should start taking action.

Chances are you’re either using enterprise-grade (aka, expensive and complex) security tools, or have cobbled together a handful of open-source projects into a CI/CD pipeline or Git commit hooks and are hoping for the best. This could leave some security gaps, such as: 

  • How your app could be vulnerable due to less-than-ideal programming practices, insecure dependencies, and beyond.
  • Where the vulnerabilities are most likely hiding, down to single LOCs or entries in your package.json file.
  • Why you should fix certain vulnerabilities immediately and why others are lower priority.

Aikido Security helps to plug these gaps in 2 simple steps:

1. Scan your code with Aikido
Sign up (free, takes 2 min) and scan your repos. Get a focused list of critical vulnerabilities based on your app’s actual architecture and usage. See exactly what matters, get guided fixes, and get alerts for new issues in your latest commits.

2. Protect your Node.js apps with Runtime
Add our open-source Runtime to block injection, prototype pollution, and path traversal attacks at the server level—without the overhead of WAFs or agents. Runtime also sends real-time attack data back to Aikido so you can see what’s being targeted and prioritize fixes.

Now you’re off on the right foot, with a clearer picture as to:

  • How your app is vulnerable in more ways than you might have once thought.
  • Where you should focus your time and attention to fix the most critical issues first.
  • Why security and vulnerability scanning isn’t a one-time effort, but a continuous process.

Get secure for free

Secure your code, cloud, and runtime in one central system.
Find and fix vulnerabilities fast automatically.

No credit card required |Scan results in 32secs.