Home/Docs/Security model

Security model

This tool is designed for teams that cannot let source code leave their machines. The security model is the product, not a FAQ entry.

Guarantees

  1. Your code never leaves your machine. scan / review / fix / deps / revalidate contain no network code at all — mechanically enforced by the test suite, which fails the build if any network primitive appears in those files.
  2. Metadata-only reporting, opt-in only. Hosted reporting requires an explicit --report-to flag. The payload builder is whitelist-constructed: unknown fields are dropped, and code snippets are structurally impossible to include — the field does not exist in the schema.
  3. Secrets are redacted in depth. Fifteen secret patterns (OpenAI, Stripe, AWS, GitHub, Slack, JWT, bearer tokens, generic key assignments and more) are scrubbed from every string of any outbound payload, and a pre-transmission assertion throws if a forbidden key or unredacted secret survives.
  4. One auditable LLM egress point. If you opt into BYO-LLM features, exactly one module (llmtransport.js) is allowed to send LLM traffic, and it is loaded dynamically only when you pass --llm. Your keys stay in your environment; error messages mask credentials.
  5. Minimal GitHub permissions. Fix PRs use a GitHub App scoped to contents:read + pull_requests:write on repos you choose. Never admin.
  6. Self-hosting available. Enterprise plans run the entire stack — change feed included — inside your firewall.

The complete upload schema

This is the entire shape of what an opt-in report can contain, verbatim from the shipped source (app/payload.js). Note what is absent: no code, no snippets, no full paths, no environment values.

shell
const PAYLOAD_SCHEMA = {
  version: 'number — payload schema version',
  tool: 'string — scanner name/version',
  generated_at: 'string — ISO timestamp from the local report',
  repo_name: 'string — basename of the scanned repo (full local path is never sent)',
  files_scanned: 'number',
  providers_detected: 'array<string>',
  changes_considered: 'number',
  sub_api_filtered: 'number',
  impacts_found: 'number',
  impacts: [
    {
      change: {
        id: 'number — change id in the public changes DB',
        provider: 'string',
        title: 'string — from the provider public release feed',
        type: 'string — breaking|deprecation|additive|fix|docs-only|unknown',
        severity: 'string',
        effective_date: 'string',
        source_url: 'string — public provider URL',
      },
      confidence: 'string — high|medium|low',
      usage_kinds: 'array<string> — import|env-var|api-host',
      symbols_extracted: 'number',
      matched_symbols: 'array<string> — public API symbol names from the changelog',
      symbol_sites: [{ file: 'string', line: 'number', symbol: 'string' }], // NO snippet
      usage_sites: [{ kind: 'string', detail: 'string', file: 'string', line: 'number' }], // NO snippet
    },
  ],
};

Fields marked NO snippet are enforced by the whitelist constructor and by a self-test suite that attempts to smuggle snippets and secrets through and asserts they are dropped or redacted.

Pre-release documentation, generated from the mendapi codebase. Command output and pack listings reflect the shipped CLI exactly.