← Back to Security Testing

    Best Security Scanners for JavaScript, React & Node.js

    JavaScript runs everywhere -- browsers, servers, serverless functions, mobile apps. That ubiquity makes it the most targeted language for supply chain attacks, XSS exploits, and dependency vulnerabilities. Generic security scanners miss JavaScript-specific patterns. This guide covers the tools that actually understand your stack.

    Why JavaScript Apps Need Specialized Scanners

    JavaScript and its ecosystem have unique security characteristics that generic SAST tools handle poorly. Prototype pollution -- where attackers modify Object.prototype to inject properties across an entire application -- is a class of vulnerability that barely exists outside JavaScript. Tools built for Java or C simply do not have rules for it.

    React introduces its own surface area. The dangerouslySetInnerHTML prop is the most obvious vector for XSS, but subtler issues exist: unescaped URL parameters in href attributes can enable javascript: protocol attacks, and server-side rendering with unsanitized data creates hydration-based XSS that client-only scanners miss entirely.

    The npm ecosystem is the largest package registry in the world, with over 2.5 million packages. That scale means supply chain risk is not theoretical -- it is constant. Typosquatting, dependency confusion, and maintainer account takeovers hit npm packages every month. The event-stream incident, ua-parser-js compromise, and colors.js sabotage all demonstrated how a single compromised dependency can cascade to millions of downstream applications.

    Node.js on the server adds path traversal via fs.readFile(userInput), command injection through child_process.exec(), and server-side request forgery when HTTP clients accept user-controlled URLs. A scanner that understands the full JavaScript stack -- browser, server, and build tooling -- catches issues that language-agnostic tools miss.

    npm audit and GitHub Dependabot

    Every Node.js project already has a security scanner built in. Running npm audit checks your dependency tree against the GitHub Advisory Database and reports known vulnerabilities with severity ratings. It is free, requires zero setup, and runs in under a second on most projects.

    What npm audit catches: Known CVEs in direct and transitive dependencies, including prototype pollution in lodash, ReDoS in validator packages, and arbitrary code execution in build tools. The npm audit fix command can automatically update to patched versions when semver-compatible fixes exist.

    GitHub Dependabot goes a step further by automatically opening pull requests when new advisories are published. It also handles version updates on a schedule, keeping dependencies current before vulnerabilities are discovered. Enable it by adding a dependabot.yml file to your repository's .github directory.

    Limitations: Both tools only scan dependencies, not your application code. They cannot detect XSS in your React components, prototype pollution in your own utility functions, or insecure configurations in your Express middleware. They also lag behind zero-day disclosures -- a vulnerability must be reported to the advisory database before these tools flag it. Use npm audit as a baseline, not as your entire security strategy.

    ESLint Security Plugins

    ESLint is already running in most JavaScript projects for code style. Adding security plugins turns it into a lightweight SAST scanner that catches vulnerabilities during development, before code reaches CI.

    eslint-plugin-security is the most established option, with rules for detecting eval() usage, non-literal require() calls, non-literal regular expressions (ReDoS risk), and object injection via bracket notation with user input. Install with npm install eslint-plugin-security --save-dev and add "plugin:security/recommended" to your ESLint config.

    eslint-plugin-no-unsanitized (maintained by Mozilla) detects direct DOM manipulation methods like innerHTML, outerHTML, and document.write() that accept unsanitized input. This is particularly valuable in codebases that mix React with vanilla DOM manipulation.

    React-specific rules: The built-in react/no-danger rule flags dangerouslySetInnerHTML, while react/jsx-no-target-blank catches missing rel="noreferrer" on external links. Combine these with eslint-plugin-security for broad coverage of both React-specific and general JavaScript vulnerabilities.

    The main advantage of ESLint security plugins is developer experience. Findings appear as squiggly lines in VS Code, not as CI failures twenty minutes later. The downside is that ESLint operates on single files without cross-file dataflow analysis, so it cannot trace tainted data from an API endpoint through middleware into a database query. For that, you need Semgrep or Snyk.

    Snyk for JavaScript Projects

    Snyk has the deepest npm integration of any commercial security platform. Running snyk test in a Node.js project scans your lockfile, identifies vulnerable packages, and shows the dependency path that introduced each vulnerability. Unlike npm audit, Snyk adds reachability analysis -- it checks whether your code actually calls the vulnerable function, dramatically reducing false positives.

    Snyk Code for JavaScript: Beyond dependencies, Snyk Code provides SAST analysis specifically tuned for JavaScript and TypeScript. It detects XSS in React components, SQL injection in Node.js database queries, path traversal in Express route handlers, and hardcoded secrets in configuration files. Results appear as inline PR comments with fix suggestions.

    .snyk policies: Create a .snyk file in your project root to ignore specific findings, set custom severity thresholds, or apply patches to vulnerabilities that do not have official fixes yet. This prevents false positive fatigue while maintaining a clean security posture.

    PR checks: Enable Snyk's GitHub integration to automatically scan every pull request. New vulnerabilities block the merge, while existing (already-tracked) issues pass through. This prevents security debt from growing without blocking developer velocity on known issues being addressed.

    The free tier includes 200 tests per month across dependency and code scanning, unlimited projects for open-source repositories, and basic reporting. For most startups and small teams, the free tier covers everything. Paid plans start at $25/developer/month and add priority support, advanced reporting, and higher test limits.

    Semgrep Rules for React and Node

    Semgrep's pattern-matching approach is particularly effective for JavaScript because the language's dynamic nature creates patterns that dataflow-based analyzers struggle with. You can write a Semgrep rule to detect any code pattern in minutes, without building an AST plugin or understanding compiler internals.

    React-specific rules: The Semgrep Registry includes rules for detecting XSS via dangerouslySetInnerHTML with unsanitized variables, insecure use of useEffect with external data that bypasses sanitization, URL injection through window.location manipulation, and server-side rendering pitfalls where user data gets embedded in the initial HTML payload without encoding.

    Node.js rules: Semgrep ships rules for path traversal via unsanitized file system operations, command injection through child_process with user input, SSRF in HTTP client libraries (axios, node-fetch, got), SQL injection in raw query builders, and insecure JWT verification that accepts algorithm: "none".

    Custom rules: The real power of Semgrep is writing rules specific to your codebase. If your team uses a custom ORM, write a rule that flags raw SQL queries outside the ORM. If you have an internal sanitization library, write a rule that detects when developers bypass it. Custom rules are YAML files that live in your repository and run alongside the community ruleset.

    Run Semgrep locally with semgrep --config=p/javascript --config=p/react --config=p/nodejs . to scan your entire project against all JavaScript-related community rules. Scanning typically completes in under 30 seconds for projects with 50,000 lines of code.

    Setting Up a JavaScript Security Pipeline

    The most effective approach combines multiple tools in a single GitHub Actions workflow. Each tool covers a different attack surface: npm audit for known dependency CVEs, Semgrep for code-level vulnerabilities, and Snyk for reachability-aware dependency analysis with automatic fix PRs.

    name: JavaScript Security Scan
    on:
      pull_request:
        branches: [main]
    
    jobs:
      security:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
    
          - uses: actions/setup-node@v4
            with:
              node-version: '20'
    
          - run: npm ci
    
          - name: npm audit
            run: npm audit --audit-level=high
            continue-on-error: true
    
          - name: Semgrep
            uses: semgrep/semgrep-action@v1
            with:
              config: >-
                p/javascript
                p/react
                p/nodejs
                p/security-audit
            env:
              SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
    
          - name: Snyk
            uses: snyk/actions/node@master
            with:
              args: --severity-threshold=high
            env:
              SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

    Pipeline strategy: Run npm audit with continue-on-error: true so it reports but does not block merges on medium-severity dependency findings (which are often transitive and outside your control). Semgrep runs next and blocks on any finding above the configured severity. Snyk runs last with --severity-threshold=high to catch only critical dependency issues that npm audit may have missed due to advisory database timing.

    Local development: Add ESLint security plugins for instant feedback in the editor. Run Semgrep as a pre-commit hook with semgrep --config=p/javascript --error so developers catch issues before pushing. This shifts security left without slowing down CI.

    Total setup time is under 15 minutes. The npm audit step requires no configuration. Semgrep needs a free account for the app token (or skip the token for anonymous scanning with rate limits). Snyk requires a free account and token. Once configured, every pull request gets scanned automatically with results appearing as PR comments and check status updates.

    Related Resources

    Scan Your JavaScript App in Seconds

    VibeEval combines SAST, dependency scanning, and AI-aware security testing for JavaScript, React, and Node.js projects. Catch XSS, prototype pollution, and supply chain vulnerabilities before they ship.

    Start Free Security Scan