rinoxRinox
SIEMSOAR

IBM QRadar to Cortex XSOAR (Palo Alto) Integration

Forward new QRadar offenses into Cortex XSOAR as incidents so playbooks can triage, enrich, and respond automatically. The integration polls QRadar's offense API for offenses updated since the last cursor and creates a matching XSOAR incident with the offense context, source IPs, destination IPs, and rule names attached.

XSOAR's `incidents` API accepts batch creation, which the integration uses to keep round-trips low even when QRadar emits a burst of offenses.

What you get

A real excerpt from a generated IBM QRadar-to-Cortex XSOAR (Palo Alto) integration. The full script ships with logging, env-var loading, error handling, FIFO-capped dedup state, and a README.

qradar_to_xsoar.py
# RINOX INTEGRATION: QRadar -> XSOAR
def fetch_offenses(since_ms):
    headers = {"SEC": QRADAR_TOKEN, "Range": "items=0-999"}
    params  = {"filter": f"last_updated_time>{since_ms}"}
    resp = requests.get(f"{QRADAR_URL}/api/siem/offenses",
                        headers=headers, params=params, timeout=30)
    resp.raise_for_status()
    return resp.json()  # list of offense objects

def to_xsoar_incident(o):
    return {
        "name": f"QRadar #{o['id']} — {o['description'][:80]}",
        "type": "QRadar Offense",
        "severity": magnitude_to_severity(o["magnitude"]),
        "occurred": iso_ms(o["start_time"]),
        "customFields": {"qradar_offense_id": str(o["id"])},
        "labels": [{"type": "Source IP", "value": ip} for ip in o.get("offense_source", "").split(",") if ip],
    }

Common pitfalls

The mistakes that turn this integration from "works once" into "loses data silently for three weeks."

  • 01QRadar offense IDs are integers; XSOAR custom field IDs are strings. Cast at the boundary — the type-safety appendix exists because alphabetical string comparison breaks state cursors.
  • 02QRadar pagination uses the `Range` header, not query parameters. The script sets `Range: items=0-999` and reads `Content-Range` to know how far to advance.
  • 03Map QRadar offense status to XSOAR severity, not status. XSOAR statuses (`pending`, `active`, `done`) are workflow states; XSOAR severity is the analyst-facing field that mirrors QRadar magnitude.
  • 04Idempotent incident creation: use `Custom Fields > qradar_offense_id` as a uniqueness key, and check for an existing incident before creating a new one. Otherwise offense updates create duplicate incidents.

Generate this for your environment.

Pre-fills the form with IBM QRadar and Cortex XSOAR (Palo Alto). You write a sentence about your use case, we write the rest.

Generate IBM QRadarCortex XSOAR (Palo Alto)

Frequently asked

  • What about offense updates after creation?

    The default behaviour is create-once: existing offenses are matched by `qradar_offense_id` custom field and skipped. Set `MODE=sync` to push updates as XSOAR incident updates instead.

  • Does this integration close XSOAR incidents when QRadar closes the offense?

    Optional — `CLOSE_ON_QRADAR_CLOSE=true` closes the matched XSOAR incident with a note. Off by default so the SOC retains its own incident lifecycle.

  • How is this different from XSOAR's built-in QRadar integration?

    XSOAR ships a marketplace pack that does this with a UI. Rinox generates the same logic as a standalone script you own, can audit, and can deploy without a XSOAR marketplace dependency. Choose the right tool for your operating model.

  • What about retries on XSOAR 502s?

    XSOAR is occasionally flaky during deployments. The script retries 502/503/504 with jittered backoff, and never advances the QRadar cursor until at least one XSOAR ACK lands for the batch.