Skip to main content

CrowdStrike Falcon

The Three-Pillar Model​

The CrowdStrike integration mirrors the Microsoft Defender integration and is built from three pillars. The first two are read-only and active as soon as credentials are saved; the third is an opt-in write pillar documented separately.

PillarDirectionFalcon API scopeDefault
1. Analytics ingest — ZTA posture score, alertsFalcon API → ESAlerts: read, Zero Trust Assessment: read (optional)On once credentials are set
2. Evidence correlation — test ↔ alert matchingES ↔ ESNone extraAutomatic
3. Auto-resolve — close correlated alerts in FalconES → Falcon APIAlerts: writeOpt-in, disabled by default

This page covers pillars 1 and 2. Pillar 3 has its own setup walkthrough — see Auto-Resolve.

Prerequisites​

  • A CrowdStrike Falcon account with access to the Falcon console
  • An API client created in the Falcon console (below)

Falcon Console Setup​

  1. Log in to the Falcon console for your cloud region and go to Support → API Clients and Keys (also reachable via the hamburger menu → Support and resources → API clients and keys).
  2. Click Create API client.
  3. Name: "ProjectAchilles Integration".
  4. Under API Scopes, enable:
    • Alerts: read — required for alert sync
    • Alerts: write — required only if you plan to enable auto-resolve (can be added later by editing the client)
    • Zero Trust Assessment: read — optional; enables the ZTA posture score. Requires Falcon Insight licensing — see ZTA licensing below.
  5. Click Create and note the Client ID and Client Secret — the secret is shown only once.
Enabling auto-resolve later

If you plan to enable auto-resolve, it requires the additional Alerts: write scope. You can grant it now or edit the API client later — the read-only integration runs fine without it.

Cloud Regions​

The integration must point at the Falcon cloud that hosts your tenant. Pick the region in Settings. Configuration is region-only — custom base URLs are not accepted (this prevents SSRF through the integration's outbound HTTP client).

RegionBase URL
US-1 (default)https://api.crowdstrike.com
US-2https://api.us-2.crowdstrike.com
EU-1https://api.eu-1.crowdstrike.com
US-GOV-1https://api.laggar.gcw.crowdstrike.com

Choosing the wrong region is the most common cause of "Test Connection" failures: a client created in US-2 does not authenticate against US-1.

Configuration​

  1. Navigate to Settings → Integrations → CrowdStrike Falcon
  2. Select your cloud region (US-1 by default)
  3. Enter:
    • Client ID — the API client's Client ID
    • Client Secret — the API client's Client Secret
    • Label — optional display name (e.g. "Production Falcon")
  4. Click Save and then Test Connection

Credentials are encrypted at rest with AES-256-GCM. Saving a configuration kicks off an initial sync in the background.

Environment Variable Alternative​

Instead of the UI, the integration can be configured entirely via environment variables. When set, they override the file-based settings (same pattern as Defender):

VariableDescription
CROWDSTRIKE_REGIONFalcon cloud region: us-1 (default), us-2, eu-1, or us-gov-1
CROWDSTRIKE_CLIENT_IDAPI client Client ID
CROWDSTRIKE_CLIENT_SECRETAPI client Client Secret
CROWDSTRIKE_LABELOptional display label

Sync Behavior​

DataSync Interval
AlertsEvery 5 minutes
ZTA posture scoreEvery 6 hours (one daily snapshot document)

In Docker deployments, sync runs via setInterval. On Vercel, sync runs via Cron at /api/cron/crowdstrike-sync.

Initial sync behavior: the first alert sync uses a 90-day lookback (created_timestamp filter) to fetch recent alerts without pulling the entire tenant history. Subsequent syncs resume incrementally from a persisted checkpoint (last_alert_sync). Timestamps are only advanced on successful syncs — failed fetches do not move the watermark.

ZTA Licensing​

The Zero Trust Assessment (ZTA) posture score — CrowdStrike's Secure-Score-equivalent — requires Falcon Insight licensing. The integration degrades gracefully when it is not licensed:

  • the ZTA sync records zta_status: "not_licensed" in the sync status instead of failing,
  • the Analytics tab shows an empty state on the ZTA tile,
  • alert sync, correlation, and auto-resolve are unaffected.

Architecture​

The CrowdStrike integration is composed of four backend services that pull data from the CrowdStrike Falcon API, store it in Elasticsearch, and expose analytics to the frontend.

Falcon Client​

The Falcon client (falcon-client.ts) is a lightweight, SDK-free HTTP client for the CrowdStrike Falcon API. Unlike Defender (which supports certificate auth), CrowdStrike uses secret-only OAuth2 — there is no certificate option.

OAuth2 Client Credentials Flow:

Key behaviors:

  • Token caching with a 5-minute refresh margin before actual expiry (tokens live ~30 minutes)
  • After-token pagination — follows the after token until all alert pages are retrieved (max 1000 per page)
  • 429 retry honoring the Retry-After header (max 3 retries)
  • 401 recovery — invalidates the cached token and re-authenticates once
  • 200-with-errors envelopes — CrowdStrike write APIs return HTTP 200 with a per-item errors[] array; the client inspects errors[] and meta.writes.resources_affected, not just the HTTP status
Do not use the legacy Detects API

The legacy /detects/* endpoints were decommissioned on 2025-09-30. All alert reads use POST /alerts/combined/alerts/v1 (FQL filter, created_timestamp sorting, after-token pagination); alert updates use PATCH /alerts/entities/alerts/v3.

Elasticsearch Storage Model​

All CrowdStrike data is stored in a single index (achilles-crowdstrike) using the same sparse document pattern as Defender, with a doc_type discriminator:

FieldTypeUsed ByDescription
doc_typekeywordAllalert or zta_score
timestampdateAllIngestion or event timestamp
alert_idkeywordalertCrowdStrike composite_id
severitykeywordalertinformational, low, medium, high, critical (mapped from severity_name)
statuskeywordalertnew, in_progress, reopened, closed
mitre_techniqueskeyword[]alertMITRE ATT&CK technique IDs from mitre_attack[]
evidence_hostnameskeyword[]alertHostnames from device.hostname
evidence_filenameskeyword[]alertFilenames/paths from filename / filepath
overall_scorefloatzta_scoreAverage ZTA assessment.overall (0–100)
os_scorefloatzta_scoreAverage ZTA OS sub-score
sensor_config_scorefloatzta_scoreAverage ZTA sensor-config sub-score
device_countintegerzta_scoreDevices included in the snapshot
min_score / max_scorefloatzta_scorePer-device score spread

ZTA snapshots are keyed score-<YYYY-MM-DD> — one document per day.

Elasticsearch API key privileges

If you connect to Elasticsearch with a scoped API key (rather than a superuser), the key must include read, write, and create_index on the achilles-crowdstrike index — the same grants you gave achilles-defender when enabling the Defender integration. Without them the sync fails with an HTTP 403 on the index existence check. (Defender can keep working while CrowdStrike fails, because the key's index list is per-pattern.)

Cross-Correlation Logic​

The analytics service provides four types of cross-correlation between Achilles test results and CrowdStrike data:

1. Detection Rate (per-execution)

The headline metric on the CrowdStrike tab. It is the share of attack-simulation executions — counted per MITRE technique — that have a temporally-correlated CrowdStrike alert:

detectionRate = correlatedExecutions / totalExecutions × 100

Correlation is roll-up aware (a T1574.002 test is satisfied by a parent T1574 alert, one-directionally) and excludes cyber-hygiene controls and skipped bundle stages. The full definition is documented in Analytics → CrowdStrike Falcon.

2. Per-test evidence correlation (alert drawer)

For a single test execution, the alert drawer correlates against CrowdStrike alerts using the same three-tier matching strategy as Defender within a -5 min to +30 min window relative to test completion:

  • Tier 1 — Evidence-based (most precise): matches evidence_filenames containing the test binary's UUID filename AND evidence_hostnames containing the test endpoint's hostname. This proves the specific execution triggered the alert.
  • Tier 2 — Technique + hostname: falls back to MITRE technique IDs scoped by evidence_hostnames. Used when alerts lack file-level evidence.
  • Tier 3 — Technique-only: falls back to MITRE technique ID alone. Used for alerts with no evidence metadata.

The enrichment pass marks matched test documents with f0rtika.crowdstrike_detected / crowdstrike_stage_detected and alert documents with the vendor-neutral f0rtika.achilles_correlated / achilles_test_uuid flags that the auto-resolve pillar reads.

3. Technique Coverage Overlap

Maps MITRE ATT&CK techniques present in both datasets to identify validated coverage, detection gaps, and untested detections.

4. Defense Score vs. ZTA Score Trending

Compares the internal Defense Score with the ZTA posture score over time using aligned date histograms — the CrowdStrike analog of Defender's Secure Score correlation.

Stages killed by the EDR See Exit Codes & Outcomes for the canonical mapping of exit codes, flags, labels, and outcomes.

A stage the EDR kills at launch or mid-run produces an error-category exit code (999, 259, or an unsigned NTSTATUS-style kill code coerced to 999 at ingestion — the raw value is kept in event.ERROR_raw) rather than a conclusive outcome. These stages are still scanned by the enrichment pass, and when alert evidence matches (hostname + stage binary + time window) they are flagged as detected and count toward the Defense Score like any other detection. Genuine test errors with no matching alert stay untouched. The exception is exit 260 (blocked before execution by an ASR/app-control policy): those are never scanned, since a policy block — including the ASR rule the platform excludes by design — is not a detection event.

Vendor-confirmed prevention

Falcon reports what it did about each alert via pattern_disposition (e.g. "Prevention, process killed."). The sync extracts this into prevention_action (quarantined / process_killed / blocked / kill_failed) on the alert doc, and enrichment upgrades matched test stages with crowdstrike_prevented: true (plus the action) under a deliberate qualification rule: stage-binary matches always qualify, while bundle-level matches qualify only when the stage never reached a conclusive outcome — a sibling stage that already ran to completion was not prevented by the kill of a later stage. Prevented stages render as Prevented in the executions view — stronger than Detected — count as protected in the Defense Score, and report as PREVENTED with preventedBy: ['CrowdStrike Falcon'] in the SB compliance report. A failed kill (kill_action_failed) never qualifies. Alert rows also carry portal_url, the exact per-alert Falcon console deep link.

The technique-only fallback in alerts-for-test is hostname-scoped whenever the host is known, so simultaneous fleet-wide runs can't cross-associate one host's alerts onto another host's stages.

Conditional Frontend Display​

All CrowdStrike dashboard elements are conditionally rendered based on the useCrowdStrikeConfig hook:

useCrowdStrikeConfig() → { configured: boolean, loading: boolean }

When configured is false, CrowdStrike panels, tabs, and cross-correlation widgets are hidden entirely — the dashboard shows only Achilles-native analytics.

Deployment Variants​

AspectDocker / Fly.io / RailwayVercel (Serverless)
Backend pathbackend/src/services/crowdstrike/backend-serverless/src/services/crowdstrike/
Settings accessSynchronous file readAsync Vercel Blob read
Sync triggersetInterval at server startupVercel Cron (/api/cron/crowdstrike-sync)
CredentialsEncrypted file or env varsEnv vars or encrypted blob

Both variants expose identical API endpoints and analytics capabilities.

Troubleshooting​

Common Issues
  • "Test Connection" fails with 401: Verify the Client ID / Client Secret, and that the selected cloud region matches the tenant where the API client was created. CrowdStrike scopes take effect per client — no admin consent step is required beyond saving the scope on the client.
  • No data after saving credentials: The first sync runs in the background (alerts every 5 minutes, ZTA every 6 hours). Click Sync Now in the integration settings to trigger an immediate sync.
  • No alerts syncing: Alert sync requires the Alerts: read scope. A 403 from /alerts/combined/alerts/v1 means the scope is missing on the API client.
  • ZTA tile shows "not licensed": ZTA requires Falcon Insight. The integration records zta_status: "not_licensed" and keeps everything else working; grant Zero Trust Assessment: read and confirm licensing if you want the posture score.
  • 403 when enabling auto-resolve: Auto-resolve needs the separate Alerts: write scope. See Auto-Resolve → Troubleshooting.