README.md

June 1, 2026 · View on GitHub

Lurkr logo

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:

GitHub Actions

- 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 | Privacy & data handling | What a finding looks like | Detection scope | Full Action usage | Why this exists


Local CLI

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 for the exact patterns covered.

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

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

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

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

{
  "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.

RuleWhat it flagsScope
bypass.direct_github_tokenDirect GitHub PAT/token references in workflows or agent manifestsGitHub Actions, agent manifests
workflow.deploy_without_approvalDeploy/release/publish steps without an approval gateGitHub Actions
workflow.pull_request_target_secrets_riskpull_request_target workflows that combine privileged context with checkout, run, or secretsGitHub Actions
tool.shell_without_approvalAgent tool manifests that enable shell execution without an approval flagMCP/CrewAI-style manifests
identity.private_key_unencryptedUnencrypted PEM private key files committed to the repoRepository files
agent.credential_to_llm_contextCredential-bearing values passed into LLM completion contextOpenAI, Anthropic, Gemini, LangChain direct call sites
agent.declared_vs_imported_deltaPython AND TypeScript/JavaScript MCP tool registrations not declared in agent manifest filesMCP, CrewAI, AutoGen, LangChain manifests + supported Python tool registrations + bounded TS/JS MCP registerTool shapes
agent.dynamic_prompt_from_user_inputPrompt templates directly interpolating function parametersPrompt-shaped Python assignments and common template helpers
agent.python_api_key_hardcodedAPI-key-shaped string literals in Python sourceModule-wide; Anthropic, OpenAI, GitHub PAT, HuggingFace
agent.python_eval_exec_in_tooleval/exec-style dynamic execution inside Python tool functionsSupported Python tool functions
agent.python_subprocess_in_toolSubprocess or shell calls inside supported Python tool functionsSupported Python tool functions
agent.python_tool_without_approvalPython agent tool declarations without an approval markerLangChain, LangGraph, CrewAI, MCP, OpenAI tool calling, Anthropic tool use, LlamaIndex, Gemini
agent.python_unrestricted_file_accessFile write or delete calls inside Python tool functionsSupported Python tool functions
agent.python_fastapi_path_auth_no_host_validationFastAPI / Starlette middleware reading request.url.path without same-file TrustedHostMiddleware evidenceFastAPI / Starlette HTTP middleware
agent.unverified_mcp_endpointMCP server URLs pointing to non-allowlisted external hostsMCP manifests
agent.javascript_child_process_in_toolNode.js child_process commands inside canonical MCP registerTool handlers (TS/JS)Canonical MCP registerTool handlers in TS/JS
agent.javascript_file_mutation_in_toolNode.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_toolSecret-like process.env.<NAME> reads inside canonical MCP registerTool handlers (TS/JS)Canonical MCP registerTool handlers in TS/JS
agent.javascript_network_call_in_toolOutbound 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 scannersLurkr
MCP servers / installed componentsRepo surfaces about to be deployed
Prompt injection / prompt riskRisky agent capabilities
Long lists of potential issuesConservative high-severity rules
API tokens / cloud callsLocal, offline, no telemetry
Generic secretsAgent-relevant credentials and bypass paths
Report onlyFindings mapped to remove / restrict / redact controls
Ad-hoc detection logicRules 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)
pip install lurkr
From GitHub release
pip install git+https://github.com/agentveil-protocol/lurkr@v0.4.0
From source (development)
git clone https://github.com/agentveil-protocol/lurkr
cd lurkr
pip install -e .
Docker
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:

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:

- 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:

- 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:

- 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 hook to catch capability issues before they reach the remote.

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

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

Then install:

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 workflows are correctly scoped to label-only or metadata-only operations. Re-check the actual job content.
  • tool.shell_without_approval flags inline shell capability declarations. Tools referenced by name, such as search_tool in CrewAI, are not detected; only literal shell: or bash: keys are.
  • identity.private_key_unencrypted is the most reliably actionable finding: committed unencrypted private keys are usually real issues.
  • agent.python_tool_without_approval flags supported Python tool declarations where the scanner cannot see a conservative approval marker.
  • agent.python_subprocess_in_tool and agent.python_eval_exec_in_tool are high-priority review items because agent-callable Python functions can run commands or dynamic code.
  • agent.python_unrestricted_file_access flags file write/delete calls in tool functions. Review whether the path is intentionally constrained.
  • agent.python_api_key_hardcoded is module-wide and should usually be treated like a secret-handling issue: remove and rotate the key if real.

Use Lurkr to surface review items for human triage, not to auto-block CI or replace SAST/secret-scanning tools.

Why This Exists

AI agents increasingly touch production credentials, deploy workflows, and developer infrastructure. Lurkr is the first step: find risky capabilities before deployment and before they become incidents.

  +----------+      +----------+      +----------+
  |   FIND   |      |  DECIDE  |      |  PROVE   |
  |  risky   | ---> |  what is | ---> |  what    |
  |   caps   |      |  allowed |      | happened |
  +----------+      +----------+      +----------+
   you are here       roadmap          roadmap
   v0.2 Lurkr
Lurkr doesLurkr does not
ScopeStatic analysis and capability risk patternsApproval, blocking, or execution of agent actions
EffectsRead-only file inspectionCode execution, network calls, or file mutation
OutputRedacted JSON findingsSecret values, command bodies, or key bytes

For the broader AgentVeil project, see agentveil.dev.

Hard Constraints

The scanner is designed to be:

  • offline: no network calls
  • telemetry-free: no usage data collected
  • read-only: does not modify scanned files
  • static-only: does not execute scanned project code
  • secret-safe: reports only redacted findings

Private-key checks use file metadata and bounded header sniffing only.

Dependency Policy

Runtime dependencies are intentionally minimal:

  • Python >=3.10
  • PyYAML>=6.0.1,<7

Additional runtime dependencies require explicit justification in PLAN.md.

Known Limitations

lurkr v0.3 is a bounded static scanner, not an exhaustive security audit.

  • Some rules may produce false positives or false negatives.
  • Oversized, unreadable, or malformed inputs may be skipped without per-file skip reasons.
  • YAML parsing is bounded, but carefully crafted YAML within the current alias limit can still consume parser memory.
  • Python analysis is bounded to .py files. Stub files and cross-file Python call resolution are out of scope for this release.
  • TypeScript / JavaScript analysis is bounded to canonical Model Context Protocol registerTool registration patterns (identifier-bound, chained, typed helper-wrapper parameters, namespace-qualified, parenthesized) and a small set of cross-file handler resolution shapes (named imports, default imports, namespace local imports, directory/index probing — all restricted to relative paths within the scan root). Untyped JS wrappers, helper-wrapper name heuristics, tool arrays / forEach loops, setRequestHandler("tools/call", ...), CommonJS module.exports shapes, barrel re-exports, tsconfig path aliases, package imports for handler resolution, and dataflow / reachability analysis beyond bounded same-file AST in the target file remain out of scope.
  • The repository includes intentional validation fixtures and release automation review items used to exercise rules. Self-scans can report those by design; they are not real credentials or production incidents.

Community

Further reading

For teams that want to attach Lurkr coverage to existing security and compliance artifacts:

Most users can start with the Local CLI section above.

License

MIT. See LICENSE.


Part of the AgentVeil project: action control for autonomous agents.