Skip to main content
Glama
EthYusuf

shipsafe-mcp

Official
by EthYusuf
README.md
# πŸ›‘οΈ ShipSafe

**Find the security holes your AI coding assistant just shipped, before someone else does.**

ShipSafe is an MCP server and CLI that checks AI-built ("vibe-coded") web and mobile apps for the mistakes that keep leaking data: API keys in the browser bundle, Supabase tables without Row Level Security, Firebase rules left in test mode, API routes anyone can call, unverified Stripe webhooks, AI endpoints that can drain your credits, and npm packages the model made up.

It plugs into Claude Code, Cursor, VS Code, Windsurf and Claude Desktop. Your assistant scans the project, explains each problem in plain language, fixes it, and re-scans to confirm.

[![Install in Cursor](https://img.shields.io/badge/Cursor-Install_MCP-000?logo=cursor)](https://cursor.com/en/install-mcp?name=shipsafe&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyJzaGlwc2FmZS1tY3AiXX0=)
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install_MCP-0098FF?logo=visualstudiocode)](https://insiders.vscode.dev/redirect/mcp/install?name=shipsafe&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22shipsafe-mcp%22%5D%7D)
[![PyPI](https://img.shields.io/pypi/v/shipsafe-mcp)](https://pypi.org/project/shipsafe-mcp/)
[![CI](https://github.com/EthYusuf/shipsafe/actions/workflows/ci.yml/badge.svg)](https://github.com/EthYusuf/shipsafe/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

---

## What it looks like

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="docs/images/report-dark.png">
    <img src="docs/images/report-light.png" alt="ShipSafe HTML report: launch readiness 0/100, grade F, six critical findings with plain-language impact, fix and a Copy fix prompt button" width="880">
  </picture>
</p>
<p align="center"><sub>The shareable HTML report (<code>shipsafe scan . --format html</code>). Every finding has a <b>Copy fix prompt</b> button for your AI assistant.</sub></p>

A typical conversation in Claude Code or Cursor:

> **You:** Is my app safe to launch?
>
> **Assistant:** I ran ShipSafe on your project. **Launch readiness: 0/100 (F), do not ship yet.** Six issues can be exploited by anyone on the internet:
>
> 1. **Your OpenAI key is public.** `NEXT_PUBLIC_OPENAI_API_KEY` is baked into the JavaScript every visitor downloads, so anyone can copy it and run up your bill.
> 2. **Anyone can read and delete your `posts` table.** It was created without Row Level Security, and your anon key ships with the site.
> 3. **Anyone can fake a payment.** `/api/webhook` trusts `checkout.session.completed` events without checking Stripe's signature.
> 4. …
>
> Should I fix these, starting with the most severe?

After the fixes, the assistant calls `verify_fixes`, which returns what was fixed, what is still open, and anything new the edits introduced:

<p align="center">
  <img src="docs/images/verify.png" alt="verify_fixes result: score 0 to 69, 21 fixed, 0 new, 2 remaining (an SSRF and missing security headers)" width="880">
</p>

The same scan works from the terminal and in CI:

<p align="center">
  <img src="docs/images/terminal.png" alt="shipsafe scan terminal output: launch readiness 0/100 (F) with critical findings, redacted evidence and fix guidance" width="880">
</p>

<sub>All screenshots are real output from scanning the intentionally vulnerable demo app in <a href="tests/fixtures/nextjs-supabase">tests/fixtures/nextjs-supabase</a>. Keys are shown redacted, exactly as ShipSafe prints them.</sub>

## Install

ShipSafe runs with [uv](https://docs.astral.sh/uv/getting-started/installation/) (`uvx`), so there is nothing to install globally. Python 3.10+ is fetched automatically if you don't have it.

**Claude Code**

```bash
claude mcp add shipsafe -- uvx shipsafe-mcp
```

**Cursor**: click the badge above, or add to `~/.cursor/mcp.json`:

```json
{ "mcpServers": { "shipsafe": { "command": "uvx", "args": ["shipsafe-mcp"] } } }
```

**VS Code (Copilot agent mode)**: click the badge above, or add to `.vscode/mcp.json`:

```json
{ "servers": { "shipsafe": { "command": "uvx", "args": ["shipsafe-mcp"] } } }
```

**Windsurf** (`~/.codeium/windsurf/mcp_config.json`) and **Claude Desktop** (`claude_desktop_config.json`) use the same `mcpServers` block as Cursor. Claude Desktop may need the absolute path to `uvx` (`which uvx` / `where uvx`).

**Before the PyPI release**, install straight from GitHub:

```bash
claude mcp add shipsafe -- uvx --from git+https://github.com/EthYusuf/shipsafe shipsafe-mcp
```

Then ask your assistant: *"Run a ShipSafe pre-launch audit"*, or use the `pre-launch-audit` prompt.

## What it catches

68 rules, written for the stacks AI tools actually generate: **Next.js, React/Vite, Expo/React Native, Express/Hono/Fastify, Supabase, Firebase, Stripe, OpenAI/Anthropic/Vercel AI SDK, Flask/Django/FastAPI**.

| Area | Examples |
|---|---|
| πŸ”‘ **Leaked secrets** | Keys behind `NEXT_PUBLIC_` / `VITE_` / `EXPO_PUBLIC_`, keys hardcoded in client components or `app.json`, Supabase `service_role` in the browser, `JWT_SECRET \|\| "secret"` fallbacks, `.env` committed or not ignored, 25+ provider key formats |
| πŸ—„οΈ **Supabase & Firebase** | Tables without RLS, `using (true)` policies, `SECURITY DEFINER` without `search_path`, public buckets, Firestore/RTDB rules open to everyone or still in test mode, edge functions using `service_role` without checking the caller |
| πŸšͺ **Access control** | Route handlers, Pages API routes, Express routes and **server actions** with no auth check; **IDOR**, where the user id comes from the request body instead of the session; `jwt.decode` without verification; `alg: none` |
| πŸ’‰ **Injection** | SQL built with template strings, Supabase `.or()` filter injection, MongoDB operator injection, command injection, `eval`, path traversal, SSRF, open redirects, unsanitized `dangerouslySetInnerHTML` / `innerHTML` / `v-html` |
| πŸ’³ **Payments** | Stripe webhooks without `constructEvent`, prices taken from the client |
| πŸ€– **AI apps** | LLM calls from the browser (`dangerouslyAllowBrowser`), AI endpoints without auth or rate limits ("denial of wallet"), model output passed to `eval`, SQL or shell |
| πŸ“± **Mobile** | Tokens in AsyncStorage/localStorage, permissive WebViews, `android:debuggable`, cleartext traffic, iOS ATS disabled |
| πŸ“¦ **Supply chain** | **Hallucinated packages** that don't exist on npm/PyPI (slopsquatting), typosquats, packages published days ago, known CVEs via OSV.dev with the right upgrade version |
| 🌐 **Live site** *(opt-in)* | Downloadable `/.env` and `/.git`, secrets in served JS bundles, **Supabase tables readable with your public anon key**, open Firebase RTDB, CORS reflection, cookie flags, security headers, source maps |

The full list with explanations is in [docs/rules.md](docs/rules.md).

## MCP tools

| Tool | What it does |
|---|---|
| `scan_project` | Scans the project and returns a launch-readiness score, a verdict and the top findings in plain language |
| `list_findings` | Pages through findings, filtered by severity, category or file |
| `get_finding` | Full detail for one finding: impact, fix, redacted code context, and a ready-made fix prompt |
| `verify_fixes` | Re-scans and reports what was fixed, what's new and how the score changed |
| `scan_snippet` | Checks code *before* it is written to disk; the assistant can call it on auth, payment and database code |
| `check_dependencies` | Hallucinated, typosquatted, brand-new and vulnerable dependencies |
| `probe_live` | Passive checks against a deployment you own (localhost is always allowed) |
| `generate_report` | Writes an HTML, Markdown, SARIF or JSON report to `.shipsafe/`, which is git-ignored automatically |

Also available: the prompts `pre-launch-audit` and `secure-feature`, and the resources `shipsafe://rules` and `shipsafe://report/latest`.

## CLI and CI

```bash
uvx --from shipsafe-mcp shipsafe scan .                        # colored terminal report
uvx --from shipsafe-mcp shipsafe scan . --format html -o report.html
uvx --from shipsafe-mcp shipsafe scan . --fail-on high         # exit 1 for CI
uvx --from shipsafe-mcp shipsafe probe http://localhost:3000   # live checks
uvx --from shipsafe-mcp shipsafe rules
```

**GitHub Actions** posts results to code scanning and to the job summary:

```yaml
permissions:
  contents: read
  security-events: write
steps:
  - uses: actions/checkout@v4
  - uses: EthYusuf/shipsafe@v0.1.0
    with:
      fail-on: high
```

**pre-commit**:

```yaml
repos:
  - repo: https://github.com/EthYusuf/shipsafe
    rev: v0.1.0
    hooks:
      - id: shipsafe
```

## Configuration

Silence a single line, optionally for one rule only:

```ts
const demoKey = "sk_test_…"; // shipsafe-ignore: secret.hardcoded
```

Or add `.shipsafe.yml` at the project root:

```yaml
ignore_paths: ["scripts/", "**/*.stories.tsx"]
disable_rules: [config.missing-security-headers]
severity_overrides:
  supabase.public-bucket: info
```

## Safety and privacy

A security tool must not become a leak itself.

- **No code is executed.** JavaScript and TypeScript are parsed with tree-sitter and Python with `ast`. Nothing is imported, run or installed.
- **Secrets are always redacted** in everything ShipSafe outputs (`sk-proj-****1Cx7`), so raw keys never reach your AI provider's logs. The test suite checks this for every output format.
- **Network access is limited and optional.** Dependency checks call registry.npmjs.org, pypi.org and api.osv.dev with package names and versions only. `--offline` / `offline: true` turns them off.
- **Live probes only send plain GET requests.** They run against localhost by default. Any other host needs your explicit confirmation (the MCP server asks you directly when your client supports it) or `SHIPSAFE_PROBE_ALLOWLIST`. Row data read from Supabase or Firebase is never returned, only table and column names.
- **No telemetry.**

## Accuracy, honestly

ShipSafe is a heuristic static analyzer. It finds *likely* issues fast, and it is not a penetration test.

- **Labeled corpus.** `benchmarks/run.py` scans realistic vulnerable apps (Next.js + Supabase, Expo + Firebase, Express + MongoDB, Flask) plus a correctly built app. Every labeled issue is found, the clean app scores 99/A, and a typical scan takes ~50–300 ms offline. We wrote this corpus ourselves, so treat it as a regression suite, not proof of real-world accuracy.
- **Real projects.** Before release we ran ShipSafe on popular open-source apps and fixed every false positive we found. For example, the official Vercel Supabase + Stripe starter scores 93/A, and its remaining findings match what Supabase's own database linter reports.
- **Known limits.** Taint tracking stays within a function (plus variable aliases), not across files. Authorization is inferred from common patterns (`auth()`, `getUser()`, middleware…), so custom auth wrappers may need a `shipsafe-ignore`. Native Swift/Kotlin/Dart source is not analyzed; manifests and configs are.

Found a false positive or a miss? Please [open an issue](https://github.com/EthYusuf/shipsafe/issues) with a minimal snippet. Every fix gets a regression test.

## Development

```bash
git clone https://github.com/EthYusuf/shipsafe && cd shipsafe
uv sync
uv run pytest            # full test suite, including an in-process MCP client
uv run ruff check src tests
uv run python benchmarks/run.py
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for how rules are structured and how to add one.

## License

MIT

TDQS

A4.3/5.0

Scored across 8 tools

Disambiguation4/5

Each tool has a clear primary purpose: scanning project/snippet/live, listing/getting findings, verifying fixes, checking dependencies, and generating reports. Minor overlap exists between scan_project and check_dependencies (and verify_fixes re-scans), but descriptions are specific enough to avoid serious misselection.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in lowercase snake_case: scan_project, list_findings, get_finding, verify_fixes, scan_snippet, check_dependencies, probe_live, generate_report. There are no mixed conventions or vague verbs.

Tool Count5/5

Eight tools is well-scoped for a security scanning server. Each tool covers a distinct stage of the workflow: scanning, inspecting findings, verifying fixes, live probing, dependency checks, and reporting, with no redundant or unnecessary additions.

Completeness4/5

Core coverage is solid: scanning (project, snippet, live, dependencies), finding inspection (list, get), verification, and reporting. Minor gaps include the inability to dismiss/mark findings as false positives or view scan history, but these are not critical to the primary launch-readiness workflow.

Maintenance

ActivityMaintained
ResponsivenessNo issues