DevOpsil
87%

JFrog Xray: Artifact Security Scanning, License Compliance, and Policy Enforcement

Sarah ChenSarah Chen5 min read

What JFrog Xray Does

JFrog Xray is the security and compliance layer of the JFrog platform. It continuously scans every artifact stored in Artifactory:

  • CVE scanning: Identifies known vulnerabilities in package dependencies
  • License compliance: Flags artifacts with licenses that violate your policy (e.g., GPL in proprietary products)
  • Operational risk: Identifies unmaintained packages, end-of-life components
  • Impact analysis: Given a vulnerability, shows which builds and deployments are affected
  • Policy enforcement: Blocks downloads or fails CI builds based on violation severity

Xray operates on your Artifactory artifacts — it doesn't scan source code, it scans the actual packaged artifacts and their transitive dependencies.


Xray Architecture

Xray maintains its own vulnerability database (updated from NVD, GitHub Advisory, and VulnDB). When an artifact lands in Artifactory:

  1. Xray receives a notification
  2. It extracts the component graph (all transitive dependencies)
  3. It queries its database for known CVEs and license data
  4. It stores results and applies configured policies
  5. Violations trigger notifications, block downloads, or fail CI

Installation

Xray is a separate service that integrates with Artifactory. Deploy via Helm (Kubernetes):

helm repo add jfrog https://charts.jfrog.io

# Install Xray alongside Artifactory
helm upgrade --install xray jfrog/xray \
  --namespace jfrog \
  --set xray.jfrogUrl=http://artifactory:8082 \
  --set xray.masterKey=$(openssl rand -hex 32) \
  --set postgresql.postgresqlPassword=xray_password \
  --set rabbitmq.auth.password=rabbit_password

For JFrog Cloud (SaaS), Xray is included — no separate installation.


Configuring Security Policies

Policies define what counts as a violation and what action to take.

Create a Security Policy

In the Xray UI: Xray → Policies & Watches → New Policy

Or via REST API:

curl -u admin:password -X POST \
  "http://artifactory.example.com:8082/xray/api/v2/policies" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "block-critical-cves",
    "type": "security",
    "description": "Block artifacts with critical CVEs",
    "rules": [
      {
        "name": "critical-rule",
        "priority": 1,
        "criteria": {
          "min_severity": "critical"
        },
        "actions": {
          "block_download": {
            "active": true,
            "unscanned": false
          },
          "fail_build": true,
          "notify_deployer": true
        }
      },
      {
        "name": "high-rule",
        "priority": 2,
        "criteria": {
          "min_severity": "high",
          "fix_version_dependence": true   // only fail if a fix exists
        },
        "actions": {
          "fail_build": true,
          "notify_deployer": true
        }
      }
    ]
  }'

Create a License Compliance Policy

curl -u admin:password -X POST \
  "http://artifactory.example.com:8082/xray/api/v2/policies" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "license-compliance",
    "type": "license",
    "rules": [
      {
        "name": "block-gpl",
        "priority": 1,
        "criteria": {
          "banned_licenses": ["GPL-2.0", "GPL-3.0", "AGPL-3.0"],
          "allow_unknown": false
        },
        "actions": {
          "block_download": {
            "active": true
          },
          "fail_build": true
        }
      }
    ]
  }'

Watches: Applying Policies to Repositories

A Watch links a policy to one or more repositories or builds:

# Watch all production repos
curl -u admin:password -X POST \
  "http://artifactory.example.com:8082/xray/api/v2/watches" \
  -H "Content-Type: application/json" \
  -d '{
    "general_data": {
      "name": "production-watch",
      "description": "Watch all production repositories",
      "active": true
    },
    "project_resources": {
      "resources": [
        {
          "type": "repository",
          "name": "libs-release-local",
          "bin_mgr_id": "default"
        },
        {
          "type": "repository",
          "name": "docker-local",
          "bin_mgr_id": "default"
        }
      ]
    },
    "assigned_policies": [
      {
        "name": "block-critical-cves",
        "type": "security"
      },
      {
        "name": "license-compliance",
        "type": "license"
      }
    ]
  }'

CI/CD Integration: Scanning in GitHub Actions

name: Build and Scan

on:
  push:
    branches: [main]

jobs:
  build-and-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: Build and publish with build info
        run: |
          jf mvn clean install \
            --build-name="$GITHUB_REPOSITORY" \
            --build-number="$GITHUB_RUN_NUMBER"

          # Publish build info to Artifactory (Xray scans this)
          jf rt build-publish "$GITHUB_REPOSITORY" "$GITHUB_RUN_NUMBER"

      - name: Scan build with Xray
        run: |
          jf rt build-scan \
            "$GITHUB_REPOSITORY" \
            "$GITHUB_RUN_NUMBER" \
            --fail   # fails the step if policy violations found

      - name: Docker build and scan
        run: |
          docker build -t myapp:$GITHUB_SHA .
          
          # Scan local Docker image before push
          jf docker scan myapp:$GITHUB_SHA

          # Push only if scan passed
          docker tag myapp:$GITHUB_SHA \
            ${{ secrets.ARTIFACTORY_URL }}/docker-local/myapp:$GITHUB_SHA
          jf docker push \
            ${{ secrets.ARTIFACTORY_URL }}/docker-local/myapp:$GITHUB_SHA

Scanning Docker Images from CLI

# Scan a Docker image (must be in Artifactory)
jf docker scan myapp:latest

# Output example:
# [Info] Scanning image...
# SEVERITY  CVE              IMPACTED PACKAGE   VERSION  FIXED VERSIONS  DESCRIPTION
# Critical  CVE-2024-23897   log4j-core         2.14.1   2.17.1+         Log4j RCE
# High      CVE-2023-44487   h2                 2.1.214  2.2.220+        HTTP/2 DoS

# Get full JSON report
jf docker scan myapp:latest --output json > scan-report.json

# Scan and fail if critical vulnerabilities found
jf docker scan myapp:latest --fail-no-op --min-severity Critical

Generating SBOMs

Software Bill of Materials — required for supply chain compliance (SLSA, EO 14028):

# Generate SBOM for an artifact
jf rt curl -XGET \
  "api/v1/component/exportDetails" \
  -H "Content-Type: application/json" \
  -d '{
    "component_name": "myapp",
    "package_type": "docker",
    "component_version": "1.2.0",
    "licenses": true,
    "security": true,
    "output_format": "spdx"
  }' > sbom.spdx.json

# Or CYCLONEDX format (more widely supported in tools)
# Change "output_format": "cyclonedx"

Checking Violation Status

# Get violations for a specific artifact
curl -u admin:password \
  "http://artifactory.example.com:8082/xray/api/v1/violations" \
  -G \
  --data-urlencode "component=docker://docker-local/myapp:latest"

# Get all violations in the last 7 days
curl -u admin:password -X POST \
  "http://artifactory.example.com:8082/xray/api/v1/violations" \
  -H "Content-Type: application/json" \
  -d '{
    "filters": {
      "created_from": "2026-03-26T00:00:00Z",
      "min_severity": "high",
      "watch_name": "production-watch"
    },
    "pagination": {
      "order_by": "created",
      "direction": "desc",
      "limit": 25,
      "offset": 0
    }
  }'

Impact Analysis: Which Deployments Are Affected?

When a new CVE drops, Xray's Impact Analysis tells you which artifacts and builds are affected:

In the UI: Xray → Reports → Impact Analysis → Search by CVE ID.

Via API:

curl -u admin:password -X POST \
  "http://artifactory.example.com:8082/xray/api/v1/component/impactGraph" \
  -H "Content-Type: application/json" \
  -d '{
    "package_name": "log4j-core",
    "package_version": "2.14.1",
    "package_type": "maven"
  }'

Returns a tree of all artifacts that contain this version of log4j-core — letting you prioritize remediation based on which production artifacts are affected.

Share:

Was this article helpful?

Sarah Chen
Sarah Chen

CI/CD Engineering Lead

Automation evangelist who believes no deployment should require a human. I write pipelines, break pipelines, and write about both. Code-first, always.

Related Articles

Discussion