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.
- Initiate the Export: Send a POST request to
/api/v2.0/scan/data/exportwith your project ID and optional filters for repositories, tags, or CVE IDs. - Poll for Completion: Query the execution status via
GET /api/v2.0/scan/data/export/executions/{id}untilfile_presentreturnstrue. - 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 artifactsexport.Request: Contains the project ID array and filter criteria specified during initiationexport.Execution: Tracks job status, user ownership viaUserName, and theExportDataDigestreferencing 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), andsystemartifact/manager.go(blob storage) - CSV files are stored as system artifacts and retrieved via the download endpoint, with automatic cleanup via
cleanUpArtifactafter 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →