scanning

Scan limits

A scan is a single serverless request, so it runs against fixed budgets. Here is every limit with its real value, the paths skipped by design, and why each cap exists. When a scan hits a limit, the result is flagged as truncated so “0 findings” is never mistaken for “actually clean.”

The limits

LimitDefaultMaxConstant
Files scanned per run1,00010,000SCAN_MAX_FILES
Wall-clock time budget55 seconds290 secondsSCAN_MAX_TIME_MS
Max single file size1 MBMAX_FILE_SIZE
Git-history depth30 commitsHISTORY_COMMIT_LIMIT
Max patch size per commit200 KBMAX_PATCH_SIZE

The file count and time budget are configurable via environment variables; the values above are the defaults the public deployment runs with. The Max column is the hard ceiling the code clamps to even if an env var asks for more.

Why the file and time caps exist

Serverless timeout

A scan runs inside a single serverless function invocation. On Vercel Hobby that invocation is capped at 60 seconds, so the default 55-second budget leaves a few seconds of headroom to finish post-loop work (the git-history pass and the posture / IAM checks) and return a response instead of being killed mid-flight. The 290-second ceiling exists for deployments on Vercel Pro, whose function limit is 300 seconds.

The 1,000-file default is the companion cap: it is the number of files that actually fits inside the time budget. Raising the time limit without raising the file limit would not let you feel the extra time, which is why the two move together. Files are fetched in batches and the time budget is checked between batches, so a scan stops cleanly at the boundary rather than being terminated.

Which files get the budget

Before the file cap is applied, candidate files are prioritized so the budget is spent on the code most likely to contain real findings: source files rank above tests, fixtures, examples, and docs. If the repo has more scannable files than the cap, the lowest-priority ones are skipped and the result is marked truncated.

Only text-based source files are eligible at all — common code, config, and infrastructure extensions, plus a few extensionless names (Dockerfile, Makefile, and .env files). A file that looks binary (more than 10% of its first 1,000 characters are non-printable) is skipped even if its extension matched.

Paths skipped by design

These paths are never scanned, regardless of the file cap. They are vendored code, build output, and lockfiles — noise that would waste the budget and produce findings you cannot act on:

  • node_modules/
  • .next/
  • dist/
  • build/
  • target/
  • vendor/
  • .git/
  • coverage/
  • out/
  • *.min.js / *.min.css
  • *.lock
  • package-lock.json
  • yarn.lock
  • pnpm-lock.yaml
  • *.map (sourcemaps)

Want to skip more (or re-include something)? That is what .repoguardignore is for — see Suppressions.

Git-history scan

On top of the current file tree, TriageRook replays the 30 most recent commitslooking for secrets that were added and later removed — a credential deleted in a follow-up commit is still in the history and still leaked. Any single commit patch larger than 200 KB is skipped to keep the history pass inside the time budget. The history scan is best-effort: if it hits a GitHub rate limit or errors, it is skipped and the scan reports that it was skipped rather than implying history is clean.

Large monorepos

If a repository is too large for one pass, you can narrow a scan to a subfolder (for example packages/auth). The file cap is then spent entirely within that subtree, and the result header makes clear it was a narrow scan so a clean result for one package is not read as a clean result for the whole repo.

Hit a limit and think a repo of your size should fit? Tell us.