Features

What an audit checks, and what it deliberately does not

What we look for

Five categories of finding

Each finding comes from a deterministic tool — a scanner that matched a rule at a line in a file. You can check every one of them yourself, because we show you the evidence.

Exposed credentials

API keys, database URLs, signing secrets and access tokens committed into the repository. We match on key formats, so a Stripe live key or a Supabase service role key is identified for what it is rather than flagged as a suspicious string.

Matched values are stored redacted. We prove a credential is present without keeping a copy of it.

Vulnerable dependencies

Your lockfile is read as data and each pinned version is checked against the public advisory database. You get the advisory identifier, what it allows, and the exact version that fixes it.

Supported: package-lock.json, pnpm-lock.yaml, yarn.lock, requirements.txt, poetry.lock, uv.lock, Pipfile.lock. No lockfile means no dependency findings — and the report says so.

Security patterns

Raw HTML rendered without sanitising, SQL assembled by joining strings, cookies set without the Secure flag, endpoints that fetch by id without an ownership check, permissive CORS.

Powered by Semgrep with a pinned ruleset, plus Bandit for Python. Rules in your repository are never loaded.

Reliability

Errors swallowed by a bare except, promises left unawaited, webhook handlers that return success before the work is done. The failures that do not crash anything — they just quietly lose data.

This is the category AI-assisted code fails most often, because the happy path is what gets tested.

Code quality

Untyped values at boundaries that matter, unused imports, request bodies written into logs. Not urgent, but the kind of thing that gets expensive once there is more code around it.

ESLint and Ruff, both running with our configuration rather than yours.

What we could not check

Every report names the languages it did not support, the files it skipped and why, and any scanner that ran short of time. Coverage you cannot see is not coverage.

Treated as a feature, not a footnote. You are hiring us because you cannot judge our thoroughness yourself.

The report

Written for the person who has to act on it

Most security tooling produces output for security engineers. If you had one of those, you would not need us.

Ordered by what to do first

Not sorted by severity label alone. A committed live key outranks a dependency advisory that needs a specific set of conditions to matter.

Evidence on every finding

The file, the line, the matched snippet, the scanner and the rule id. Enough to verify it yourself or hand it to a contractor.

Confidence, stated plainly

High, medium or low — and where a tool cannot settle it, the finding is marked as requiring human review rather than presented as fact.

Explanations, clearly labelled

What it means and what to do, written in plain language and marked as AI-generated so you always know which part is the tool and which part is the explanation.

Fix tracking across re-scans

Re-run after a fix and the report tells you which findings you closed, which are still open, and which are new since last time.

No false reassurance

A clean report says no blocking issues were found in what was covered. It never says your code is secure, because no automated tool can honestly say that.

Under the hood

The tools we run, and how we run them

Deterministic scanners produce every finding. The language model groups and explains them — it cannot create a finding, hide one, or change its severity.

ScannerCoversHow it is run
Secret scanningAll file typesPattern and entropy matching over file contents. Reads only.
Dependency auditnpm, pnpm, yarn, pip, Poetry, uvLockfiles parsed as data and checked against the advisory database. Nothing is ever installed.
SemgrepJavaScript, TypeScript, PythonPinned ruleset. Registry and in-repository rule discovery disabled.
ESLintJavaScript, TypeScriptOur configuration, with config lookup disabled. Your eslint.config.js is read as text, never executed.
RuffPythonParses to a syntax tree. Your modules are never imported.
BanditPythonSyntax-tree analysis for common security issues.

Language support is JavaScript, TypeScript and Python today. Other languages in your repository are detected and reported as not covered rather than quietly ignored.

See it against your own code

The free plan runs a full audit on one repository. No card, and read-only access you choose repository by repository.

Run a free audit