Crypto Finder is a CLI tool that detects cryptographic algorithm usage in source code. It runs detection rules through a scanning engine (OpenGrep by default, Semgrep supported), builds a call graph of the scanned code, computes which crypto findings are reachable from which API entry points, and exports the results as interim JSON, CycloneDX CBOM, a finding-centric call graph, or a reusable graph fragment.
# Configure your API key (one-time setup)
crypto-finder configure --api-key YOUR_API_KEY
# Scan a project using the remote ruleset
crypto-finder scan /path/to/code
# Generate a CycloneDX CBOM
crypto-finder scan --format cyclonedx --output cbom.json /path/to/code
# Scan with call graph reachability export
crypto-finder scan --export-callgraph callgraph.json --output findings.json /path/to/code-
Go 1.25+ (only for building from source)
-
OpenGrep (recommended) or Semgrep — the scanning engine. Included in the Docker images.
# OpenGrep v1.12.1: download from https://github.com/opengrep/opengrep/releases/tag/v1.12.1 # Semgrep: pip install semgrep==1.145.0
Option 1: Build from source
git clone https://github.com/scanoss/crypto-finder.git
cd crypto-finder
make build
sudo make installOption 2: Go install
go install github.com/scanoss/crypto-finder/cmd/crypto-finder@latestOption 3: Docker
# Full image with scanners included (recommended)
docker pull ghcr.io/scanoss/crypto-finder:latest
# Slim image (bring your own scanner)
docker pull ghcr.io/scanoss/crypto-finder:latest-slim
# Deps image (all language toolchains for dependency scanning)
docker pull ghcr.io/scanoss/crypto-finder:latest-deps| Command | Purpose |
|---|---|
scan |
Scan a source tree for crypto usage. Optionally builds the call graph, scans dependencies, and exports reachability artifacts. |
annotate |
Re-run only crypto detection against a previously exported graph fragment — skips the expensive call graph rebuild. |
convert |
Convert interim JSON results to CycloneDX CBOM. |
configure |
Persist the SCANOSS API key / URL. |
version |
Print version information. |
# Remote ruleset (default; requires API key)
crypto-finder scan /path/to/code
# Local rules only (rules development loop, offline use)
crypto-finder scan --no-remote-rules --rules-dir ./rules /path/to/code
# CI/CD: fail the build when crypto is detected
crypto-finder scan --fail-on-findings /path/to/code
# Scan third-party dependencies with call chain tracing
crypto-finder scan --scan-dependencies /path/to/code
# Export the finding-centric call graph (reachability slices)
crypto-finder scan --export-callgraph callgraph.json /path/to/code
# Export a reusable structural graph fragment (for stitching / caching)
crypto-finder scan --export-graph-fragment fragment.json /path/to/codeThe interim JSON report (findings + metadata) goes to --output (stdout by default). The call graph and graph fragment exports are separate files written to the paths given to --export-callgraph / --export-graph-fragment. Use scan --progress when an integration needs lifecycle JSONL on stderr; it suppresses human logs and leaves findings on stdout or --output. See Output Formats for all schemas.
The call graph build (parsing + type inference) is the expensive ~95% of a scan and is rules-independent. When only the detection ruleset changed — new rules version, local rule you are iterating on — you do not need to rebuild the graph:
# One-time: full scan, cache the structural fragment
crypto-finder scan --export-graph-fragment fragment.json /path/to/code
# Every rules change afterwards: detection-only re-annotation
crypto-finder annotate --import-fragment fragment.json --source /path/to/code --output annotation.jsonannotate runs only the detection pass, maps each finding onto the imported fragment's function line ranges, and emits crypto_annotations that are byte-identical to a full scan --export-graph-fragment for the same source + rules. On a large library this turns a ~20 minute re-scan into ~1 minute of detection.
Use scan when the source code changed (the graph must be rebuilt); use annotate when only the rules changed. The fragment's graph_algo_version in scan_metadata tells you when a new binary release invalidates cached fragments (it bumps only on graph-construction changes).
| Flag | Default | Description |
|---|---|---|
-v, --verbose |
off | Info-level logging |
-d, --debug |
off | Debug-level logging |
-q, --quiet |
off | Error-level logging only |
--error-format <fmt> |
text |
Terminal error rendering: text or json. With json, failures are emitted to stderr as a structured payload with a stable code and stage — see Error Codes. |
| Flag | Default | Description |
|---|---|---|
-r, --rules <file> |
— | Rule file path (repeatable) |
--rules-dir <dir> |
— | Rule directory path (repeatable) |
--no-remote-rules |
off | Disable the default remote ruleset |
--no-cache |
off | Force fresh download of remote rules, bypass cache |
--strict |
off | Fail if the rules cache expired and the API is unreachable (no stale-cache fallback) |
--max-stale-age <dur> |
30d |
Maximum age for stale cache fallback (max 90d) |
--scanner <name> |
opengrep |
Scanner engine: opengrep, semgrep |
-f, --format <fmt> |
json |
Output format: json (interim), cyclonedx |
-o, --output <file> |
stdout | Output file path for the findings report |
--languages <langs> |
auto | Override language detection (comma-separated) |
--fail-on-findings |
off | Exit non-zero if findings are detected |
-t, --timeout <dur> |
10m |
Scan timeout (e.g. 10m, 1h, 2w) |
--no-dedup |
off | Disable per-line deduplication of findings |
--include-tests |
off | Include test sources in findings and dependency scans |
--no-default-exclusions |
off | Disable built-in exclusions (vendor, node_modules, shaded/, generated protobuf stubs, ...). Slows scans on large repos; combine with --exclude to re-add specific paths |
--exclude <glob> |
— | Gitignore-style pattern to skip (repeatable); added on top of the defaults |
--scan-dependencies |
off | Recursively scan third-party dependencies (requires the deps image or local toolchains) |
--dep-ecosystem <eco> |
auto |
Dependency ecosystem: auto, go, java, python, rust |
--dep-workers <n> |
0 |
Parallel dependency scan workers (0 = half of CPU cores, max 8; Java max 2) |
--findings-cache <backend> |
disk |
Dependency findings cache backend: disk, none, postgres (also via SCANOSS_FINDINGS_CACHE_BACKEND; postgres needs SCANOSS_FINDINGS_CACHE_DSN) |
--progress |
off | Write scan lifecycle JSONL to stderr; findings remain on stdout or --output, and explicit --error-format=text is incompatible |
--export-callgraph <file> |
— | Write the finding-centric crypto call graph (reachability slices) to <file> |
--export-callgraph-format <fmt> |
json |
Call graph export format (only json) |
--export-graph-fragment <file> |
— | Write a reusable structural graph fragment to <file> |
--export-graph-fragment-format <fmt> |
json |
Graph fragment export format (only json) |
--java-jdk-major <major> |
— | Java JDK major for dependency resolution/type enrichment: auto, 8, 11, 17, 21 |
--java-jdk-home <major=path> |
— | Explicit JDK home mapping (repeatable) |
--java-compiled-artifact <path> |
— | Compiled Java artifact used for standalone callgraph/type enrichment |
--interfile |
off | Cross-file analysis (Semgrep Pro only) |
--api-key, --api-url |
config | Override the configured SCANOSS API key / base URL |
| Flag | Default | Description |
|---|---|---|
--import-fragment <file> |
required | Cached structural graph fragment JSON to re-annotate |
--source <dir> |
required | Source directory to run crypto detection over |
-o, --output <file> |
stdout | Output file for the annotation JSON |
annotate also accepts the detection-related subset of scan flags: --rules, --rules-dir, --no-remote-rules, --no-cache, --scanner, --timeout, --languages, --include-tests, --no-default-exclusions, --exclude, --api-key, --api-url.
Detection (rules-based scanning) covers whatever languages the ruleset covers. Call graph construction and reachability analysis support these ecosystems:
| Ecosystem | Call graph parser | Contract knowledge bases (internal/callgraph/contracts/) |
|---|---|---|
| C | yes | OpenSSL EVP, libsodium, Mbed TLS, wolfSSL/wolfCrypt |
| C++ | yes | Crypto++ (SHA-256 hash lifecycle) |
| Go | yes | stdlib crypto/*, golang.org/x/crypto, golang-fips/openssl |
| Java | yes | JDK JCA/JCE, BouncyCastle (+ OpenPGP), Tink, jjwt, Nimbus JOSE+JWT, Apache Santuario, Apache SSHD, Password4j, Spring Security Crypto |
| JavaScript / TypeScript (Node) | yes | none yet (bootstrap placeholder) |
| Python | yes | pyca/cryptography, PyCryptodome(x), paramiko, passlib, bcrypt, argon2-cffi, PyNaCl, pyOpenSSL, M2Crypto, PyJWT, flask-jwt-extended, pyotp, werkzeug, boto3, azure-keyvault-keys/secrets |
| Rust | yes | ring, chacha20poly1305 |
Dependency scanning (--scan-dependencies) resolves and scans third-party packages for: Go, Java (Maven/Gradle), Python (pip), Rust (Cargo).
Detection rules are not in this repository — they live in scanoss/crypto_rules and are served as the remote dca ruleset via the SCANOSS API (cached locally with TTL + stale fallback; see Remote Rulesets).
Local rules development loop:
# Iterate on rules without touching the remote ruleset
crypto-finder scan --no-remote-rules --rules-dir /path/to/crypto_rules/checkout /path/to/testcode
# Combine remote rules with local additions
crypto-finder scan --rules-dir ./custom-rules /path/to/codeSmall rule fixtures used by this repo's tests live under testdata/rules/. Rules detect terminal crypto operations only and carry standard CycloneDX metadata; supporting/lifecycle calls are derived structurally from the call graph, never tagged by rules — see Architecture.
Callgraph schema 6.12 places contract-derived Java key-generation key-length evidence on supporting_calls[].supporting_call.resolved_key_length, marking it rule_conflict when a rule-declared key length disagrees with the resolved one; terminal crypto_call records remain the detected operations.
crypto-finder configure --api-key YOUR_API_KEY
crypto-finder configure --api-url https://custom.scanoss.comEnvironment variables: SCANOSS_API_KEY, SCANOSS_API_URL. Project-level skip patterns via scanoss.json:
{
"settings": {
"skip": {
"patterns": {
"scanning": ["node_modules/", "target/", "venv/"]
}
}
}
}See Configuration for the full guide.
| Document | Contents |
|---|---|
| docs/ARCHITECTURE.md | Pipeline overview, package map, load-bearing invariants |
| docs/OUTPUT_FORMATS.md | Interim JSON, callgraph export (schema 6.12), graph fragment (graph-fragment-1.12), CycloneDX CBOM |
| docs/ERROR_CODES.md | Stable failure code/stage taxonomy emitted by --error-format json |
| docs/CONFIGURATION.md | Configuration options and skip patterns |
| docs/DEPENDENCY_SCANNING.md | Dependency scanning, call chain tracing, attribution |
| docs/REMOTE_RULESETS.md | Remote ruleset API, caching, troubleshooting |
| docs/DOCKER_USAGE.md | Container usage and CI/CD integration |
| CONTEXT.md | Domain glossary — the ubiquitous language used across code and docs |
| AGENTS.md | Conventions for AI agents and contributors (changelog policy, error layering, contracts KB) |
We welcome contributions! See CONTRIBUTING.md and our Code of Conduct.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests (
make test) - Install pinned linter (
make lint-install) - Run linter (
make lint) - Commit your changes (
git commit -m 'feat: add an amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
See CHANGELOG.md for a detailed history of changes — including every partner-facing schema bump.
Copyright (C) 2026 SCANOSS.COM
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file for the full license text.
SPDX-License-Identifier: GPL-2.0-only
For questions, issues, or feature requests, please use the GitHub Issues page.