Skip to main content
Glama
README.md
<div align="center">

# Kelp

**Security scanner for vibe-coded apps.**
Finds the doors AI code generators leave open — hardcoded secrets, permissive
RLS, unauthenticated edge functions — and gates them out of your pull requests.

[![License: MIT](https://img.shields.io/badge/License-MIT-signal.svg?labelColor=0a0a0c&color=b8f2c9)](LICENSE)
[![CI](https://github.com/Mic52M/kelp/actions/workflows/ci.yml/badge.svg)](https://github.com/Mic52M/kelp/actions/workflows/ci.yml)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-signal.svg?labelColor=0a0a0c&color=b8f2c9)](CONTRIBUTING.md)
[![Deploy](https://img.shields.io/badge/kelp.build-live-signal.svg?labelColor=0a0a0c&color=b8f2c9)](https://kelp.build)

[Live app](https://kelp.build) · [Docs](docs/) · [CLI](docs/CLI.md) · [MCP server](docs/MCP.md) · [GitHub Action](https://github.com/kelp-security/kelp-action) · [Architecture](docs/ARCHITECTURE.md)

</div>

---

## What it does

Kelp scans an app's **backend surface** — Supabase (managed backends included),
edge functions, RLS policies, source tree — the way an attacker would. Every
finding is **evidence-gated**: a reviewer re-runs the reproduction before it
lands in your report, so what you see is what an attacker would actually get.

Four surfaces, one detection engine:

| Surface | For | How you use it |
|---|---|---|
| **CLI** [`kelp`](docs/CLI.md) | Local scans, CI shells, scripts | `npx @kelp-security/cli scan ./my-app` |
| **MCP server** [`kelp mcp`](docs/MCP.md) | Claude Code, Claude Desktop, Cursor, any MCP client | `npx @kelp-security/cli mcp` |
| **GitHub Action** [`kelp/check`](https://github.com/kelp-security/kelp-action) | Pull-request gating | `uses: kelp-security/kelp-action@v1` |
| **Hosted app** [kelp.build](https://kelp.build) | Continuous scanning, dashboard, PR fixes | Connect a repo, sign in with GitHub |

Zero configuration in the common case. The Action reads the workflow's
`GITHUB_TOKEN`, the hosted app installs a GitHub App, the CLI walks the
filesystem, the MCP server speaks stdio JSON-RPC to the LLM client.

## Quickstart — CLI

```bash
npx @kelp-security/cli scan ./my-app
```

```
kelp v0.1.0  ·  scanning ./my-app  ·  214 files walked

CRITICAL  src/lib/db.ts:14   VITE_SERVICE_ROLE — Supabase service_role JWT
HIGH      src/api/orders.ts  hardcoded Stripe secret (sk_live_…)
MEDIUM    supabase/config.toml  verify_jwt=false on get-order

3 findings · 8s · report at ./kelp-report.json
```

Add `--json` for machine-readable output, `--severity high` to filter, or see
[docs/CLI.md](docs/CLI.md) for the full reference.

## Quickstart, MCP server

Kelp implements the [Model Context Protocol](https://modelcontextprotocol.io) so
an LLM client (Claude Code, Claude Desktop, Cursor, or any MCP-compatible client)
can call Kelp mid-conversation, while it is writing code, instead of scanning
after the fact. Same static engine as the CLI, exposed as MCP tools, resources,
and slash commands over stdio. Runs locally, offline. No file content ever leaves
the machine.

Add to your client's MCP config (`~/.claude.json`, Claude Desktop config, or the
Cursor MCP settings):

```json
{
  "mcpServers": {
    "kelp": {
      "command": "npx",
      "args": ["-y", "@kelp-security/cli", "mcp"]
    }
  }
}
```

Restart the client, then ask the assistant to scan the repo, or use the
`/kelp:review-repo` slash command.

**MCP tools:** `scan_path`, `scan_snippet`, `list_rules`, `explain_finding`,
`explain_rule`. **Resources:** `kelp://rules`, `kelp://rules/{ruleId}`.
**Prompts (slash commands):** `/kelp:review-repo`, `/kelp:harden-file`.
Full guide, with per-client install snippets, in [docs/MCP.md](docs/MCP.md).

## Quickstart — GitHub Action

Add `.github/workflows/kelp-check.yml`:

```yaml
name: kelp/check
on:
  pull_request:
    branches: [main]
permissions:
  contents: read
  pull-requests: read
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: kelp-security/kelp-action@v1
```

Kelp will run on every PR, comment the verdict on the PR, and fail the check
when new **critical or high** findings are introduced against the base branch.
See [the action docs](https://github.com/kelp-security/kelp-action) for inputs
and required-status-check setup.

## What Kelp checks today

| Class | How | Output |
|---|---|---|
| **Secrets** in source | Provider patterns (AWS/GCP/Stripe/Supabase/…) + entropy fallback | Masked preview + line + severity |
| **Supabase RLS** | Reads schema + policies, flags tables open to `anon` | Proposed migration snippet |
| **Edge functions** | Replays without a JWT to detect `verify_jwt=false` | Function name + reproduction curl |
| **CORS + auth flows** | Reads config + auth callbacks for permissive defaults | Config diff |
| **BOLA** (opt-in, hosted only) | Active test with two user-provided test accounts | Human-review only, never auto-fix |

New detections land in [packages/core/src/scanners/](packages/core/src/scanners/).
See [docs/ADAPTERS.md](docs/ADAPTERS.md) for extending Kelp to other backends
(Firebase, Convex, PocketBase — see the [north-star issue](https://github.com/Mic52M/kelp/issues/45)).

## Architecture

Monorepo (npm workspaces). Three surfaces share one engine:

```
apps/
├─ web/           Next.js — hosted app at kelp.build
└─ cli/           kelp binary — standalone Node CLI
packages/
├─ core/          detection engine (pure, no I/O)
├─ worker/        scan pipeline + integrations (GitHub, Supabase, queue)
└─ db/            SQL migrations
```

The **core** is intentionally I/O-free: it takes `SourceFile[]` and returns
`Finding[]`. The CLI shells file-reads to it; the worker adds the GitHub App
plumbing; the web app adds auth, storage, and the reviewer loop.

Full breakdown: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).

## Evidence-gating

Kelp's most important invariant: **the model never decides a finding is real.**
Every agent-produced lead requires a reproduction (probe + expected observable,
or a source citation). The executor re-runs it and records the finding only if
the observable holds. Autonomy in reasoning, zero fabrication.

Read the full principle at [docs/EVIDENCE-GATING.md](docs/EVIDENCE-GATING.md).

## Contributing

PRs, bug reports, and new detection classes are welcome — see
[CONTRIBUTING.md](CONTRIBUTING.md) for the dev setup and the review checklist.
Security vulnerabilities go through [SECURITY.md](SECURITY.md), not the public
issue tracker.

Good first contributions:
- A new secret provider pattern in
  [`packages/core/src/scanners/secrets.ts`](packages/core/src/scanners/secrets.ts).
- A new edge-function heuristic in
  [`packages/core/src/agent/edge-functions.ts`](packages/core/src/agent/edge-functions.ts).
- Docs improvements — the tutorials in `docs/` are always in flight.

## License

MIT — see [LICENSE](LICENSE).

## Acknowledgements

Kelp exists because vibe-code tools ship a lot of the same footguns, and the
people using them shouldn't need a security team to catch them. Built by
[@Mic52M](https://github.com/Mic52M) — solo, in the open.

TDQS

A4.2/5.0

Scored across 5 tools

Disambiguation4/5

Each tool has a distinct core purpose: scanning paths vs snippets, listing rules, and explaining rules vs findings. The pairings scan_path/scan_snippet and explain_rule/explain_finding have some surface similarity, but descriptions clarify their boundaries.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case: scan_path, scan_snippet, list_rules, explain_rule, explain_finding. The naming is predictable and makes the toolset easy to navigate.

Tool Count5/5

Five tools is well-scoped for a security scanning server: two scan entry points, one rule catalog query, and two explanation helpers. Each tool serves a clear, non-redundant role in the workflow.

Completeness5/5

The toolset covers the full lifecycle expected of a static analysis scanner: discover rules, scan a path or snippet, retrieve rule details, and explain findings with remediation. There are no obvious missing operations for the stated domain.

Maintenance

ActivityActive
ResponsivenessResponsive