JFrog Xray: Vulnerability Scanning for Your Artifact Pipeline
JFrog Xray: Vulnerability Scanning for Your Artifact Pipeline
Scanning a container image with a standalone tool like Trivy is a good start. But if your team uses Artifactory as a registry, JFrog Xray takes a different approach: it scans artifacts as they're indexed in Artifactory and blocks promotion or download automatically based on policies you define. No separate scan step in CI, no images that "passed CI" but never got scanned.
This guide sets up Xray scanning, configures policies and watches, and integrates the results into your CI/CD pipeline.
How Xray Works
Xray is a separate service that integrates tightly with Artifactory:
- You index a repository in Xray (once)
- Every artifact pushed to that repo gets scanned automatically
- Xray evaluates the artifact against your security and license policies
- If a policy is violated, Xray can block download, fail a build, or just alert
The key difference from standalone scanners: Xray knows the entire component graph. It scans the artifact plus all its transitive dependencies — a Docker image layer might contain a Node.js app that depends on a library with a CVE three levels deep.
Enable Indexing on Your Repositories
ARTIFACTORY_URL="https://yourcompany.jfrog.io"
TOKEN="your-admin-token"
# Enable Xray indexing on docker-dev-local
curl -u "admin:${TOKEN}" \
-X PUT \
-H "Content-Type: application/json" \
"${ARTIFACTORY_URL}/artifactory/api/repositories/docker-dev-local" \
-d '{"xrayIndex": true}'
# Enable indexing on docker-prod-local
curl -u "admin:${TOKEN}" \
-X PUT \
-H "Content-Type: application/json" \
"${ARTIFACTORY_URL}/artifactory/api/repositories/docker-prod-local" \
-d '{"xrayIndex": true}'
# Trigger a retroactive scan on existing artifacts
curl -u "admin:${TOKEN}" \
-X POST \
"${ARTIFACTORY_URL}/xray/api/v1/index" \
-H "Content-Type: application/json" \
-d '{
"repo_paths": ["docker-dev-local/", "docker-prod-local/"]
}'
Create a Security Policy
Policies define what constitutes a violation. Create a policy that blocks anything with a Critical or High CVE with a CVSS score above 7:
curl -u "admin:${TOKEN}" \
-X POST \
-H "Content-Type: application/json" \
"${ARTIFACTORY_URL}/xray/api/v2/policies" \
-d '{
"name": "block-critical-cves",
"description": "Block Critical and High CVEs with CVSS >= 7",
"type": "security",
"rules": [
{
"name": "critical-cve-rule",
"priority": 1,
"criteria": {
"min_severity": "High",
"cvss_range": {
"from": 7.0,
"to": 10.0
},
"fix_version_dependant": false,
"applicable_cves_only": false
},
"actions": {
"webhooks": [],
"mails": ["[email protected]"],
"fail_build": true,
"block_download": {
"active": true,
"unscanned": false
},
"block_release_bundle_distribution": true,
"notify_deployer": false,
"notify_watch_recipients": true,
"create_ticket_enabled": false
}
}
]
}'
Create a separate license compliance policy:
curl -u "admin:${TOKEN}" \
-X POST \
-H "Content-Type: application/json" \
"${ARTIFACTORY_URL}/xray/api/v2/policies" \
-d '{
"name": "license-compliance",
"description": "Block GPL and AGPL licenses in production",
"type": "license",
"rules": [
{
"name": "no-gpl-in-prod",
"priority": 1,
"criteria": {
"banned_licenses": ["GPL-2.0", "GPL-3.0", "AGPL-3.0"],
"allow_unknown": false,
"multi_license_permissive": false
},
"actions": {
"fail_build": false,
"block_download": {
"active": false
},
"mails": ["[email protected]"],
"notify_watch_recipients": true
}
}
]
}'
Create Watches to Apply Policies
Watches link repositories to policies:
# Watch the prod repo with both policies
curl -u "admin:${TOKEN}" \
-X POST \
-H "Content-Type: application/json" \
"${ARTIFACTORY_URL}/xray/api/v2/watches" \
-d '{
"general_data": {
"name": "prod-security-watch",
"description": "Security and license watch for production images",
"active": true
},
"project_resources": {
"resources": [
{
"type": "repository",
"name": "docker-prod-local",
"bin_mgr_id": "default",
"filters": [
{
"type": "package-type",
"value": "Docker"
}
]
}
]
},
"assigned_policies": [
{
"name": "block-critical-cves",
"type": "security"
},
{
"name": "license-compliance",
"type": "license"
}
],
"watch_recipients": ["[email protected]"]
}'
Query Xray from CI/CD
Use the Xray build scan API to fail your CI pipeline when violations are found:
# In your CI pipeline — scan a specific build
# First, publish build info to Artifactory
jfrog rt build-collect-env BUILD_NAME BUILD_NUMBER
jfrog rt build-publish BUILD_NAME BUILD_NUMBER
# Then scan the build with Xray
jfrog bs BUILD_NAME BUILD_NUMBER \
--fail=true \
--format=simple-json \
--server-id=my-artifactory
# Or use the REST API directly
curl -u "admin:${TOKEN}" \
-X POST \
-H "Content-Type: application/json" \
"${ARTIFACTORY_URL}/xray/api/v1/scanBuild" \
-d '{
"artBuildName": "my-app",
"artBuildNumber": "42",
"rescan": false,
"filters": {
"min_severity": "High"
}
}'
GitHub Actions example:
# .github/workflows/security-scan.yml
name: Build and Security Scan
on:
push:
branches: [main]
jobs:
build-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup JFrog CLI
uses: jfrog/setup-jfrog-cli@v4
env:
JF_URL: ${{ secrets.ARTIFACTORY_URL }}
JF_ACCESS_TOKEN: ${{ secrets.ARTIFACTORY_TOKEN }}
- name: Configure build info
run: |
jf rt build-collect-env ${{ github.repository }} ${{ github.run_number }}
- name: Build Docker image
run: |
jf docker build \
--build-name=${{ github.repository }} \
--build-number=${{ github.run_number }} \
-t ${{ secrets.ARTIFACTORY_URL }}/docker/myapp:${{ github.sha }} .
- name: Push to Artifactory
run: |
jf docker push \
--build-name=${{ github.repository }} \
--build-number=${{ github.run_number }} \
${{ secrets.ARTIFACTORY_URL }}/docker/myapp:${{ github.sha }}
- name: Publish build info
run: |
jf rt build-publish ${{ github.repository }} ${{ github.run_number }}
- name: Xray security scan
run: |
jf bs ${{ github.repository }} ${{ github.run_number }} \
--fail=true \
--format=table
# Pipeline fails here if Critical/High CVEs found
View and Triage Violations
# List all violations in a repository
curl -u "admin:${TOKEN}" \
-X POST \
-H "Content-Type: application/json" \
"${ARTIFACTORY_URL}/xray/api/v1/violations" \
-d '{
"filters": {
"watch_name": "prod-security-watch",
"violation_type": "Security",
"min_severity": "High"
},
"pagination": {
"order_by": "created",
"direction": "desc",
"limit": 25,
"offset": 0
}
}'
# Get scan summary for a specific artifact
curl -u "admin:${TOKEN}" \
"${ARTIFACTORY_URL}/xray/api/v1/summary/artifact" \
-d '{
"paths": ["default/docker-prod-local/myapp/1.0.0/manifest.json"]
}'
CVE Exception Workflow
Not every CVE is exploitable in your context. Xray lets you create exceptions (called "Ignore Rules"):
curl -u "admin:${TOKEN}" \
-X POST \
-H "Content-Type: application/json" \
"${ARTIFACTORY_URL}/xray/api/v1/ignore_rules" \
-d '{
"notes": "CVE-2023-44487 (HTTP/2 rapid reset) — mitigated at load balancer level",
"expiration_date": "2026-06-01",
"ignore_filters": {
"cves": ["CVE-2023-44487"],
"watches": ["prod-security-watch"]
}
}'
Exceptions have mandatory expiration dates — they force you to revisit the decision periodically rather than ignoring CVEs forever.
Summary: Xray vs Standalone Scanners
| Feature | Xray | Trivy/Grype |
|---|---|---|
| Scans on push (automatic) | Yes | CI step required |
| Blocks download of violating artifacts | Yes | No |
| Transitive dependency analysis | Yes | Yes |
| License scanning | Yes | Limited |
| Build-level scan history | Yes | No |
| Policy enforcement without code change | Yes | Pipeline changes needed |
| Cost | Included with Artifactory Enterprise | Free |
Xray is most valuable when you've already standardized on Artifactory. The automatic scan-on-index and download-block capabilities close gaps that CI-only scanning leaves open — a developer pulling an old image directly from the registry bypasses your CI pipeline entirely but not Xray.
Was this article helpful?
DevSecOps Lead
Security-first mindset in everything I ship. From zero-trust architectures to supply chain security, I make sure your pipeline doesn't become your weakest link.
Related Articles
JFrog Xray: Artifact Security Scanning, License Compliance, and Policy Enforcement
How to use JFrog Xray to scan Docker images, Maven JARs, and npm packages for CVEs and license violations — setting up security policies, watching repositories, and blocking builds with policy violations.
Configuring JFrog Artifactory Virtual Repositories For Multi-Team Dependency Resolution
Virtual repositories are the glue that holds multi-team artifact management together. Instead of pointing every team at a dozen different repos, you expose...
Automating Artifactory Cleanup Policies With AQL To Reduce Storage Costs
If you've been running JFrog Artifactory for more than a few months, you've almost certainly had the conversation: *"Why is our storage bill so high?"* Art...
JFrog Artifactory as Your Docker Registry: Setup and Security
Configure JFrog Artifactory as a production Docker registry with virtual repos, access control, image promotion, and cleanup policies.
JFrog Artifactory: Repository Setup and Access Control
Install JFrog Artifactory, configure local, remote, and virtual repositories, set up Docker registries, and manage permissions with access control.
JFrog Artifactory: Setup, Repository Configuration, and Pipeline Integration
How to set up JFrog Artifactory, configure local and remote repositories, integrate with Docker and build tools, use Artifactory query language for artifact searches, and set up release bundles.