How to Export Vulnerability Scan Results from Harbor: Complete API Workflow Guide

Harbor provides a scan data export feature via the POST /api/v2.0/scan/data/export endpoint that generates CSV files containing vulnerability details for images in a specified project.

Harbor's vulnerability scanning capabilities generate detailed security reports for container images, and the platform offers a programmatic way to export vulnerability scan results from Harbor through its REST API. This workflow is implemented asynchronously across several Go packages in the goharbor/harbor repository, utilizing a job-based architecture that processes exports in the background to handle large datasets efficiently.

Understanding the Export Architecture

The export functionality follows a four-stage pipeline implemented across the API handler, controller, and job service layers. When you initiate an export, Harbor validates your request, creates an execution record, processes the data asynchronously, and stores the result as a system artifact.

API Handler Layer (src/server/v2.0/handler/scanexport.go)

The ExportScanData method handles incoming HTTP requests and validates parameters using validateScanExportParams. This function checks MIME types, ensures exactly one project is specified, and verifies that repository, tag, or CVE filters contain no spaces before accepting the request.

Controller Layer (src/controller/scandataexport/execution.go)

The Start method in the scandataexport.Controller creates a task.Execution record and launches a task.Job of type ScanDataExportVendorType. If job creation fails, the controller marks the execution as errored using the internal markError function.

Job Service Layer (src/jobservice/job/impl/scandataexport/scan_data_export.go)

The Execute method runs in Harbor's jobservice process, fetching scanner data from the specified project, formatting it into CSV rows based on the export.Data struct, and storing the blob via the systemartifact.Manager. The resulting digest is saved to the execution record's ExportDataDigest field.

Step-by-Step Export Workflow

Exporting vulnerability data requires interacting with three main API endpoints to trigger, monitor, and retrieve the CSV file.

  1. Initiate the Export: Send a POST request to /api/v2.0/scan/data/export with your project ID and optional filters for repositories, tags, or CVE IDs.
  2. Poll for Completion: Query the execution status via GET /api/v2.0/scan/data/export/executions/{id} until file_present returns true.
  3. Download the CSV: Retrieve the file using GET /api/v2.0/scan/data/export/executions/{id}/download, which streams the artifact and automatically cleans up temporary storage after completion.

API Implementation and Code Examples

The following examples demonstrate how to interact with the Harbor API to export vulnerability scan results programmatically.

Starting an Export Job

The handler in src/server/v2.0/handler/scanexport.go (lines 26-61) accepts JSON payloads containing the project ID in an array and optional filter strings.

curl -X POST "https://harbor.example.com/api/v2.0/scan/data/export" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <access_token>" \
  -H "X-Scan-Data-Type: application/vnd.scanner.adapter.scan.report.generic" \
  -d '{
        "job_name": "my-export-job",
        "projects": [42],
        "repositories": "",
        "tags": "",
        "cve_ids": ""
      }'

The response contains the execution ID:

{
  "id": 12345
}

Checking Export Status

Poll the execution endpoint implemented in GetScanDataExportExecution (lines 13-44 of scanexport.go) to monitor progress. The endpoint returns the job status and a file_present boolean indicating CSV readiness.

curl -X GET "https://harbor.example.com/api/v2.0/scan/data/export/executions/12345" \
  -H "Authorization: Bearer <access_token>"

Successful completion shows:

{
  "id": 12345,
  "status": "Success",
  "file_present": true,
  "export_data_digest": "a3f5c6..."
}

Downloading the CSV Report

When file_present is true, retrieve the file using the DownloadScanData handler (lines 84-103 of scanexport.go). This streams the CSV with Content-Type: text/csv and executes cleanUpArtifact (lines 80-99) to remove the temporary system artifact and execution record after transfer.

curl -L -X GET "https://harbor.example.com/api/v2.0/scan/data/export/executions/12345/download" \
  -H "Authorization: Bearer <access_token>" \
  -o scan_report_42.csv

Listing All Export Executions

To view historical exports for your user account, call the list endpoint handled by GetScanDataExportExecutionList:

curl -X GET "https://harbor.example.com/api/v2.0/scan/data/export/executions" \
  -H "Authorization: Bearer <access_token>"

Core Data Structures and Storage

The export system relies on models defined in src/pkg/scan/export/model.go:

  • export.Data: Defines CSV columns for vulnerability details including CVE IDs, severity, packages, and artifacts
  • export.Request: Contains the project ID array and filter criteria specified during initiation
  • export.Execution: Tracks job status, user ownership via UserName, and the ExportDataDigest referencing the stored blob

The CSV content is persisted using the system artifact manager (src/pkg/systemartifact/manager.go), which stores blobs in Harbor's configured storage backend. The digest stored in the execution record allows the DownloadScanData handler to locate and stream the file to the client.

Permissions and Security Controls

The export endpoints enforce project-level RBAC using rbac.ActionCreate for initiating exports and rbac.ActionRead for downloading or listing executions. Additionally, the DownloadScanData handler compares the request's security context with the execution's UserName field, ensuring users can only access export files they created.

Summary

  • Harbor exports vulnerability scan results asynchronously via POST /api/v2.0/scan/data/export, creating background jobs handled by the jobservice
  • The workflow spans four core files: scanexport.go (API validation), execution.go (controller logic), scan_data_export.go (job implementation), and systemartifact/manager.go (blob storage)
  • CSV files are stored as system artifacts and retrieved via the download endpoint, with automatic cleanup via cleanUpArtifact after streaming
  • Request validation enforces single-project scope and rejects unsupported MIME types or malformed filters containing spaces
  • Access is restricted to the creating user through execution record ownership checks in the handler security context

Frequently Asked Questions

How long does Harbor retain exported vulnerability scan CSV files?

Harbor stores exported CSV files as system artifacts only until the download completes. According to the implementation in src/server/v2.0/handler/scanexport.go, the DownloadScanData handler automatically calls cleanUpArtifact to delete the temporary artifact and execution record after successfully streaming the file to the client.

Can I export vulnerability data from multiple projects simultaneously?

No. The validateScanExportParams function in src/server/v2.0/handler/scanexport.go explicitly validates that exactly one project ID is provided in the request array. If multiple projects are specified, the handler rejects the request with a validation error to ensure manageable processing scope and file sizes.

What CSV columns are included in the vulnerability export?

The export includes fields defined in the export.Data struct from src/pkg/scan/export/model.go, typically containing CVE IDs, severity levels, CVSS scores, package names, artifact repositories, tags, and scan timestamps. The exact column schema depends on your configured scanner adapter's report format.

Why does my export execution show a "Running" status for an extended period?

Large projects with numerous artifacts or extensive vulnerability histories require significant processing time in the Execute method of src/jobservice/job/impl/scandataexport/scan_data_export.go. The job queries the vulnerability database, formats records into CSV rows, writes to system artifact storage, and updates the execution's ExportDataDigest before marking FilePresent=true in the database.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →