Skip to content
PreClone

CLI, extension and API

The same engine everywhere. It reads files and never runs them, whether it's on our server, in your browser tab or on your machine.

CLI

Check a link, a folder you already downloaded, or a zip, from the terminal. The CLI is one bundled file with no dependencies, and it never uploads your code: it downloads public archives itself and only sends package names and versions to npm and OSV.

It isn't on the npm registry yet. Until it is, install the tarball this site serves. It's one readable file, and we'd rather you read it first: preclone-1.3.2.tgz (checksums in SHA256SUMS). For a one-off check without installing, run npx https://preclone.dev/cli/preclone-1.3.2.tgz owner/repo.

curl -fsSLO https://preclone.dev/cli/preclone-1.3.2.tgz
shasum -a 256 preclone-1.3.2.tgz   # compare with /cli/SHA256SUMS
npm install -g ./preclone-1.3.2.tgz

preclone https://github.com/acme/take-home      # any GitHub, GitLab or Bitbucket link
preclone acme/take-home                         # owner/repo means GitHub
preclone ./downloaded-folder                    # a folder on disk
preclone ~/Downloads/project.zip                # .zip, .tar.gz or .tgz
preclone acme/private --token $GITHUB_TOKEN     # private repos (token used for the download only)
preclone . --fail-on high                       # exit 1 if anything is high or critical (CI)
preclone ./big-monorepo --time-limit 300        # more time for a huge folder (default 120 s)
preclone acme/take-home --json | jq .verdict    # machine-readable report
preclone acme/take-home --share                 # get a shareable link (public repos only)

Exit codes: 0 finished, 1 a finding met --fail-on, 2 the check couldn't run. It respects NO_COLOR and reads GITHUB_TOKEN / GITLAB_TOKEN when set.

In CI

If you take pull requests from people you don't know, this flags a malicious install script, folder-open task or agent hook before you check the branch out on your own machine, and before later jobs install it. Put it ahead of anything that installs or builds. A pull request can edit workflow files too, so read any change under .github/workflows yourself.

# .github/workflows/preclone.yml
name: PreClone
on: pull_request
permissions:
  contents: read
jobs:
  preclone:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          persist-credentials: false
      - run: |
          curl -fsSLO https://preclone.dev/cli/preclone-1.3.2.tgz
          echo "f3ecb86e6d58b6fc87d3fb298483092210e177510fda5e4524cf57445b268fc0  preclone-1.3.2.tgz" | shasum -a 256 -c
          npm install -g ./preclone-1.3.2.tgz
      - run: preclone . --fail-on high

  # jobs in this file that install or build wait for the check
  test:
    needs: preclone

Browser extension

Adds a “Check before cloning” button next to the Code button on GitHub (and the clone button on GitLab and Bitbucket). Clicking it opens this site's report for that repo and branch. The toolbar icon does the same for the tab you're on.

It runs only on github.com, gitlab.com and bitbucket.org, and makes no network requests of its own. To work out the repo and branch it reads the page address and, when the address doesn't say, the branch picker on the page. Because it adds a button to those pages, Chrome will say it can read and change your data on those three sites.

  1. Download preclone-extension.zip (checksum in SHA256SUMS) and unzip it. It's a handful of small readable files; read them before you load it.
  2. Open chrome://extensions (Edge, Brave and Arc work the same) and turn on Developer mode.
  3. Click Load unpacked and pick the unzipped folder.

It isn't in the Chrome or Firefox stores yet, so for now it loads unpacked. In Firefox, use about:debugging and Load Temporary Add-on.

The prefix trick

Put our domain in front of any repo link in the address bar and the check starts straight away.

preclone.dev/github.com/acme/take-home
preclone.dev/https://github.com/acme/take-home/tree/dev
preclone.dev/gitlab.com/group/project

You can also link to https://preclone.dev/scan?url=<repo url> from your own tools, docs or bot replies.

HTTP API

Create a token in Settings and send it as a bearer token. Every response is JSON. Errors look like {"error": {"code", "message"}}.

Check a repository

curl -X POST https://preclone.dev/api/v1/scan \
  -H "Authorization: Bearer pc_…" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://github.com/acme/take-home"}'

# private repo (Pro): add "token": "github_pat_…" (used once, never stored)
# skip the 15-minute cache: add "fresh": true
{
  "id": "k7Qm2xPa9c",
  "path": "/r/k7Qm2xPa9c",
  "cached": false,
  "visibility": "unlisted",
  "report": { "verdict": { "level": "danger", "headline": "…" }, "findings": [ … ], … }
}

Other endpoints

  • GET /api/v1/scans: your recent checks, newest first.
  • GET /api/v1/me: the account and plan a token belongs to.
  • GET /api/scan/:id: one report (unlisted reports need no token; private ones need yours).
  • POST /api/scan: what the website uses. Works without a token at the anonymous limit.

Error codes

CodeHTTPMeaning
bad_request400The body wasn't the JSON we expected.
invalid_url400Not a repository URL we can parse.
unsupported_host400Only github.com, gitlab.com and bitbucket.org links. Upload a zip for anything else.
auth_required401This endpoint needs an API token, or private repos need an account.
invalid_token401The token you sent doesn't exist or was revoked.
pro_required402Private repositories are a Pro feature.
not_found404The repo doesn't exist, is private, or the token can't read it.
too_large413Archive over the size limit for your plan. Use the CLI.
quota429You've used your checks for this window.
upstream502GitHub, GitLab or Bitbucket answered with an error.
rate_limited503The code host is rate-limiting downloads. Retry in a minute.
timeout504The download took too long.

The report format

verdict.level is one of danger, warning, notice or clear, shown on the site as Malware signs, Read first, Worth a look and Nothing flagged. It is never “safe”.

  • findings[]: rule, title, moment (open, agent, install, run, commit, code), severity, auto (runs without you typing a command), detail, command and evidence[] with path, line and the surrounding lines.
  • surface[]: every entry point, including expected ones like husky, with a status of expected, review or danger.
  • dependencies: direct dependencies and whether they were checked against npm and OSV.
  • notes[]: limits hit and checks skipped.
  • stats.incomplete[]: present when the check couldn't cover everything that matters, such as a time limit or config files it couldn't read. While it's there, the level is at least warning.

URLs and IP addresses inside evidence are defanged (hxxp, [.]) so nobody clicks them by accident. Anything shaped like a credential (tokens, npm auth settings, passwords in URLs) is replaced with <redacted>, and in env files only the flagged line is shown.

Limits

  • Without an account: 12 checks an hour per network.
  • Free account: 40 a day. Pro: 1,000 a day once payments are on; until then, the free Pro preview keeps the free limits.
  • Archive size: 80 MB compressed on Free, 200 MB on Pro. The CLI takes much bigger repos.
  • The same public repo and branch checked within 15 minutes returns the earlier report, as long as the branch still points at the same commit. “Check again” skips that.