Aikido

Top 10 JavaScript Security Vulnerabilities in Modern Web Apps

Ruben CamerlynckRuben Camerlynck
|
#
#

Top 10 JavaScript Security Vulnerabilities

JavaScript powers a huge swath of modern applications – from dynamic web frontends to scalable Node.js backends – which means it also exposes a broad attack surface. The flexibility that makes JavaScript so powerful can turn into a double-edged sword when security is overlooked. Frontend code runs directly in users’ browsers (and can be inspected or manipulated by attackers), while backend Node.js applications often integrate countless packages and handle sensitive data. The ugly truth is that a single insecure line of JavaScript or a vulnerable dependency can open the door for exploits. In fact, recent industry reports show that web apps continue to be riddled with common vulnerabilities like cross-site scripting and outdated libraries, despite years of warnings.

Every script tag, every npm install, and every JSON parse could be hiding a potential risk. In the sections below, we break down the top ten JavaScript security vulnerabilities (spanning both client-side and server-side issues), with real-world examples and tips on how to fix or prevent them. From classic pitfalls like XSS to cutting-edge supply chain attacks, each vulnerability includes mitigation steps and a callout for how modern security tools (such as Aikido’s SAST, secrets detection, and dependency scanning) can help catch issues early.

1. Cross-Site Scripting (XSS) Attacks

Cross-Site Scripting (XSS) is one of the most prevalent vulnerabilities in we11b applications year after year. XSS occurs when an application includes unsanitized user input in a webpage, allowing attackers to inject malicious JavaScript that executes in the browsers of other users. This can lead to session hijacking, defacement, and theft of sensitive data. Even widely used libraries have suffered XSS flaws – for example, a five-year-old jQuery bug (CVE-2020-11023) allowed arbitrary code execution by passing malicious HTML to jQuery’s DOM methods. Unsuspecting developers who included a vulnerable jQuery (<3.5.0) version in their frontend exposed their users to potential XSS, a flaw so serious that U.S. CISA added it to its exploited vulnerabilities catalog in 2025.

Real-world example: An attacker might craft a comment or profile name containing <script> tags on a forum that doesn’t properly escape output. When other users view that page, the script runs in their browser – perhaps stealing their session cookie or impersonating them. Claranet’s 2024 security report found 2,570 instances of XSS (reflected and stored) across 500 penetration tests, making it “one of the most common vulnerabilities found… over the past five years”. This underscores that XSS remains a top threat in JavaScript-heavy apps.

Mitigation: Defending against XSS requires a combination of coding practices and browser defenses:

  • Escape and Validate Output: Never inject raw user input into HTML. Sanitize input on arrival and escape output in the proper context (HTML, attribute, JavaScript, etc.).
  • Use Framework Controls: Leverage templating or frontend frameworks (React, Angular, Vue) that automatically escape or sanitize content. Avoid using dangerous sinks like innerHTML or document.write with dynamic data – use safer alternatives like textContent.
  • Content Security Policy (CSP): Implement a strict CSP header to restrict where scripts can be loaded from. CSP can act as a second line of defense by blocking unauthorized scripts.
  • HttpOnly Cookies and SameSite: Mark cookies as HttpOnly (not accessible via JS) and use SameSite attributes to make some types of attacks (like cross-site scripting stealing cookies or CSRF) harder.

Catching XSS requires vigilance in code review and testing. Aikido’s static application security testing (SAST) can flag dangerous patterns – for example, usage of innerHTML with user-provided data or missing output encoding in server templates. Dependency scanning also helps: Aikido would alert you if you’re using an old library version known to enable XSS (like the jQuery 3.4.1 example above) so you can upgrade to a patched version. By integrating automated scans into your CI/CD, you can detect XSS vulnerabilities early, before attackers do.

2. Prototype Pollution

Prototype pollution is a JavaScript-specific vulnerability that leverages the dynamic nature of object prototypes. In JavaScript, objects inherit properties from their prototype, and if an attacker can inject properties into Object.prototype, those properties become accessible in all objects – often leading to denial of service or even remote code execution. Many popular libraries have suffered prototype pollution CVEs. For instance, Lodash versions before 4.17.12 had a vulnerability in its defaultsDeep and other functions that could be tricked into modifying Object.prototype via a crafted payload. Another example is Handlebars.js: versions <4.3.0 allowed template input to alter special properties like __proto__, which “may allow an attacker to execute arbitrary code” on the server (CVE-2019-19919).

Real-world example: An attacker submits JSON data to an API with a payload like {"__proto__": {"admin": true}}. If the application merges objects without guard (e.g. using an outdated lodash.merge or similar), the prototype chain gets polluted – subsequently, checks like if(user.admin) might unexpectedly return true for all users, or worse, application logic might be subverted. In some cases, prototype pollution can be combined with other techniques to execute code. For example, the “prototype poison” flaw in Handlebars templates mentioned above could be used to run server-side JavaScript in the context of the application.

Mitigation: To prevent prototype pollution:

  • Update Dependencies: Use fixed versions of libraries that have patched prototype pollution bugs. For example, upgrade Lodash to >=4.17.20 (which fixed multiple such CVEs).
  • Input Validation: Validate and sanitize JSON or object inputs. Reject or filter out object keys named __proto__, constructor, or prototypes in data.
  • Safe Object Merge: When merging objects (e.g. deep cloning or extending), use safe functions or libraries that do not copy prototype properties. Some utility libraries provide options to ignore inherited properties.
  • Run in Strict Mode: While not a silver bullet, strict mode ("use strict") can prevent certain hazardous actions and make bugs easier to catch.

Prototype pollution can be subtle, but dependency scanning is your friend here. Aikido’s dependency scanner will flag known vulnerable versions of libraries like Lodash, jQuery, or Handlebars that are susceptible to prototype pollution, so you can update them proactively. On the code side, Aikido’s SAST engine can detect patterns of unsafe object merging or usage of potentially dangerous object keys. By using Aikido to continuously audit both your code and your npm packages, you gain a safety net for this class of bug – catching it during development rather than after a breach.

3. Insecure Deserialization

Insecure deserialization flaws occur when an application accepts untrusted serialized data and deserializes it into objects without proper validation. In JavaScript/Node, this often involves functions that take user-supplied JSON or JavaScript objects and “revive” them into live objects. If not handled carefully, deserialization can be abused to execute arbitrary code or manipulate application state. A notorious example was the node-serialize package vulnerability (CVE-2017-5941): it allowed attackers to pass a malicious serialized object containing an Immediately-Invoked Function Expression (IIFE). Upon deserialization, the function would execute on the server, effectively achieving remote code execution.

Real-world examples: This issue isn’t theoretical – even major frameworks have gotten it wrong. In late 2025, a critical React/Next.js vulnerability (dubbed React2Shell, CVE-2025-55182) was disclosed, rooted in how React Server Components handle serialized data. “At the center of the issue is insecure deserialization,” noted Akamai’s research, which allowed attackers to inject malicious object keys leading to prototype pollution and ultimately remote code execution on the server. This means that by sending a specially crafted HTTP request, an unauthenticated attacker could take over a Node.js server running vulnerable React code – a nightmare scenario for any DevSecOps team.

Mitigation: Preventing insecure deserialization involves careful handling of data formats:

  • Prefer Safe Formats: Use JSON for data interchange and avoid parsing JavaScript code or functions from client input. Standard JSON.parse is safer than eval() or custom deserialization of JS objects.
  • Whitelisting & Validation: If you must accept serialized objects, implement strict schemas or whitelists. Only allow expected object properties and types. Reject any input containing keys like __proto__ or constructor that could be abuse vectors.
  • Avoid eval and Function(): Don’t use eval() on JSON or accept raw JS code from clients. Similarly, avoid libraries that execute object data (for instance, avoid automatically running functions that come from parsed input).
  • Library Updates: Stay updated on framework patches. The React vulnerability above was fixed by updates to React/Next – apply such patches immediately and monitor advisories for Node.js libraries that perform deserialization.

Aikido’s platform can help catch insecure deserialization in a few ways. Static code analysis will warn you if your code is using risky functions (like unserialize() from an outdated library or using eval on input). If you’re using known-vulnerable packages (like the buggy node-serialize <=0.0.4, or certain versions of React), Aikido’s dependency scanner would flag those by CVE. Additionally, Aikido’s runtime SAST analysis (if integrated in testing) can observe data flows – for example, user input flowing into a dangerous sink – and alert you. The bottom line: integrating such tools in CI means you’d catch something like React2Shell in your code before it becomes React2Shell in the news.

4. Cross-Site Request Forgery (CSRF)

Cross-Site Request Forgery (CSRF) is a classic web vulnerability that often affects JavaScript-backed apps (or any web app with sessions). Unlike XSS, which exploits code injection, CSRF exploits trust in the user’s browser. It allows an attacker to trick a victim’s browser into making unintended requests to your application, under the guise of the victim’s own credentials. In simpler terms, if a user is logged into your site, an attacker can potentially induce their browser (via a malicious link or image) to perform actions like changing account details or initiating transactions without the user’s consent.

Real-world example: A well-known example is the forum post/bank transfer analogy – imagine a banking app where the money transfer form is vulnerable to CSRF. An attacker could send a logged-in user a link (or embed an auto-submitting form on a malicious page) that triggers POST /transfer?amount=1000&to=attackerAccount. If the banking app has no CSRF protection, the user’s browser will dutifully send that request along with session cookies, and the bank will execute it thinking the user intended it. In the context of JavaScript, Single Page Applications (SPAs) might rely on APIs that use cookies for authentication; if those APIs don’t implement CSRF defenses (like requiring a token or same-site cookies), they are similarly exploitable. Even frameworks that include CSRF tokens can be misconfigured – e.g., if an Angular or React app’s backend sets an overly broad CORS policy or missing SameSite flags, CSRF attacks can sneak through.

Mitigation: Key strategies to stop CSRF include:

  • CSRF Tokens: Embed unpredictable tokens in forms or API calls and verify them server-side. Modern frameworks often have CSRF middleware. Ensure that tokens are tied to the user’s session and verified on every state-changing request.
  • SameSite Cookies: Set session cookies with the SameSite=Lax or Strict attribute. This restricts browsers from sending cookies on cross-site requests (the primary mechanism of CSRF). Notably, Strict might break some legitimate flows, so Lax is a balanced default for most apps.
  • Custom Headers & Verify Origin: For APIs (especially if using fetch/XHR in SPAs), you can require a custom header (e.g., X-Requested-With: XMLHttpRequest) and reject requests that don’t have it. Additionally, check the Origin and Referer headers on sensitive requests – ensure they come from your domain.
  • Avoid Using GET for State Changes: CSRF can use <img> or <script> tags to initiate GET requests. Ensure that any critical action (like modifying data) uses POST (or other non-GET methods), and ideally still requires a token.

While CSRF is more about design than code bug, Aikido’s security toolkit can still assist. Static analysis can detect routes or controllers lacking CSRF protections if you’re using common frameworks (for example, a missing csrf() middleware in an Express app, or no anti-CSRF module in use). Aikido can also scan your HTTP security headers and cookies configurations (via dynamic analysis or pipeline scripts) to flag missing SameSite or HttpOnly attributes. By integrating these checks, Aikido ensures that the secure coding habits (like implementing CSRF tokens and proper cookie flags) are consistently applied across your project.

5. NoSQL Injection

Just as traditional SQL databases suffer from SQL injection, modern JavaScript applications using NoSQL databases (like MongoDB, CouchDB, etc.) can be vulnerable to NoSQL injection. NoSQL injection occurs when an attacker manipulates inputs that are used in NoSQL queries, allowing them to alter queries, bypass authentication, or retrieve unauthorized data. Since NoSQL queries often use JSON or query objects, the syntax is different from SQL – but the concept of injecting parameters in unexpected ways still applies.

Real-world example: Consider a Node.js application using MongoDB for user authentication, with code like:

// insecure pseudo-codeUsers.findOne({ username: inputUser, password: inputPass })

This looks fine at first glance, but MongoDB queries accept objects and special operators. An attacker could submit a JSON payload for inputPass such as { "$ne": null }. The query becomes {username: "victim", password: { $ne: null } }, which in Mongo means “find a user with username ‘victim’ and a password that is not null” – essentially bypassing the password check because $ne: null is always true for a real password field. This kind of NoSQL operator injection is a known technique to bypass login forms. PortSwigger’s Web Security Academy documents how NoSQL injection can “enable an attacker to bypass authentication, extract or alter data, or even execute code on the server” in some cases.

Beyond authentication bypass, NoSQL injection can be used to extract data. For example, by injecting $regex or other operators, attackers might enumerate user records or dump databases if the application is not careful.

Mitigation:

  • Input Sanitization: Do not directly pass user-controlled data into database queries. Sanitize inputs – for instance, if expecting a string username, ensure it’s a string and doesn’t contain $ or other special characters. Some ORMs or driver libraries have built-in checks or modes to prevent operator injection (e.g., Mongoose can disable $ prefixed keys by default).
  • Use Parameterized Queries / ORM: Using an ORM or query builder can reduce direct exposure to raw queries. Ensure you use any available parameterization features.
  • Authentication & Query Logic: Don’t rely on only one condition for sensitive operations. For login, prefer a workflow that independently verifies the password (after retrieving user by username) rather than one big query that could be manipulated.
  • Logging and Monitoring: NoSQL injection attempts often leave traces (e.g., odd query patterns or errors). Log failed login attempts and unexpected query parameters; it might help detect an attack in progress.

Aikido’s static analysis can detect risky patterns like using

findOne()

or similar queries with unchecked user input. For example, Aikido could flag if it sees $ or regex characters being concatenated into a query string, or the use of raw Users.findOne({ ... user input ... }) without sanitization. Additionally, Aikido’s dynamic scanning (if you employ it against a running dev instance) can include specific tests for NoSQL injection, similar to how DAST tools test for SQLi. By leveraging these, developers get an early warning: “Hey, this login function might be vulnerable to a NoSQL injection.” Fixing it early saves you from a potentially disastrous authentication bypass in production.

6. Regular Expression Denial of Service (ReDoS)

Regular Expression Denial of Service (ReDoS) is a vulnerability where an attacker provides specially crafted input to a regex (regular expression) that takes an exceptionally long time to evaluate, monopolizing CPU and effectively causing a denial of service. JavaScript’s regex engine (like many others) can exhibit catastrophic backtracking on certain patterns. This is particularly relevant to Node.js, where a single thread handles many clients – a stuck regex can block the entire event loop. ReDoS vulnerabilities have been found in various npm packages and frameworks. For example, a low-severity but notable flaw was discovered in Vue.js 2’s template compiler (CVE-2024-9506): an improperly written regex for parsing HTML could be exploited by a malformed <textarea> or <script> tag to “cause significant delays in template parsing”. Similarly, the popular path-to-regexp library (used in Express routing) had a ReDoS issue (CVE-2024-52798), and countless validation libraries (for URLs, emails, etc.) have had ReDoS CVEs over the years.

Real-world example: Imagine a Node.js server that uses a regex to validate email addresses on user signup. A naive regex pattern (e.g., something like /(.+)@(.+)\.(.+)/) might catastrophically backtrack on a string of certain length and makeup. Attackers could send an extremely long email string like "aaaa....aaaa!" (with certain patterns) that causes the regex to grind for seconds or more, during which the server might not handle other requests. In one case, a ReDoS in the validator.js library’s URL validation was found – a crafted URL input of a few dozen kilobytes caused the process to hang. If an attacker automated sending such inputs en masse, they could effectively take down the service. The OWASP foundation notes that most regex engines are susceptible to these kinds of extreme cases.

Mitigation:

  • Avoid Complex Regex for Untrusted Input: Simplify your regex patterns or use non-backtracking approaches. If possible, use built-in libraries or vetted algorithms for common tasks (for example, use Node’s built-in URL parser instead of a complex regex for URLs).
  • Use Timeouts: For critical cases, you can use a regex library that supports timeouts or sandboxing. In Node, the RegExp operations are synchronous, but you could run regex work in a separate worker thread if needed to avoid blocking the main loop.
  • Limit Input Length: Often, ReDoS relies on very large input strings. By imposing reasonable length limits on inputs (e.g., no email address should be over 254 characters as per RFC), you reduce the feasibility of ReDoS.
  • Review and Test Patterns: Tools exist that can analyze regex for catastrophic backtracking potential. Incorporate those in code review for any complex pattern. Write test cases with pathological inputs to see how your regexes perform under stress.

Dependency scanning shines here – Aikido tracks known CVEs and weaknesses in your npm packages. If you’re pulling in a package with a known ReDoS (say a vulnerable version of a date parser or URL validator), Aikido will alert you to update to a fixed version. For custom regex patterns in your code, Aikido’s SAST can spot hard-coded regex literals or new RegExp() usage and apply heuristic checks (for example, flagging patterns with excessive quantifiers or nested groups). It may not catch every evil regex, but combined with Aikido’s knowledge base, it can warn “This regex looks suspiciously exponential.” Also, Aikido’s testing tools can simulate fuzzing attacks; if a simple payload causes performance issues, you’d learn about it during testing rather than from a pager at 2 AM.

7. Directory Traversal & File Exposure

Directory traversal (or path traversal) vulnerabilities allow attackers to access files on the server that were meant to be off-limits, by manipulating file paths. In Node.js, this often comes into play with libraries or code that serve static files, handle file downloads, or process zip archives. If user input is concatenated into file paths without proper sanitization, an attacker can use sequences like ../ to break out of the intended directory. For example, a vulnerability in the node-static package (a simple static file server) was discovered where an improper check in the servePath function allowed an attacker to request a URL with .. and access arbitrary files (CVE-2023-26111). A proof-of-concept showed an attacker could retrieve sensitive files like /root/.ssh/id_rsa by encoding ../../../../../ in the URL.

Real-world example: A common scenario is an Express app using express.static() or a custom file serve route. Suppose you have:

app.get('/download', (req, res) => {  const file = req.query.file;    res.sendFile(__dirname + '/uploads/' + file);});

If not careful, an attacker can call /download?file=../../etc/passwd and retrieve system files. There have been instances where applications inadvertently exposed keys or config files this way. Even when using libraries, there have been bugs: older versions of Express’s static middleware had known directory traversal issues on edge cases (like URLs with encoded dots). Node’s core path handling on Windows also had a traversal quirk (CVE-2025-27210) involving device names that could be abused. Beyond reading files, writing files is another angle (e.g., “Zip Slip” attacks where a zip archive extraction writes files outside the intended folder).

Mitigation:

  • Normalize and Validate Paths: Use path.normalize() and path.join() to resolve any .. sequences, and then ensure the resolved path is within the allowed directory. For instance, after resolving, reject the request if the file is outside your /uploads folder.
  • Avoid Direct User-Controlled Paths: Where possible, don’t directly use user input as filenames. Map user inputs to pre-defined file paths. For example, if users should only download their own files, use an identifier and look up the filename on the server side rather than trusting a filename parameter.
  • Least Privilege: Run your Node.js processes with minimal privileges. If the app has no reason to access outside certain directories, consider OS-level restrictions or containerization to limit the damage a traversal could do.
  • Keep Libraries Updated: If you use file-serving libraries or unzip libraries, stay updated on their security patches. The node-static vulnerability above had “no fix” in the older package, which might mean using an alternative library or adding your own patch.

Aikido’s scanning can detect common patterns of directory traversal in code. For example, the use of sendFile or readFile with req.query or req.params is a red flag that our SAST rules can highlight. Aikido also cross-references known vulnerabilities – if your project depends on a version of send or node-static with a CVE for path traversal, it will prompt you to update. For DevSecOps teams, Aikido’s strength is combining these signals: imagine it flags your file-serving code snippet as risky and notes that you’re using an outdated library for it – that insight can drive a quick remediation (sanitize input and bump the library version). Essentially, Aikido acts as an extra security reviewer, combing through your file access logic so that attackers can’t comb through your file system.

8. Vulnerable and Outdated Dependencies

Modern JavaScript applications often include dozens or hundreds of npm packages. Each of those dependencies (and their sub-dependencies) could harbor known vulnerabilities. Using outdated libraries is so common that it’s its own category of risk: insecure versions of frontend frameworks, Node modules, or utility libraries can expose your app to attacks even if your own code is fine. Claranet’s 2024 study found 1,032 instances of out-of-date JavaScript libraries in 500 apps, noting that “using out of date JavaScript can lead to XSS, Denial of Service attacks and sensitive information disclosure”. In other words, known CVEs in popular libraries translate directly into risks for your application if you haven’t updated them.

Real-world examples:

  • Lodash: Extremely popular utility library. Multiple CVEs (as discussed earlier) have affected Lodash – prototype pollution flaws (CVE-2018-16487, CVE-2019-10744, CVE-2020-8203) and even a Regular Expression DoS issue in _.escapeRegExp. Apps stuck on old Lodash versions inherited those vulnerabilities.
  • jQuery: Once ubiquitous on the frontend. jQuery <3.5.0 had that XSS vulnerability where injecting <option> tags could execute scripts. If your frontend still uses, say, jQuery 2.1 or 3.4, you’re carrying known XSS holes that attackers are actively exploiting.
  • Express and others: The Express framework itself has had a few CVEs (open redirects, a denial-of-service via malformed requests, etc.). Smaller packages like moment (date library) had a path traversal in certain usage (CVE-2022-24785), markdown-it had an XSS issue, and so on. Even core Node had vulnerabilities requiring patching (like the HTTP request smuggling and path traversal issues in 2022-2025).

Using vulnerable components is one of the OWASP Top Ten (Under “Using Components with Known Vulnerabilities”). It’s essentially a supply chain concern: if you bring in a library, you also bring its bugs.

Mitigation:

  • Dependency Scanning & Updates: Regularly run npm audit or similar tools to get a list of known vulnerabilities in your dependencies. Upgrade packages to patched versions. Use tools that alert you when new vulnerabilities are found in libraries you use.
  • Lockfile Hygiene: Maintain your package-lock.json (or Yarn lockfile) carefully. Avoid having unresolved, nested dependency issues by using npm audit fix where appropriate. If a sub-dependency is vulnerable and doesn’t update, consider overrides or contacting maintainers.
  • Minimal Dependencies: Don’t include packages you don’t need. Each extra dependency is another potential hole. E.g., if you only need a small function, it might be safer to implement it than pull in a 30-function library that you’ll have to trust and monitor.
  • Monitor Advisories: Stay aware of security advisories in the Node/JS ecosystem. Subscribe to Node security mailing lists or GitHub’s Dependabot alerts for your repositories.

This is where Aikido’s dependency scanning and AI-powered fixes truly shine. Aikido continuously scans your dependency tree against a vulnerability database. If a new CVE comes out for, say, Express or Lodash, you’d get a notification and even an automatic fix suggestion (e.g., “upgrade from Lodash 4.17.11 to 4.17.21 to patch CVE-2020-8203”). Developer-friendly tooling means it’s not just a report – Aikido can open a pull request with the updated version. Moreover, Aikido’s SafeChain capability (an in-app firewall for your package manager) can prevent installing known-malicious packages. By integrating these tools, your team can drastically reduce the window of exposure from when a library vulnerability is disclosed to when you remediate it in your app.

9. Malicious NPM Packages and Supply Chain Attacks

Not all attacks come from coding mistakes – some come from the code you thought you could trust. The npm ecosystem has suffered from supply chain attacks where attackers subvert the package supply to insert malicious code. This can happen through techniques like typosquatting (publishing a package with a name similar to a popular one, hoping someone mistypes or installs it by mistake), or by compromising maintainers of legitimate projects. One infamous incident was the event-stream attack in 2018: an attacker convinced the maintainer of event-stream (a widely used package) to hand over control, then released a new version that included a hidden dependency (flatmap-stream) containing malware. Over a couple of months, that malicious update was downloaded millions of times, and it specifically targeted a Bitcoin wallet app (Copay) to steal cryptocurrency keys.

Other examples include packages like ua-parser-js, node-ipc, and event-source-polyfill that were either hijacked by attackers or sabotaged by their own developers to deliver unwanted payloads (like spyware, coin miners, or destructive scripts). In 2021, security researchers demonstrated “dependency confusion” attacks – where if a company uses an internal package name and an attacker publishes a package with the same name to npm, build tools might pull the attacker’s version. These scenarios are particularly dangerous because they can give attackers remote code execution during your build or in production, without exploiting any traditional vulnerability.

Mitigation:

  • Verify Package Authenticity: Use package integrity hashes (npm automatically uses package-lock with sha512 hashes for packages – keep that lockfile committed). Consider enabling 2FA on npm accounts and prefer packages from trustworthy sources.
  • Lock Down Internal Dependencies: If you have private packages, ensure your registry or build process doesn’t accidentally grab from the public registry. Namespace internal packages or use scoped registries.
  • Monitor Install Scripts: Be wary of packages that have install/post-install scripts. Audit what those scripts do (some malicious packages use these to run harmful commands on install).
  • Use Security Tools: Leverage npm’s audit and other tooling to identify anomalies. For example, if a widely used package suddenly releases a new minor version after a long lull, treat it with scrutiny (as was the case with event-stream’s 3.3.6 release).
  • Principle of Least Privilege: When running builds or CI, run them in sandboxed environments. For production, consider mechanisms like Node’s --experimental-policy to control which modules can require what, or containerization to limit damage.

Aikido helps guard your software supply chain. Aikido SafeChain, for instance, can analyze package metadata and even the package content for malicious indicators. It can block installation of packages known to be compromised or that exhibit suspicious behavior (like obfuscated post-install scripts). Aikido’s threat intelligence feed keeps tabs on malware in open-source packages, so if tomorrow a popular library is hijacked, Aikido can warn you or prevent updates to the tainted version. Additionally, Aikido’s SAST can detect usage of sensitive operations in dependencies (like if a dependency suddenly starts executing shell commands or accessing network in an unexpected way). By integrating these tools in your pipeline, you add a strong layer of defense against the next event-stream style attack – essentially having an automated code reviewer for third-party code.

10. Hardcoded Secrets and Exposed Credentials

Hardcoding secrets (API keys, tokens, passwords) in your JavaScript code or config is a risky practice that unfortunately remains common. In frontend code, any secret (say an API key for a third-party service) is visible to the end-user and should be treated as public – but developers sometimes forget that and leave sensitive tokens in the JS bundle. In Node.js backend code or config files, secrets might get committed to git and end up in source control or in the deployed package. The exposure of secrets can lead to unauthorized access, account takeover, or costly bills (for example, if an attacker finds a cloud provider API key, they can spin up resources or dump your databases).

The scale of this issue is highlighted by research: in 2024 alone, nearly 23.8 million new hardcoded secrets were detected in public GitHub commits, a 25% increase over the previous year. High-profile breaches have occurred due to leaked credentials – for instance, a New York Times credentials leak and another at Sisense were traced back to secrets sprawl. Even in Docker images, thousands of API keys have been found inadvertently baked in. The takeaway: secret exposure is rampant and often the easiest way for attackers to get in without exploiting a software bug.

Real-world example: In 2019, a developer accidentally pushed a MongoDB connection string (with credentials) to a public GitHub repo. Within hours, attackers scanning GitHub found it, accessed the database, and held the data for ransom. In another case, mobile app developers left a Firebase private key in the app’s JavaScript – attackers extracted it and accessed user data on Firebase. These examples show that whether it’s in a .js file, a .env file committed by mistake, or anywhere in your codebase, secrets are low-hanging fruit for attackers if exposed.

Mitigation:

  • Never Hardcode Secrets: Use environment variables or a secrets management service. Your Node.js app can read from process.env at runtime, rather than having the secret in the source. For frontend needs, consider proxying requests through your backend so the secret isn’t exposed, or use OAuth flows that don’t require embedding secrets.
  • Git Ignore and Scanning: Don’t commit .env files or other secret-containing files. Use .gitignore to exclude them. Additionally, use secret scanning tools (GitHub has a built-in secret scanner for public repos, and third-party tools can scan commits) to catch any secret that does slip in.
  • Rotate Keys: In case of any suspicion that a secret leaked, rotate it immediately. Have a plan for key rotation and use separate credentials for different environments (so a dev leak doesn’t compromise prod, for example).
  • Vaults and Config Management: Use a proper secrets vault or cloud secret manager to store and fetch secrets at runtime, rather than storing them in config files.

Aikido includes secrets detection capabilities that continuously scan your code and configs for credential patterns. For instance, if someone accidentally commits an AWS access key or an API token, Aikido would flag it (even during a pull request) with a high-priority alert. It recognizes patterns and can also use context (e.g., a 40-character hex string in a config file might be flagged as a potential API key). Moreover, Aikido’s platform can integrate with version control to prevent secrets from ever reaching production – catching them in the CI pipeline. This is akin to having a guardian that checks “Are you sure you want to commit that key?”. In the event that a secret is found, Aikido can assist in assessing impact by identifying where that secret might have propagated and even suggesting remediation (like which keys to rotate). By employing such tooling, developers can commit to repos with confidence that they’re not inadvertently publishing the keys to the kingdom.

Conclusion

JavaScript’s strength – its ubiquity and flexibility from browser to backend – is exactly what makes securing it such a critical task. We’ve seen how easily a simple oversight (an unsanitized output, an outdated package, a leaked API key) can unravel the security of an application. The good news is that awareness and best practices go a long way: by understanding these top vulnerabilities, developers can avoid common mistakes like eval-ing untrusted data or leaving a door open via ../ in a path. Embracing a security-first mindset means validating inputs, encoding outputs, updating dependencies, and never assuming “nobody will notice my mistake” – because if you don’t catch it, an attacker eventually will.

Build security into your development workflow. Adopt secure coding habits (review the OWASP cheat sheets, use linters and type-checkers to catch issues early). And leverage integrated security tools that work alongside you – from static code analysis to dependency auditing and secret scanning. Solutions like Aikido allow you to bake these practices into your CI/CD pipeline, so every commit and build is checked for vulnerabilities automatically. By catching issues early and often, you reduce risk without slowing down. The world of JavaScript moves fast, but with the right safeguards in place, you can innovate just as fast without leaving your app exposed. Ship confidently and securely – your users and your DevSecOps team will thank you!

Continue reading:
Top 9  Docker Container Security Vulnerabilities    
Top 7 Cloud Security Vulnerabilities    
Top 10 Web Application Security Vulnerabilities Every Team  Should Know    
Top 9 Kubernetes Security Vulnerabilities and Misconfigurations    
Top Code Security Vulnerabilities Found in Modern  Applications    
Top 10 Python Security Vulnerabilities Developers Should Avoid    Top 9 Software Supply Chain Security Vulnerabilities Explained

4.7/5

Secure your software now

Start for Free
No CC required
Book a demo
Your data won't be shared · Read-only access · No CC required

Get secure now

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

No credit card required | Scan results in 32secs.