v0.1.0-draft AI Drafted

Qualys Hardening Guide

Security Last updated: 2025-02-05

Vulnerability management platform hardening for Qualys VMDR including user access, scanning configuration, and policy compliance

Overview

Qualys is a leading cloud-based vulnerability management and compliance platform protecting millions of assets across enterprises worldwide. As a critical security tool with deep access to infrastructure, Qualys configurations directly impact vulnerability visibility and remediation effectiveness. Proper hardening ensures security data integrity and prevents unauthorized access to sensitive vulnerability information.

Intended Audience

  • Security engineers managing vulnerability programs
  • IT administrators configuring Qualys
  • GRC professionals using Policy Compliance
  • SOC analysts managing vulnerability data

How to Use This Guide

  • L1 (Baseline): Essential controls for all organizations
  • L2 (Hardened): Enhanced controls for security-sensitive environments
  • L3 (Maximum Security): Strictest controls for regulated industries

Scope

This guide covers Qualys platform security including user management, scanning configuration, policy compliance, and Security Configuration Assessment (SCA).


Table of Contents

  1. Access & Authentication
  2. Scanning Configuration
  3. Policy Compliance
  4. Asset Management
  5. Compliance Quick Reference

1. Access & Authentication

1.1 Configure SSO Authentication

Profile Level: L2 (Hardened)

Framework Control
CIS Controls 6.3, 12.5
NIST 800-53 IA-2, IA-8

Description

Configure SAML SSO to centralize authentication for Qualys platform.

ClickOps Implementation

Step 1: Access SSO Settings

  1. Navigate to: AdministrationUser ManagementAuthentication
  2. Click SAML Authentication

Step 2: Configure SAML

  1. Enable SAML authentication
  2. Configure IdP settings:
    • IdP SSO URL
    • IdP Certificate
    • Entity ID
  3. Download Qualys SP metadata

Step 3: Configure IdP

  1. Create SAML application
  2. Configure attribute mappings
  3. Assign users/groups

Step 4: Enable SSO Enforcement

  1. Test SSO authentication
  2. Enable SSO for users
  3. Disable password authentication

Time to Complete: ~1 hour


1.2 Enforce Multi-Factor Authentication

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 6.5
NIST 800-53 IA-2(1)

Description

Require MFA for all users, especially administrators.

Rationale

Why This Matters:

  • Admin accounts without MFA pose significant risk
  • Qualys admins have access to all vulnerability data
  • MFA should be enforced via SSO/IdP

ClickOps Implementation

Step 1: Configure MFA for Non-SSO Users

  1. Navigate to: AdministrationUser ManagementUsers
  2. Enable 2FA requirement for each user
  3. Or enforce through SSO/IdP

Step 2: Protect Admin Accounts

  1. Ensure all admin accounts have MFA
  2. Use strong passwords stored in vault
  3. Consider hardware keys for admins

Step 3: Verify Compliance

  1. Review user MFA status
  2. Follow up with non-compliant users
  3. Document exceptions

1.3 Implement Role-Based Access Control

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 5.4
NIST 800-53 AC-6

Description

Configure granular roles for least privilege access.

ClickOps Implementation

Step 1: Review Built-in Roles

  1. Navigate to: AdministrationUser ManagementRoles
  2. Review available roles:
    • Manager: Full administrative access
    • Unit Manager: Team management
    • Scanner: Scanning only
    • Reader: View only

Step 2: Create Custom Roles

  1. Click New Role
  2. Configure permissions:
    • Asset management
    • Scanning
    • Reporting
    • Policy compliance
  3. Apply principle of least privilege

Step 3: Assign Appropriate Roles

  1. Limit Manager to essential personnel (2-3)
  2. Use Scanner for vulnerability teams
  3. Use Reader for stakeholders

Code Pack: API Script
hth-qualys-1.03-implement-rbac.sh View source on GitHub ↗
# Fetch all users and audit role assignments
# Qualys v2 user list returns XML with USER_LIST/USER elements
USER_XML=$(ql_get "/auth/user/?action=list" 2>/dev/null) || {
  fail "1.3 Failed to retrieve user list (requires Manager role)"
  increment_failed
  summary
  exit 1
}

# Count users by role type
TOTAL_USERS=$(echo "${USER_XML}" | xml_count "USER")
MANAGER_COUNT=$(echo "${USER_XML}" | grep -c "<USER_ROLE>Manager</USER_ROLE>" || echo "0")
ADMIN_COUNT=$(echo "${USER_XML}" | grep -c "<USER_ROLE>Unit Manager</USER_ROLE>" || echo "0")
READER_COUNT=$(echo "${USER_XML}" | grep -c "<USER_ROLE>Reader</USER_ROLE>" || echo "0")
SCANNER_COUNT=$(echo "${USER_XML}" | grep -c "<USER_ROLE>Scanner</USER_ROLE>" || echo "0")

info "1.3 Total users: ${TOTAL_USERS}"
info "1.3 Managers: ${MANAGER_COUNT} | Unit Managers: ${ADMIN_COUNT}"
info "1.3 Scanners: ${SCANNER_COUNT} | Readers: ${READER_COUNT}"

# Flag if more than 3 Manager-level accounts exist
if [ "${MANAGER_COUNT}" -gt 3 ]; then
  warn "1.3 ${MANAGER_COUNT} Manager accounts detected -- review for least-privilege"
  warn "1.3 Best practice: limit Manager role to 2-3 accounts maximum"
fi
# List all users with Manager or Unit Manager roles for review
info "1.3 Privileged users requiring review:"
echo "${USER_XML}" | grep -B5 -A5 "<USER_ROLE>Manager</USER_ROLE>" \
  | grep -oP "<USER_LOGIN>\K[^<]+" | while read -r login; do
    warn "1.3   Manager: ${login}"
  done
echo "${USER_XML}" | grep -B5 -A5 "<USER_ROLE>Unit Manager</USER_ROLE>" \
  | grep -oP "<USER_LOGIN>\K[^<]+" | while read -r login; do
    warn "1.3   Unit Manager: ${login}"
  done
Code Pack: Sigma Detection Rule
hth-qualys-1.03-admin-role-assigned.yml View source on GitHub ↗
detection:
    selection_create:
        Action: 'User Created'
    selection_modify:
        Action: 'User Role Modified'
    selection_role:
        Details|contains:
            - 'Manager'
            - 'Unit Manager'
    condition: (selection_create or selection_modify) and selection_role
fields:
    - Date
    - User
    - Action
    - Details
    - UserLogin

1.4 Configure IP Restrictions

Profile Level: L2 (Hardened)

Framework Control
CIS Controls 13.5
NIST 800-53 AC-17

Description

Restrict Qualys access to approved IP addresses.

ClickOps Implementation

Step 1: Configure IP Allowlist

  1. Navigate to: AdministrationUser ManagementAllowed IPs
  2. Add corporate network IPs
  3. Add VPN egress IPs

Step 2: Apply to User Accounts

  1. Configure IP restrictions per user
  2. Apply stricter restrictions to admins
  3. Test access restrictions

2. Scanning Configuration

2.1 Secure Scan Credentials

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 3.11
NIST 800-53 SC-12

Description

Securely manage credentials used for authenticated scanning.

Rationale

Why This Matters:

  • Scan credentials have privileged access
  • Compromised credentials can expose infrastructure
  • Qualys encrypts credentials but proper management is critical

ClickOps Implementation

Step 1: Create Dedicated Scan Accounts

  1. Create dedicated service accounts for scanning
  2. Grant minimum required permissions:
    • Read access for vulnerability scanning
    • Admin only if compliance required
  3. Do not use admin/root accounts

Step 2: Configure Credential Vaults

  1. Navigate to: ScansAuthenticationVault
  2. Configure credential vault integration:
    • CyberArk
    • HashiCorp Vault
    • Thycotic
  3. Retrieve credentials dynamically

Step 3: Rotate Credentials

  1. Establish rotation schedule
  2. Update credentials in Qualys
  3. Verify scanning still works

Code Pack: Sigma Detection Rule
hth-qualys-2.01-scan-credential-modified.yml View source on GitHub ↗
detection:
    selection:
        Action|contains:
            - 'Credential Created'
            - 'Credential Updated'
            - 'Credential Deleted'
            - 'Authentication Record Created'
            - 'Authentication Record Updated'
            - 'Authentication Record Deleted'
    condition: selection
fields:
    - Date
    - User
    - Action
    - Details

2.2 Configure Scan Options

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 7.1
NIST 800-53 RA-5

Description

Configure appropriate scan options for comprehensive coverage.

ClickOps Implementation

Step 1: Configure Scan Profiles

  1. Navigate to: ScansOption Profiles
  2. Create profiles for different use cases:
    • Full vulnerability scan
    • Authenticated scan
    • PCI compliance scan

Step 2: Configure Scan Settings

  1. Configure appropriate settings:
    • Port ranges
    • Performance settings
    • Authentication type
  2. Balance thoroughness with impact

Step 3: Schedule Scans

  1. Configure scan schedules
  2. Avoid production impact times
  3. Ensure full coverage

Code Pack: API Script
hth-qualys-2.02-configure-scan-options.sh View source on GitHub ↗
# List all scan option profiles and check for hardened configuration
PROFILES_XML=$(ql_get "/scan/option_profile/?action=list" 2>/dev/null) || {
  fail "2.2 Failed to retrieve scan option profiles"
  increment_failed
  summary
  exit 1
}

PROFILE_COUNT=$(echo "${PROFILES_XML}" | xml_count "OPTION_PROFILE")
info "2.2 Found ${PROFILE_COUNT} scan option profile(s)"

# Check each profile for vulnerability detection settings
# A hardened profile should have:
#   - TCP and UDP scanning enabled
#   - Authentication scanning enabled
#   - All port ranges covered (1-65535)
echo "${PROFILES_XML}" | grep -oP "<TITLE>\K[^<]+" | while read -r title; do
  info "2.2   Profile: ${title}"
done
# List recent scans to verify scanning is active and not stale
SCANS_XML=$(ql_get "/scan/?action=list" 2>/dev/null) || {
  warn "2.2 Failed to retrieve scan list"
  SCANS_XML=""
}

if [ -n "${SCANS_XML}" ]; then
  SCAN_COUNT=$(echo "${SCANS_XML}" | xml_count "SCAN")
  info "2.2 Found ${SCAN_COUNT} scan(s) in history"

  # Check for scans in the last 30 days
  RECENT_SCANS=$(echo "${SCANS_XML}" | grep -c "<STATUS>Finished</STATUS>" || echo "0")
  if [ "${RECENT_SCANS}" -gt 0 ]; then
    pass "2.2 ${RECENT_SCANS} completed scan(s) found"
  else
    warn "2.2 No recently completed scans -- verify scan scheduling"
  fi
fi

2.3 Configure Agent Security

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 7.1
NIST 800-53 RA-5

Description

Securely configure Qualys Cloud Agents.

ClickOps Implementation

Step 1: Secure Agent Deployment

  1. Use secure distribution methods
  2. Deploy with endpoint management
  3. Verify agent integrity

Step 2: Configure Agent Settings

  1. Navigate to: AgentsAgent Configuration
  2. Configure:
    • Activation key security
    • Communication intervals
    • Local scanning options

Step 3: Monitor Agent Status

  1. Monitor agent health
  2. Alert on disconnected agents
  3. Investigate failed deployments

3. Policy Compliance

3.1 Configure CIS Benchmark Assessments

Profile Level: L2 (Hardened)

Framework Control
CIS Controls 4.1
NIST 800-53 CM-6

Description

Configure Policy Compliance for CIS Benchmark assessments.

Rationale

Why This Matters:

  • Qualys covers more CIS benchmarks than competitors
  • System hardening reduces attack surface
  • Improves security posture from 51% to 80% average

ClickOps Implementation

Step 1: Enable Policy Compliance

  1. Navigate to: Policy CompliancePolicies
  2. Review available CIS benchmarks
  3. Select appropriate benchmarks for your environment

Step 2: Configure Compliance Profiles

  1. Create compliance profile
  2. Select CIS benchmark (Level 1 or Level 2)
  3. Configure exceptions if needed

Step 3: Run Compliance Scan

  1. Schedule compliance assessments
  2. Review compliance reports
  3. Prioritize remediation

3.2 Configure DISA STIG Assessments

Profile Level: L2 (Hardened)

Framework Control
CIS Controls 4.1
NIST 800-53 CM-6

Description

Configure DISA STIG assessments for government compliance.

ClickOps Implementation

Step 1: Select STIG Templates

  1. Navigate to: Policy ComplianceTemplates
  2. Select DISA STIG templates:
    • Operating systems
    • Databases
    • Network devices
    • Applications

Step 2: Create Compliance Policy

  1. Create policy from STIG template
  2. Configure applicable findings
  3. Document exceptions

Step 3: Assess and Remediate

  1. Run STIG assessments
  2. Generate compliance reports
  3. Track remediation progress

3.3 Configure Security Configuration Assessment

Profile Level: L2 (Hardened)

Framework Control
CIS Controls 4.1
NIST 800-53 CM-6

Description

Use Qualys SCA for automated configuration assessment.

ClickOps Implementation

Step 1: Enable SCA

  1. Navigate to: Vulnerability ManagementSCA
  2. Enable Security Configuration Assessment

Step 2: Configure SCA Profiles

  1. Select benchmark profiles
  2. Configure assessment frequency
  3. Enable automated alerting

Step 3: Review Results

  1. Review configuration findings
  2. Prioritize by severity
  3. Track hardening progress

4. Asset Management

4.1 Configure Asset Discovery

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 1.1
NIST 800-53 CM-8

Description

Configure comprehensive asset discovery for visibility.

ClickOps Implementation

Step 1: Configure Discovery Methods

  1. Navigate to: AssetsAsset Discovery
  2. Configure:
    • Network scanning
    • Cloud connectors
    • Agent deployment
    • Passive discovery

Step 2: Configure Asset Tagging

  1. Create asset tags for organization
  2. Apply tags automatically
  3. Use tags for scan targeting

Step 3: Monitor for Rogue Assets

  1. Configure alerts for new assets
  2. Flag unmanaged devices
  3. Integrate with ITSM

Code Pack: API Script
hth-qualys-4.01-configure-asset-discovery.sh View source on GitHub ↗
# Retrieve asset host list and check inventory health
HOSTS_XML=$(ql_get "/asset/host/?action=list&truncation_limit=0" 2>/dev/null) || {
  fail "4.1 Failed to retrieve host list"
  increment_failed
  summary
  exit 1
}

TOTAL_HOSTS=$(echo "${HOSTS_XML}" | xml_count "HOST")
info "4.1 Total hosts in inventory: ${TOTAL_HOSTS}"

# Check for hosts with no last scan date (never scanned)
UNSCANNED=$(echo "${HOSTS_XML}" | grep -c "<LAST_VULN_SCAN_DATETIME/>" || echo "0")
if [ "${UNSCANNED}" -gt 0 ]; then
  warn "4.1 ${UNSCANNED} host(s) have never been vulnerability scanned"
else
  pass "4.1 All hosts have been scanned at least once"
fi
# Use v3 API to check asset tagging for organization
TAGS_JSON=$(ql_v3_get "/get/am/tag" 2>/dev/null) || {
  warn "4.1 Failed to retrieve asset tags (v3 API)"
  TAGS_JSON=""
}

if [ -n "${TAGS_JSON}" ]; then
  TAG_COUNT=$(echo "${TAGS_JSON}" | grep -oP '"count"\s*:\s*\K[0-9]+' | head -1 || echo "0")
  info "4.1 Asset tags defined: ${TAG_COUNT}"
  if [ "${TAG_COUNT}" -lt 1 ]; then
    warn "4.1 No asset tags defined -- create tags to organize assets by environment/criticality"
  else
    pass "4.1 Asset tagging is configured (${TAG_COUNT} tag(s))"
  fi
fi
# Check for hosts with active detections to verify scanning coverage
DETECTIONS_XML=$(ql_get "/asset/host/vm/detection/?action=list&truncation_limit=10" 2>/dev/null) || {
  warn "4.1 Failed to retrieve host detections"
  DETECTIONS_XML=""
}

if [ -n "${DETECTIONS_XML}" ]; then
  DETECTION_COUNT=$(echo "${DETECTIONS_XML}" | xml_count "DETECTION")
  info "4.1 Sample detection count: ${DETECTION_COUNT}"
  if [ "${DETECTION_COUNT}" -gt 0 ]; then
    pass "4.1 Vulnerability detections present -- scanning is active"
  else
    warn "4.1 No detections found -- verify scanner appliances are functioning"
  fi
fi

4.2 Configure Cloud Connector Security

Profile Level: L1 (Baseline)

Framework Control
CIS Controls 1.1
NIST 800-53 CM-8

Description

Securely configure cloud provider connectors.

ClickOps Implementation

Step 1: AWS Connector

  1. Navigate to: AssetsConnectorsAWS
  2. Create IAM role with minimum permissions
  3. Configure cross-account access

Step 2: Azure Connector

  1. Create app registration
  2. Grant minimum required permissions
  3. Configure connector

Step 3: GCP Connector

  1. Create service account
  2. Grant minimum roles
  3. Configure connector

Code Pack: API Script
hth-qualys-4.02-configure-cloud-connectors.sh View source on GitHub ↗
# Search for cloud assets via the v3 Asset Management API
# Cloud connectors (AWS, Azure, GCP) sync assets automatically
CLOUD_ASSETS=$(ql_v3_post "/search/am/asset" '{
  "filters": [
    {
      "field": "sourceCategory",
      "operator": "IN",
      "value": "cloud"
    }
  ],
  "preferences": {
    "startFromOffset": 0,
    "limitResults": 10
  }
}' 2>/dev/null) || {
  warn "4.2 Failed to query cloud assets (v3 API)"
  CLOUD_ASSETS=""
}

if [ -n "${CLOUD_ASSETS}" ]; then
  CLOUD_COUNT=$(echo "${CLOUD_ASSETS}" | grep -oP '"count"\s*:\s*\K[0-9]+' | head -1 || echo "0")
  info "4.2 Cloud-sourced assets: ${CLOUD_COUNT}"

  if [ "${CLOUD_COUNT}" -gt 0 ]; then
    pass "4.2 Cloud connectors are active (${CLOUD_COUNT} assets synced)"
  else
    warn "4.2 No cloud assets found -- configure AWS/Azure/GCP connectors"
  fi
fi
# Check activity log for recent connector sync events
ACTIVITY_XML=$(ql_get "/activity_log/?action=list&truncation_limit=50" 2>/dev/null) || {
  warn "4.2 Failed to retrieve activity log"
  ACTIVITY_XML=""
}

if [ -n "${ACTIVITY_XML}" ]; then
  # Look for cloud connector-related activity
  CONNECTOR_EVENTS=$(echo "${ACTIVITY_XML}" | grep -ci "connector\|cloud\|aws\|azure\|gcp" || echo "0")
  info "4.2 Cloud connector activity events (last 50): ${CONNECTOR_EVENTS}"

  if [ "${CONNECTOR_EVENTS}" -gt 0 ]; then
    pass "4.2 Recent cloud connector activity detected"
  else
    warn "4.2 No recent cloud connector activity -- verify connectors are scheduled"
  fi
fi
# Identify cloud assets that have not been scanned
UNSCANNED_CLOUD=$(ql_v3_post "/search/am/asset" '{
  "filters": [
    {
      "field": "sourceCategory",
      "operator": "IN",
      "value": "cloud"
    },
    {
      "field": "lastVulnScan",
      "operator": "NONE",
      "value": ""
    }
  ],
  "preferences": {
    "startFromOffset": 0,
    "limitResults": 10
  }
}' 2>/dev/null) || {
  UNSCANNED_CLOUD=""
}

if [ -n "${UNSCANNED_CLOUD}" ]; then
  UNSCANNED_COUNT=$(echo "${UNSCANNED_CLOUD}" | grep -oP '"count"\s*:\s*\K[0-9]+' | head -1 || echo "0")
  if [ "${UNSCANNED_COUNT}" -gt 0 ]; then
    warn "4.2 ${UNSCANNED_COUNT} cloud asset(s) have not been vulnerability scanned"
  else
    pass "4.2 All cloud assets have been scanned"
  fi
fi

4.3 Configure Approval Workflows

Profile Level: L2 (Hardened)

Framework Control
CIS Controls 4.1
NIST 800-53 CM-3

Description

Configure approval workflows for automated remediation.

ClickOps Implementation

Step 1: Configure Workflows

  1. Navigate to: AdministrationWorkflows
  2. Configure approval requirements:
    • Maintenance windows
    • Risk level thresholds
    • Automated vs. manual actions

Step 2: Set Approval Roles

  1. Define approvers
  2. Configure escalation
  3. Set timeout actions

5. Compliance Quick Reference

SOC 2 Trust Services Criteria Mapping

Control ID Qualys Control Guide Section
CC6.1 SSO/MFA 1.1
CC6.2 RBAC 1.3
CC6.6 IP restrictions 1.4
CC7.1 Vulnerability scanning 2.2
CC7.2 Configuration assessment 3.3

NIST 800-53 Rev 5 Mapping

Control Qualys Control Guide Section
IA-2 SSO 1.1
IA-2(1) MFA 1.2
RA-5 Vulnerability scanning 2.2
CM-6 Configuration assessment 3.1
CM-8 Asset discovery 4.1

Appendix A: References

Official Qualys Documentation:

API & Developer Resources:

Compliance & Certifications:

Security Incidents:

  • Accellion FTA Breach (2021): Qualys confirmed data was accessed via a zero-day vulnerability in the Accellion FTA file transfer appliance used by Qualys. Production environments and customer data on the Qualys Cloud Platform were not affected.
  • Salesloft/Drift Supply Chain Attack (September 2025): Attackers exfiltrated OAuth tokens from breached Salesloft/Drift infrastructure and accessed some data in Qualys’s Salesforce environment (leads and contacts). No impact to Qualys production environments, codebase, or customer platform data. Mandiant was engaged for investigation.

Changelog

Date Version Maturity Changes Author
2025-02-05 0.1.0 draft Initial guide with access controls, scanning, and policy compliance Claude Code (Opus 4.5)

Contributing

Found an issue or want to improve this guide?