conda-cve.tech exposes a small JSON HTTP API. Base URL:
(same host as this page unless you run the CLI elsewhere).
Machine-readable schema:
/openapi.json.
Liveness probe for load balancers and orchestrators.
Response 200:
{ "status": "ok" }
OpenAPI 3.0 description of this API.
Same inputs as /v1/scan, but the response is NDJSON
(application/x-ndjson): one JSON object per line. The web UI uses this endpoint so
results appear package-by-package. Event types: started, progress,
package, done, error.
Parse a conda ecosystem lockfile and return a structured vulnerability report.
Provide exactly one lockfile source: file upload, remote http(s) URL, or inline
content. Lockfile format is detected from file content, not from the
filename or extension.
POST /v1/scan — request options| Content-Type | Fields | Description |
|---|---|---|
multipart/form-data |
lockfile |
Upload the lockfile (browser / curl -F). |
multipart/form-data |
url |
Remote http(s) URL to fetch. |
application/json |
content |
Lockfile body as a JSON string. |
application/json |
url |
Same semantics as multipart url. |
application/json |
filename (optional) |
Optional name hint; format detection still uses content. |
http:// or https://. The server fetches the
lockfile remotely; private and localhost hosts are blocked (SSRF protection). GitHub
github.com/…/blob/… and …/raw/… links are rewritten to
raw.githubusercontent.com before fetch.
Replace $BASE with your API origin (e.g. ).
curl -F lockfile=@pixi.lock "$BASE/v1/scan"
curl -H 'Content-Type: application/json' \
-d '{"url":"https://example.com/conda-lock.yml"}' \
"$BASE/v1/scan"
curl -H 'Content-Type: application/json' \
-d '{"content":"# lockfile…","filename":"conda-lock.yml"}' \
"$BASE/v1/scan"
POST /v1/scan — responses| Status | Meaning |
|---|---|
200 | Scan completed; body is a scan report (JSON). |
400 | Invalid or unrecognized lockfile, bad URL, size limit, or conflicting fields. Body: { "error": "…" }. |
502 | Upstream failure (vulnerability lookup, package mapping, or URL fetch). Body: { "error": "…" }. |
Lock updates are performed in the web UI using
mambajs (browser WASM solver). Supported formats:
mamba JSON (lockVersion), conda explicit (@EXPLICIT), conda-lock YAML, and
pixi/rattler locks. The UI imports the lock, re-solves selected packages, exports the same format, then
rescans via POST /v1/scan.
The final done event on POST /v1/scan/stream may include
lock_content (echo of the scanned file) so URL-based scans can be updated in the browser.
Top-level fields:
| Field | Description |
|---|---|
lockfile_format | Detected format (e.g. conda-lock-yaml, mambajs-json). |
scanned_at | ISO 8601 timestamp (UTC). |
stats | Counts: package_count, packages_with_cves, packages_checked, packages_not_checked, plus per-lookup-path query totals. |
packages | Array of per-package results (see below). |
info | Optional informational strings (e.g. served from lockfile snapshot cache). |
warnings | Optional strings (e.g. rate limits, partial failures). |
Each element of packages:
| Field | Description |
|---|---|
name, version | Conda package identity from the lockfile. |
manager | conda or pypi. |
cve_lookup | How the package was mapped (method, PyPI targets, channel). |
coverage | checked (bool) and per-source sources[] status entries. |
cves | CVE list with id, severity, summary, references. |
cves: [] as “no known CVEs for this
version” only when coverage.checked is true. If
coverage.checked is false, the package was not fully scanned — do not assume
it is safe.
MAX_LOCKFILE_BYTES — max upload / fetch size (default 20 MiB).HTTP_TIMEOUT_SECS — timeout for URL fetch and upstream APIs (default 30).