npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

gemsec-security-analyzer-mcp

v1.3.0

Published

MCP server for security analysis of NextJS/React TypeScript codebases

Readme

GemSec MCP Server

GemSec is a Model Context Protocol (MCP) tool that scans JavaScript/TypeScript codebases (Next.js/React friendly) for common security pitfalls, then produces actionable CLI and HTML reports with contextual snippets, debugging prompts, and deep links.

🚀 Quick Start

Configure in Cursor (Settings → Features → MCP Servers):

"gemsec-local": {
      "command": "npx",
      "args": [
        "-y",
        "gemsec-security-analyzer-mcp@latest"
      ]
    },

That's it! No cloning, no building, no manual setup. Just install and use.

Key Features

  • Recursive Analysis – Scan an individual file or an entire directory (skipping node_modules, dot folders, and non JS/TS extensions).
  • Rule Library – Detects XSS risks, missing CSRF tokens, hardcoded secrets, SQL injection patterns, weak crypto, insecure storage, and more (see src/config/securityPatterns.ts).
  • Rich Reporting
    • Terminal output with severity badges, code snippets, VS Code deep links, and suggested prompts for debugging.
    • Styled HTML report (reports/security-report-*/index.html) generated inside the root of the analyzed project.
  • Best Practices Helper – Quick reference guide for hardened Next.js/React deployments.

Security Patterns

GemSec scans for 14 common security vulnerabilities in JavaScript/TypeScript codebases. Each pattern is detected using regex-based matching and includes severity classification, detailed explanations, and actionable recommendations.

Pattern Overview

| Pattern Name | Severity | Description | |--------------|----------|-------------| | XSS - eval() | 🔴 Critical | Detects use of eval() which can execute arbitrary code | | Hardcoded Secrets | 🔴 Critical | Finds API keys, passwords, secrets, or tokens hardcoded in source code | | SQL Injection Risk | 🔴 Critical | Identifies SQL queries with string interpolation vulnerabilities | | XSS - dangerouslySetInnerHTML | 🟠 High | Detects unsafe HTML injection in React components | | Missing Input Validation | 🟠 High | Flags unvalidated user input from request parameters | | CORS Misconfiguration | 🟠 High | Finds CORS configured to accept all origins (*) | | Missing CSRF Protection | 🟠 High | Detects forms without CSRF token protection | | Weak Crypto | 🟠 High | Identifies use of weak hashing algorithms (MD5/SHA1) | | Insecure localStorage | 🟡 Medium | Flags use of localStorage for sensitive data storage | | Insecure Random | 🟡 Medium | Detects use of Math.random() for security-sensitive operations | | Insecure HTTP | 🟡 Medium | Finds HTTP URLs (should use HTTPS) | | Missing Security Headers | 🟡 Medium | Checks for missing CSP, X-Frame-Options, or HSTS headers | | Unsafe Redirect | 🟡 Medium | Detects redirects without URL validation | | Exposed Server Info | 🔵 Low | Finds X-Powered-By headers that expose server technology |

Detailed Pattern Descriptions

🔴 Critical Severity

XSS - eval()

  • Issue: eval() executes strings as JavaScript code, allowing arbitrary code execution
  • Risk: Remote code execution in browser or server if input comes from untrusted sources
  • Recommendation: Avoid eval(), use JSON.parse() or safer alternatives

Hardcoded Secrets

  • Issue: API keys, passwords, secrets, or tokens hardcoded in source code
  • Risk: Secrets exposed in repositories, build artifacts, or shared code can be used by attackers to access APIs, databases, or services
  • Recommendation: Use environment variables (.env) and never commit secrets to version control

SQL Injection Risk

  • Issue: SQL queries constructed with string interpolation instead of parameterized queries
  • Risk: Attackers can inject SQL code to read sensitive data, modify data, or gain remote code execution on the database server
  • Recommendation: Use parameterized queries or ORM like Prisma

🟠 High Severity

XSS - dangerouslySetInnerHTML

  • Issue: React's dangerouslySetInnerHTML allows direct HTML injection into DOM without sanitization
  • Risk: If content comes from user input or untrusted sources, attackers can inject malicious scripts leading to cookie theft, session hijacking, or defacement
  • Recommendation: Use DOMPurify for HTML sanitization or avoid innerHTML entirely

Missing Input Validation

  • Issue: User input from req.body, req.query, or req.params used without validation
  • Risk: Can lead to injection attacks (SQL, NoSQL, Command), type confusion, buffer overflow, or business logic bypass
  • Recommendation: Validate all input using libraries like zod or joi

CORS Misconfiguration

  • Issue: CORS configured to accept all origins (*)
  • Risk: Any website can make authenticated requests to your API, enabling CSRF attacks or unauthorized data access
  • Recommendation: Restrict CORS to trusted domains only

Missing CSRF Protection

  • Issue: Forms without CSRF token protection
  • Risk: Attackers can make requests on behalf of authenticated users, performing actions like changing passwords or deleting data without user knowledge
  • Recommendation: Implement CSRF tokens for all form mutations

Weak Crypto

  • Issue: Use of weak hashing algorithms (MD5/SHA1)
  • Risk: Vulnerable to collision attacks and too fast for password hashing; attackers can use rainbow tables or brute force
  • Recommendation: Use bcrypt, scrypt, or Argon2 for password hashing

🟡 Medium Severity

Insecure localStorage

  • Issue: Use of localStorage for storing sensitive data
  • Risk: Accessible by JavaScript in same origin (including XSS attacks); no httpOnly protection; tokens can be stolen if XSS occurs
  • Recommendation: Do not store tokens or sensitive data in localStorage; use httpOnly cookies instead

Insecure Random

  • Issue: Use of Math.random() for security-sensitive operations
  • Risk: Pseudo-random number generator is predictable; attackers can guess or predict generated values for tokens, session IDs, or cryptographic keys
  • Recommendation: Use crypto.randomBytes() or crypto.getRandomValues() for security

Insecure HTTP

  • Issue: HTTP URLs used instead of HTTPS
  • Risk: Data sent in plain text; attackers on same network can intercept, read, and modify communications including credentials and tokens
  • Recommendation: Use HTTPS for all communications

Missing Security Headers

  • Issue: Important security headers (CSP, X-Frame-Options, HSTS) may not be configured
  • Risk: More vulnerable to XSS, clickjacking, and man-in-the-middle attacks
  • Recommendation: Implement CSP, X-Frame-Options, and HSTS headers

Unsafe Redirect

  • Issue: Redirects without URL validation
  • Risk: Attackers can redirect users to malicious websites for phishing or to bypass security controls
  • Recommendation: Validate redirect URLs against a whitelist of domains

🔵 Low Severity

Exposed Server Info

  • Issue: X-Powered-By header exposes server technology information
  • Risk: Helps attackers find technology-specific vulnerabilities during reconnaissance
  • Recommendation: Disable X-Powered-By header to minimize information disclosure

Extending Security Patterns

To add new security patterns, edit src/config/securityPatterns.ts:

{
  name: "Your Pattern Name",
  pattern: /your-regex-pattern/g,
  severity: "high" | "medium" | "low" | "critical",
  message: "Brief description of the issue",
  recommendation: "Actionable fix suggestion",
  explanation: "Detailed explanation of the vulnerability and its risks"
}

Available MCP Tools

| Tool Name | Description | Arguments | |-----------|-------------|-----------| | analyze_file | Scan a single file | { "file_path": "/abs/path/to/file.tsx", "file_content"?: "..." } | | analyze_directory | Recursively scan a folder for JS/TS files | { "directory_path": "/abs/path/to/project", "files"?: [...] } | | get_security_best_practices | Returns the curated best-practices checklist | none |

Note: For remote MCP servers, you can provide file_content (for analyze_file) or files array (for analyze_directory) to send file contents directly instead of reading from filesystem.

Typical Workflow

  1. Start the MCP server

    • StdIO/CLI
      node ./build/index.js
    • Express + SSE backend
      npm start
      # or: PORT=4000 node ./build/httpServer.js
  2. Call analyze_directory

    For local server:

    {
      "name": "analyze_directory",
      "arguments": { "directory_path": "/Users/me/projects/test-project" }
    }

    For remote server (with file contents):

    {
      "name": "analyze_directory",
      "arguments": {
        "directory_path": "/Users/me/projects/test-project",
        "files": [
          {
            "path": "/Users/me/projects/test-project/src/App.tsx",
            "content": "// file content here..."
          }
        ]
      }
    }
  3. Open the HTML report

    • GemSec determines the project root (presence of package.json, .git, pnpm-workspace.yaml, or yarn.lock) and writes the report under <project>/reports/security-report-*/.
    • The CLI response includes the exact index.html path plus embedded VS Code links for each finding.

IDE / Cursor Integration

GemSec is an MCP server, so any MCP-aware IDE (such as Cursor) can invoke it directly.

Setup with StdIO (Manual/Development)

  1. Register the server in Cursor

    • Open Settings → Features → MCP Servers.

    • Add a new custom server with the following configuration:

      If installed globally:

      {
        "mcpServers": {
          "gemsec": {
            "command": "gemsec-mcp"
          }
        }
      }

      If installed locally:

      {
        "mcpServers": {
          "gemsec": {
            "command": "npx",
            "args": ["gemsec-mcp"]
          }
        }
      }

      Or with full path (if needed):

      {
        "mcpServers": {
          "gemsec": {
            "command": "node",
            "args": ["/absolute/path/to/node_modules/gemsec-mcp/build/index.js"]
          }
        }
      }
    • Name: gemsec

    • Save; restart Cursor if prompted.

  2. Prompting the assistant

    • Mention GemSec or the tool you want, e.g. "Run GemSec analyze_directory on src/features/log-activity" or "Use GemSec to analyze FormAddNewUser.tsx."
    • Cursor will surface the GemSec tools (analyze_file, analyze_directory, get_security_best_practices) in the tool picker.
  3. Handling results

    • The response includes a Markdown summary plus the HTML path. Open the index.html inside your project (e.g. …/reports/security-report-*/index.html).
    • Use the VS Code vscode://file/... links embedded in the text or HTML report to jump straight to the relevant lines.

Setup with SSE (Server-Sent Events)

To use SSE transport, you need to run the HTTP server first, then connect from the client using HTTP endpoints.

1. Running HTTP Server

# Build the project first
npm run build

# Run HTTP server (default port 3030)
npm start

# Or with a custom port
PORT=8080 npm start

Server will run at http://localhost:3030 (or the port you specify).

2. Verify Server is Running

# Test health endpoint
curl http://localhost:3030/healthz

# Response:
# {
#   "status": "ok",
#   "name": "GemSec",
#   "transport": "sse"
# }

3. Connect with Streamable HTTP Client

Streamable HTTP transport uses a single endpoint that handles both GET and POST:

  • GET/POST /mcp - Primary endpoint (modern standard)
    • GET: Opens SSE stream (server → client)
    • POST: Sends requests to server (client → server)
  • Legacy endpoints (for backward compatibility):
    • GET/POST /sse - Legacy SSE endpoint
    • POST /messages - Legacy message endpoint

Example using curl for testing:

# 1. Open SSE connection (will get sessionId from response headers)
curl -N http://localhost:3030/sse

# 2. In another terminal, send message (replace <sessionId> with ID from step 1)
curl -X POST http://localhost:3030/messages?sessionId=<sessionId> \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list",
    "params": {}
  }'

4. Configuration for Web-based MCP Clients

If you are using a web-based MCP client that supports SSE, the configuration is usually like this:

{
  "mcpServers": {
    "gemsec-streamable": {
      "type": "streamable-http",
      "url": "http://localhost:3030/mcp"
    }
  }
}

For remote deployment (with authentication):

{
  "mcpServers": {
    "gemsec-remote": {
      "type": "streamable-http",
      "url": "https://your-server.com/mcp",
      "headers": {
        "Authorization": "Bearer your-secret-token"
      }
    }
  }
}

For legacy SSE clients:

{
  "mcpServers": {
    "gemsec-sse": {
      "url": "http://localhost:3030/sse",
      "transport": "sse"
    }
  }
}

For legacy SSE with authentication:

{
  "mcpServers": {
    "gemsec-sse": {
      "url": "http://localhost:3030/sse",
      "transport": "sse",
      "headers": {
        "Authorization": "Bearer your-secret-token"
      }
    }
  }
}

Note: Cursor currently works better with StdIO transport. SSE transport is more suitable for:

  • Web-based MCP clients
  • Remote deployments (Azure, Docker, etc.)
  • Integration with HTTP-based tools
  • Multi-client scenarios

Development Guide

  • Source Layout
    • src/gemsecServer.ts – MCP server bootstrap (registers tools, handles routing, resolves project roots).
    • src/index.ts – StdIO entry point for CLI-oriented MCP clients.
    • src/httpServer.ts – Express + SSE transport so HTTP clients can connect over /sse and /messages.
    • src/services/securityAnalyzer.ts – Core scanner; reads files and applies regex-based rules defined in src/config/securityPatterns.ts.
    • src/reporters/*.ts – Text and HTML reporting pipelines.
    • src/types.ts – Shared interfaces (SecurityIssue, SecurityPattern, etc.).
  • Commands
    • npm run build – Compile TypeScript to build/.
    • npm run dev – TypeScript watch mode.
  • Extending Rules
    • Add new entries to securityPatterns.ts.
    • Each pattern requires a name, regex, severity, message, and recommendation.
  • Adding Tools
    • Update registerListToolsHandler + registerCallToolHandler in src/gemsecServer.ts.

Express + SSE Backend

The HTTP transport aligns with the Azure-ready blueprint described by Build5Nines for deploying TypeScript-based MCP servers with Express, Docker, and Azure Developer CLI [source].

📖 Complete SSE setup documentation: See SSE_SETUP.md for detailed guide.

  • Endpoints

    • GET/POST /mcp – Primary Streamable HTTP endpoint (modern standard). Handles both SSE streams (GET) and requests (POST) on a single endpoint.
    • GET/POST /sse – Legacy SSE endpoint (for backward compatibility).
    • POST /messages – Legacy message endpoint (for backward compatibility).
    • GET /healthz – Lightweight readiness probe that reports tool name and transport type.
  • Running locally

    npm start            # defaults to port 3030
    PORT=8080 npm start  # override the port
  • Quick Test

    # Test health endpoint
    curl http://localhost:3030/healthz
      
    # Expected: {"status":"ok","name":"GemSec","transport":"sse"}
  • Authentication (Optional)

    • By default, the server runs without authentication (suitable for local development)
    • To enable token-based authentication, set the GEMSEC_AUTH_TOKEN environment variable:
      GEMSEC_AUTH_TOKEN=your-secret-token npm start
    • Clients must include the token in requests:
      • Header: Authorization: Bearer your-secret-token
      • Or query parameter: ?token=your-secret-token
    • Note: "No stored tokens found" messages from the client are normal when authentication is disabled
  • Deployment hints

    • Expose the same port you pass through $PORT and ensure your ingress preserves SSE headers.
    • When scaling beyond a single replica (e.g., multiple Azure Container App pods), configure session affinity so /messages requests reach the pod that owns the /sse stream.
    • The included Dockerfile already produces a minimal Node 20 runtime suitable for ACA or other container targets.
    • For production deployments, consider enabling authentication via GEMSEC_AUTH_TOKEN.
    • See DEPLOYMENT.md for complete Docker deployment guide.

Output Anatomy

Each finding contains:

  • Severity & Type – e.g., HIGH — Missing CSRF Protection.
  • Line + Code – Source line and the specific snippet.
  • Context Block – Multi-line excerpt with highlighting for quick review.
  • Recommendation – Suggested remediation.
  • Debug Prompt – Plain-text instruction suitable for AI pair programming or issue tracking.
  • VS Code Deep Linkvscode://file/<path>:<line> to jump directly into the file.

Auto-Open Browser

When an HTML report is generated, it will automatically open in your default browser. This feature works on:

  • macOS: Uses open command
  • Windows: Uses start command
  • Linux: Uses xdg-open command

To disable auto-open, set the environment variable:

GEMSEC_NO_AUTO_OPEN=true npm start

If auto-open fails (e.g., no browser available), the report path will still be shown in the response, and you can open it manually.

Troubleshooting

  • Report path not under your repo? Ensure the analyzed directory contains a project marker (package.json, .git, etc.). GemSec walks up the filesystem until it finds one.
  • Missing findings? Only .ts, .tsx, .js, and .jsx files are scanned.
  • Custom report locations? Pass an absolute path via analyze_directory or analyze_file; GemSec will infer the nearest project root automatically.

Remote MCP Server Support

⚠️ Important: When using a remote MCP server (deployed in the cloud), the server cannot access files on your local filesystem by default. However, GemSec now supports sending file contents directly to the remote server!

Option 1: Send File Content Directly (Recommended for Remote Servers)

You can provide file contents directly in the tool call, allowing remote servers to analyze your local files:

For single file analysis:

{
  "name": "analyze_file",
  "arguments": {
    "file_path": "/Users/me/project/src/App.tsx",
    "file_content": "import React from 'react';\n\nexport default function App() {\n  return <div>Hello</div>;\n}"
  }
}

For directory analysis:

{
  "name": "analyze_directory",
  "arguments": {
    "directory_path": "/Users/me/project/src",
    "files": [
      {
        "path": "/Users/me/project/src/App.tsx",
        "content": "import React from 'react';\n\nexport default function App() {\n  return <div>Hello</div>;\n}"
      },
      {
        "path": "/Users/me/project/src/components/Button.tsx",
        "content": "export function Button() { return <button>Click</button>; }"
      }
    ]
  }
}

How it works:

  • The client reads files from the local filesystem
  • File contents are sent to the remote server in the tool call
  • The remote server analyzes the content without needing filesystem access
  • Results are returned with the original file paths for proper reporting

Option 2: Use Local MCP Server (Recommended for Local Development)

For local development, use StdIO transport with a local server:

{
  "mcpServers": {
    "gemsec": {
      "command": "node",
      "args": ["/absolute/path/to/security-analyzer-mcp/build/index.js"]
    }
  }
}

Option 3: Analyze Files on Remote Server

If your files are already on the remote server's filesystem, you can use the remote server directly with file paths:

{
  "name": "analyze_directory",
  "arguments": {
    "directory_path": "/remote/path/to/project"
  }
}

Best Practice:

  • Use Option 1 (file content) when you want to analyze local files with a remote server
  • Use Option 2 (local server) for local development (most efficient)
  • Use Option 3 (remote paths) when files are already on the remote server

Using mcp-remote with GemSec

If you're using npx mcp-remote to connect to a remote GemSec server (like in the PostHog example), here's what you need to know:

Configuration example:

{
  "mcpServers": {
    "gemsec-remote": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote@latest",
        "https://your-gemsec-server.com/sse",
        "--header",
        "Authorization:Bearer your-token"
      ],
      "env": {
        "GEMSEC_AUTH_TOKEN": "your-token"
      }
    }
  }
}

How it works:

  1. mcp-remote acts as a proxy between your local client and the remote GemSec server
  2. When you call analyze_file or analyze_directory, the AI assistant (Cursor) should read the local files and include their content in the tool call
  3. The remote server receives the file contents and can analyze them without needing filesystem access

Important Notes:

  • Works with smart AI assistants: If your AI assistant (like Cursor) can read local files and include file_content/files in tool calls, this will work seamlessly
  • ⚠️ Manual file reading: If the AI doesn't automatically read files, you may need to explicitly provide file contents
  • 💡 Recommendation: For local development, use a local StdIO server instead. Use mcp-remote when you want to leverage cloud resources or when analyzing files that are already on the remote server

Example tool call that works with mcp-remote:

{
  "name": "analyze_file",
  "arguments": {
    "file_path": "/Users/me/project/src/App.tsx",
    "file_content": "// AI assistant reads this from local file and includes it"
  }
}

License

MIT – see LICENSE (or add one if missing).