# Lurkr

> Pre-deploy static scanner for risky AI agent capabilities. Local-only. No telemetry. No network calls during scan. Redacted output. MIT.

- **Type:** MCP server
- **Install:** `agentstack add mcp-agentveil-protocol-lurkr`
- **Verified:** Pending review
- **Seller:** [agentveil-protocol](https://agentstack.voostack.com/s/agentveil-protocol)
- **Installs:** 0
- **Category:** [Developer Tools](https://agentstack.voostack.com/c/developer-tools)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [agentveil-protocol](https://github.com/agentveil-protocol)
- **Source:** https://github.com/agentveil-protocol/lurkr
- **Website:** https://agentveil.dev

## Install

```sh
agentstack add mcp-agentveil-protocol-lurkr
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

Lurkr

Find what your agent can touch before you deploy it.

Lurkr is a static, local-only scanner for risky AI-agent and GitHub-workflow
capability surfaces. It runs before deployment, does not execute project code,
does not make network calls during scan, and redacts sensitive output.

## New in v0.4.0

Lurkr now includes a high-severity FastAPI / Starlette BadHost detector:

- Rule: [`agent.python_fastapi_path_auth_no_host_validation`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.python_fastapi_path_auth_no_host_validation.md)
- Flags middleware that reads `request.url.path` for path-based security decisions without same-file `TrustedHostMiddleware` evidence.
- Covers Starlette BadHost risk [GHSA-86qp-5c8j-p5mr / CVE-2026-48710](https://github.com/Kludex/starlette/security/advisories/GHSA-86qp-5c8j-p5mr), fixed upstream in Starlette `1.0.1`.
- See [Detection Scope](#detection-scope) and [Triaging Findings](#triaging-findings).

## GitHub Actions

```yaml
- uses: agentveil-protocol/lurkr@v0.4.0
  with:
    path: "."
    output: lurkr-report.json
    fail-on: high
```

Omit `fail-on` for review-only mode. Use SARIF output with GitHub Code
Scanning when you want findings in the Security tab.

[Local CLI](#local-cli) |
[Privacy & data handling](#privacy--data-handling) |
[What a finding looks like](#what-a-finding-looks-like) |
[Detection scope](#detection-scope) |
[Full Action usage](#use-as-a-github-action) |
[Why this exists](#why-this-exists)

---

## Local CLI

```bash
pip install lurkr
lurkr scan --path . --output report.json
cat report.json
```

That is the whole flow. The scanner is read-only: it does not modify your
files, run your code, or send data over the network.

Python agent detection is enabled for bounded `.py` source analysis.
FastAPI / Starlette middleware detection is enabled for BadHost-style
path-auth risk: Lurkr flags security middleware that reads
`request.url.path` without same-file `TrustedHostMiddleware` evidence.
Bounded TypeScript / JavaScript MCP analysis is enabled for canonical
Model Context Protocol `registerTool` handler shapes; see
[Detection scope](#detection-scope) for the exact patterns covered.

To fail CI when findings meet a threshold, add `--fail-on`:

```bash
lurkr scan --path . --output report.json --fail-on high
```

For existing repositories, create a baseline first so CI only fails on new
findings:

```bash
lurkr scan --path . --save-baseline .lurkr-baseline.json
lurkr scan --path . --baseline .lurkr-baseline.json --fail-on high
```

## Privacy & Data Handling

Lurkr is local-only by design.

- It does not upload source code, manifests, scan reports, findings, paths, or
  usage data to AgentVeil.
- It does not make network calls during `lurkr scan`.
- It does not execute scanned project code.
- It writes output only to the terminal or to the report path you provide.
- Reports are redacted: raw secrets, command bodies, private-key bytes, and
  credential material are not included.

If you use the optional GitHub Action, the scan still runs inside your CI
environment. Any SARIF upload is performed by GitHub's own CodeQL upload action
only when you add that step to your workflow.

## What a Finding Looks Like

```json
{
  "rule_id": "workflow.deploy_without_approval",
  "severity": "high",
  "file": ".github/workflows/deploy.yml",
  "line": 12,
  "message": "Deployment workflow appears to run without an approval gate.",
  "remediation": "Add a protected GitHub environment or explicit manual approval before production deploy, release, or publish steps."
}
```

Every finding contains rule ID, severity, repository-relative file path, line
number when available, redacted message, and remediation pointer. Raw secrets,
command bodies, and key material never appear in the report.

## Detection Scope

All current rules are reported as `high` severity.

| Rule | What it flags | Scope |
|---|---|---|
| [`bypass.direct_github_token`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/bypass.direct_github_token.md) | Direct GitHub PAT/token references in workflows or agent manifests | GitHub Actions, agent manifests |
| [`workflow.deploy_without_approval`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/workflow.deploy_without_approval.md) | Deploy/release/publish steps without an approval gate | GitHub Actions |
| [`workflow.pull_request_target_secrets_risk`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/workflow.pull_request_target_secrets_risk.md) | `pull_request_target` workflows that combine privileged context with checkout, run, or secrets | GitHub Actions |
| [`tool.shell_without_approval`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/tool.shell_without_approval.md) | Agent tool manifests that enable shell execution without an approval flag | MCP/CrewAI-style manifests |
| [`identity.private_key_unencrypted`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/identity.private_key_unencrypted.md) | Unencrypted PEM private key files committed to the repo | Repository files |
| [`agent.credential_to_llm_context`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.credential_to_llm_context.md) | Credential-bearing values passed into LLM completion context | OpenAI, Anthropic, Gemini, LangChain direct call sites |
| [`agent.declared_vs_imported_delta`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.declared_vs_imported_delta.md) | Python AND TypeScript/JavaScript MCP tool registrations not declared in agent manifest files | MCP, CrewAI, AutoGen, LangChain manifests + supported Python tool registrations + bounded TS/JS MCP `registerTool` shapes |
| [`agent.dynamic_prompt_from_user_input`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.dynamic_prompt_from_user_input.md) | Prompt templates directly interpolating function parameters | Prompt-shaped Python assignments and common template helpers |
| [`agent.python_api_key_hardcoded`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.python_api_key_hardcoded.md) | API-key-shaped string literals in Python source | Module-wide; Anthropic, OpenAI, GitHub PAT, HuggingFace |
| [`agent.python_eval_exec_in_tool`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.python_eval_exec_in_tool.md) | `eval`/`exec`-style dynamic execution inside Python tool functions | Supported Python tool functions |
| [`agent.python_subprocess_in_tool`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.python_subprocess_in_tool.md) | Subprocess or shell calls inside supported Python tool functions | Supported Python tool functions |
| [`agent.python_tool_without_approval`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.python_tool_without_approval.md) | Python agent tool declarations without an approval marker | LangChain, LangGraph, CrewAI, MCP, OpenAI tool calling, Anthropic tool use, LlamaIndex, Gemini |
| [`agent.python_unrestricted_file_access`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.python_unrestricted_file_access.md) | File write or delete calls inside Python tool functions | Supported Python tool functions |
| [`agent.python_fastapi_path_auth_no_host_validation`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.python_fastapi_path_auth_no_host_validation.md) | FastAPI / Starlette middleware reading `request.url.path` without same-file `TrustedHostMiddleware` evidence | FastAPI / Starlette HTTP middleware |
| [`agent.unverified_mcp_endpoint`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.unverified_mcp_endpoint.md) | MCP server URLs pointing to non-allowlisted external hosts | MCP manifests |
| [`agent.javascript_child_process_in_tool`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.javascript_child_process_in_tool.md) | Node.js `child_process` commands inside canonical MCP `registerTool` handlers (TS/JS) | Canonical MCP `registerTool` handlers in TS/JS |
| [`agent.javascript_file_mutation_in_tool`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.javascript_file_mutation_in_tool.md) | Node.js `fs` / `fs/promises` write/delete calls inside canonical MCP `registerTool` handlers (TS/JS) | Canonical MCP `registerTool` handlers in TS/JS |
| [`agent.javascript_env_secret_access_in_tool`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.javascript_env_secret_access_in_tool.md) | Secret-like `process.env.` reads inside canonical MCP `registerTool` handlers (TS/JS) | Canonical MCP `registerTool` handlers in TS/JS |
| [`agent.javascript_network_call_in_tool`](https://github.com/agentveil-protocol/lurkr/blob/main/docs/rules/agent.javascript_network_call_in_tool.md) | Outbound network calls (fetch / axios / got / undici / http(s)) inside canonical MCP `registerTool` handlers (TS/JS) | Canonical MCP `registerTool` handlers in TS/JS |

TS/JS coverage is bounded to canonical Model Context Protocol
`registerTool` registration patterns (identifier-bound, chained, typed
helper-wrapper parameters, namespace-qualified, parenthesized) reached
through bounded same-file AST analysis and relative-path cross-file
handler resolution. See the per-rule docs for each rule's exact gate.

Deployment checks include common CLI deploy, release, registry push, and
infrastructure apply commands. Build, plan, dry-run, and package-only commands
are excluded unless the same step also contains a deploy marker.

## How Lurkr is different

Most AI-agent scanners focus on installed components, MCP servers, prompts, or skills.

Lurkr focuses on **capability risk before deployment**.

It scans the repo surfaces that turn an agent into an actor:
- GitHub workflows that can deploy or expose secrets
- Agent manifests that expose shell-capable tools
- Python agent code that wires tools to subprocess, file writes, eval/exec, direct tokens, LLM context, prompts, or external MCP endpoints
- Bounded TypeScript / JavaScript MCP tool handlers that reach `child_process`, file mutation, secret-like `process.env`, or outbound network calls

Static. Local-only. Offline. Redacted by default.

The goal: find high-severity capabilities worth controlling before they become production incidents — not produce a giant list of theoretical issues.

| Most scanners | Lurkr |
|---|---|
| MCP servers / installed components | Repo surfaces about to be deployed |
| Prompt injection / prompt risk | Risky agent capabilities |
| Long lists of potential issues | Conservative high-severity rules |
| API tokens / cloud calls | Local, offline, no telemetry |
| Generic secrets | Agent-relevant credentials and bypass paths |
| Report only | Findings mapped to remove / restrict / redact controls |
| Ad-hoc detection logic | Rules grounded in Saltzer-Schroeder principles (1975), Schneier attack trees (1999), OWASP LLM Top 10, MITRE ATLAS |

## Roadmap

### Available now

19 high-severity rules across:
- GitHub workflows + agent manifests + identity files
- Python agent code: LangChain / LangGraph, CrewAI, MCP (FastMCP and Server-style), OpenAI tool calling, Anthropic tool use, LlamaIndex, Gemini
- FastAPI / Starlette middleware that can make path-based auth decisions from host-poisoned `request.url.path`
- Bounded TypeScript / JavaScript MCP tool handlers: `child_process`, `fs` / `fs/promises` mutation, secret-like `process.env`, and outbound network calls (`fetch` / `axios` / `got` / `undici` / `http(s)`). Coverage is limited to canonical Model Context Protocol `registerTool` registration shapes and bounded same-file + relative-import handler resolution
- Declared-vs-imported capability delta across MCP/CrewAI/AutoGen/LangChain manifests, Python tool registrations, AND bounded TS/JS MCP `registerTool` extraction (identifier-bound, chained, typed helper-wrapper parameters, namespace-qualified, parenthesized, with same-file top-level `const` name resolution)
- AI-specific static checks for credential flow into LLM context, direct prompt interpolation, and external MCP endpoints
- Baseline mode for CI adoption: save current findings, then fail only on new findings

### v0.5.0 — broader framework coverage

Candidates for broader framework coverage:
- AutoGen / AG2 (re-validation against current Microsoft direction)
- PydanticAI
- Semantic Kernel

### v0.6.0+ — quality and ergonomics

Roadmap items being considered:
- Auto-fix patches via SARIF `fixes` field
- Per-finding contextual remediation
- Suppression comments / inline `lurkr: ignore`
- Cross-file `Tool(func=external_module.helper)` resolution
- More manifest formats (mcp.json variants)

### Community input welcome

Open an issue with framework or rule requests. Real-world examples accelerate prioritization.

## Install

From PyPI (recommended)

```bash
pip install lurkr
```

From GitHub release

```bash
pip install git+https://github.com/agentveil-protocol/lurkr@v0.4.0
```

From source (development)

```bash
git clone https://github.com/agentveil-protocol/lurkr
cd lurkr
pip install -e .
```

Docker

```bash
docker build -t lurkr .
docker run --rm -v "$PWD:/workspace" lurkr --output /workspace/report.json
```

The container runs as a non-root user (UID 1000). For host UID/GID matching to
avoid permission issues with the generated report file:

```bash
docker run --rm -u $(id -u):$(id -g) -v "$PWD:/workspace" lurkr --output /workspace/report.json
```

Add `--fail-on high` to make the container exit non-zero when high findings are
present.

## Use as a GitHub Action

Use the action from the same repository:

```yaml
- uses: agentveil-protocol/lurkr@v0.4.0
  with:
    path: "."
    output: lurkr-report.json
    fail-on: high
```

The action requires Python 3.10 or newer on the runner. It writes the report
path to the `report` output and does not upload data to AgentVeil. Omit
`fail-on` to keep review-only behavior.

For existing repositories, commit a baseline and only fail on new findings:

```yaml
- uses: agentveil-protocol/lurkr@v0.4.0
  with:
    path: "."
    output: lurkr-report.json
    baseline: ".lurkr-baseline.json"
    fail-on: high
```

For GitHub Code Scanning, write SARIF and upload it with CodeQL:

```yaml
- uses: agentveil-protocol/lurkr@v0.4.0
  with:
    path: "."
    output: lurkr.sarif
    format: sarif

- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: lurkr.sarif
```

## Pre-commit Hook

Run Lurkr as a [pre-commit](https://pre-commit.com) hook to catch capability
issues before they reach the remote.

Add to your `.pre-commit-config.yaml`:

```yaml
repos:
  - repo: https://github.com/agentveil-protocol/lurkr
    rev: v0.4.0
    hooks:
      - id: lurkr
        args: ["--fail-on", "high"]
```

Then install:

```bash
pre-commit install
```

The hook generates `lurkr-report.json` on every commit. Omit `args` for
review-only behavior, or use `--fail-on` to block commits when findings meet
the selected threshold.

## Triaging Findings

`lurkr` flags **capability surfaces**: places where an AI agent or workflow has
direct capability to do something risky. Most findings are **review items**,
not incidents:

- **`bypass.direct_github_token`** commonly appears on stale-bots,
  release-bots, CI publish steps, and label-management workflows that
  legitimately use the auto-injected `secrets.GITHUB_TOKEN`. The rule fires
  by design: the workflow holds direct GitHub write capability and that is a
  capability surface worth surfacing, even when expected.
- **`workflow.deploy_without_approval`** may flag deploy paths that have
  approval mechanisms the static scanner cannot see, such as manual job
  dispatch, branch protection, or external reviewer chains. Verify against
  your actual approval flow before treating as incident.
- **`workflow.pull_request_target_secrets_risk`** flags risky combinations,
  but some `pull_request_target` work

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [agentveil-protocol](https://github.com/agentveil-protocol)
- **Source:** [agentveil-protocol/lurkr](https://github.com/agentveil-protocol/lurkr)
- **License:** MIT
- **Homepage:** https://agentveil.dev

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-agentveil-protocol-lurkr
- Seller: https://agentstack.voostack.com/s/agentveil-protocol
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
