{"id":51677458,"url":"https://github.com/ayman-m/yarascanner","last_synced_at":"2026-07-15T08:33:45.021Z","repository":{"id":370728113,"uuid":"1290847362","full_name":"ayman-m/yarascanner","owner":"ayman-m","description":"Multi-threaded Python YARA scanner for endpoint threat detection, with real-time match streaming to Cortex XDR \u0026 XSIAM.","archived":false,"fork":false,"pushed_at":"2026-07-10T15:12:05.000Z","size":1622,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-10T16:10:48.995Z","etag":null,"topics":["cortex","yara","yara-rules"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ayman-m.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-07-06T09:32:28.000Z","updated_at":"2026-07-10T07:08:41.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ayman-m/yarascanner","commit_stats":null,"previous_names":["ayman-m/yarascanner"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/ayman-m/yarascanner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayman-m%2Fyarascanner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayman-m%2Fyarascanner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayman-m%2Fyarascanner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayman-m%2Fyarascanner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ayman-m","download_url":"https://codeload.github.com/ayman-m/yarascanner/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ayman-m%2Fyarascanner/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35498250,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-15T02:00:06.706Z","response_time":131,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cortex","yara","yara-rules"],"created_at":"2026-07-15T08:33:43.456Z","updated_at":"2026-07-15T08:33:45.007Z","avatar_url":"https://github.com/ayman-m.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# YARA Scanner for Cortex XDR \u0026 XSIAM\n\n[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)\n[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg)](#)\n[![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n\n\u003e Fleet-scale YARA scanning delivered through the Cortex agent — alerts sized for triage,\n\u003e datasets sized for forensics, and delivery accounting that always balances.\n\nA multi-threaded, resource-aware YARA scanning engine designed to run on endpoints **through the\nCortex agent** (Action Center / automation playbooks / scheduled jobs). Matches flow back into the\nCortex platform as alerts, datasets, and dashboards — no extra infrastructure on the endpoint.\n\n---\n\n## 1. Overview\n\n### Two editions, one engine\n\n| | `xdr_yara_scanner.py` (Cortex XDR) | `xsiam_yara_scanner.py` (Cortex XSIAM) |\n|---|---|---|\n| **Delivery APIs** | Insert Parsed Alerts + XQL lookup datasets | HTTP Event Collector (webhook) |\n| **Auth** | XDR API key — Advanced (HMAC) and Standard, **auto-detected** | Single HTTP Collector key |\n| **Alerting model** | One XDR alert per **finding** (file × rule), storm-capped | Raw JSON events; alerting via XSIAM correlation rules |\n| **Forensic record** | Sharded + monthly-rotated lookup datasets (one row per matched string) | Collector dataset (one event per matched string) |\n| **Telemetry** | Match-focused (`UPLOAD_NON_MATCH_DATA=False`); agent covers general telemetry | Full telemetry: stats, performance, resources |\n| **Cancel a running scan** | `cancel` entry point (cooperative, ~5 s) | stop via agent |\n| **Dashboards** | `Yara XDR Scanner (Lookup).json` — 40 widgets | `Yara Matches.json`, `Yara Scan Performance.json` |\n\n### Architecture\n\n```\n┌────────────────────────────────────────────────────────────────┐\n│                      Cortex XDR / XSIAM                        │\n│   ┌────────────┐   ┌───────────┐   ┌────────┐   ┌──────────┐   │\n│   │ Dashboards │   │ Playbooks │   │ Alerts │   │ Datasets │   │\n│   └────────────┘   └───────────┘   └────────┘   └──────────┘   │\n│          ▲               ▲              ▲            ▲         │\n│          └───────────────┴──────┬───────┴────────────┘         │\n│                                 │  public API / HTTP collector │\n└─────────────────────────────────┼──────────────────────────────┘\n                                  │ HTTPS (from the endpoint)\n                   ┌──────────────┴──────────────┐\n              ┌────▼─────┐                  ┌────▼─────┐\n              │ Endpoint │                  │ Endpoint │\n              │  Cortex  │  Action Center   │  Cortex  │\n              │  agent ──┼── runs script ───┼── agent  │\n              │  scanner │                  │  scanner │\n              └──────────┘                  └──────────┘\n```\n\n### Engine capabilities (both editions)\n\n- **Multi-threaded scanning** with a bounded queue and light process priority (agent-friendly)\n- **CPU throttling** — `script` (pause/resume with hysteresis), `os` (idle-tier priority), or `off`\n- **Rule pack handling** — per-rule compile isolation, unavailable-module detection (skips only\n  rules that *import* a missing module), condition-only match summaries, `filename`/`filepath`\n  externals available to rules\n- **Rule-compile disk cache** (XDR edition) — re-runs with an identical pack skip compilation\n- **Junction/symlink cycle protection**, special-file skipping, per-file size limits\n- **Evidence collection** (optional) — matched files zipped on the endpoint\n- **Structured endpoint logs** per run + machine-readable `scan_summary_\u003crun_id\u003e.json`\n- **Log retention** — old run logs pruned automatically (last 10 runs kept)\n\n---\n\n## 2. Quick start (XDR edition)\n\n### Step 1 — set the CUSTOMER CONFIG\n\nAll deployment-wide behaviour lives in one block at the top of `xdr_yara_scanner.py`. Edit it once,\nthen upload — operators never type these again:\n\n| Constant | Values | Default | Effect |\n|----------|--------|---------|--------|\n| `CONFIG_MODE` | scan/cancel | `scan` | Default action for `main` |\n| `CONFIG_CREATE_ALERTS` | True/False | `True` | Insert Parsed Alerts (→ incident creation) |\n| `CONFIG_WRITE_DATASET` | True/False | `True` | Write the lookup datasets |\n| `CONFIG_COLLECT_FILES` | True/False | `False` | Copy matched files into the evidence zip |\n| `CONFIG_THROTTLE_MODE` | script/os/off | `script` | CPU pacing strategy |\n| `CONFIG_CPU_HIGH_THRESHOLD` | int/None | `None` | Pause-entry % CPU (None = profile default) |\n| `CONFIG_CPU_CRITICAL_THRESHOLD` | int/None | `None` | Critical % CPU (None = profile default) |\n| `CONFIG_MAX_PAUSE_SECS` | int/None | `None` | Cap on one continuous CPU pause |\n| `CONFIG_TENANT_ID` | string | `\"\"` | Tenant tag (`\"\"` = derive from API URL) |\n| `CONFIG_LOOKUP_SHARD` | endpoint/none/label | `endpoint` | Per-writer dataset sharding |\n| `CONFIG_ALERT_MAX_PER_SCAN` | int | `500` | Storm cap: max per-finding alerts per scan (`≤0` = uncapped) |\n| `CONFIG_LOOKUP_ROTATION` | monthly/none | `monthly` | Monthly dataset rotation (`_YYYYMM`) |\n| `CONFIG_OPTIONS` | `key=value,...` | `\"\"` | Extra overrides applied every run (rarely needed) |\n\nAlso set the API credentials (`DEFAULT_XDR_API_URL` / `DEFAULT_XDR_API_ID` / `DEFAULT_XDR_API_KEY`).\nBoth XDR auth models are supported and **auto-detected** (Advanced/HMAC and Standard); override with\n`XDR_AUTH_TYPE` if needed. **A scan aborts loudly if delivery is enabled and the credentials are\nstill placeholders** — a misconfigured deployment can't silently scan into the void.\n\n### Step 2 — upload to the script library\n\nConsole → **Action Center → Script Library → Upload**, entry point **`main`**. The signature is the\ninput list, so operators see exactly **3 inputs**:\n\n1. `yarafile` — base64-encoded YARA rules (`python3 encode_rules.py rules.yar`)\n2. `scan_folder` — target path, or `default` for platform defaults\n3. `alert_severity` — `low` | `medium` | `high`\n\nUpload the same file again with entry point **`cancel`** (no inputs) to get a stop button.\n\n### Step 3 — run\n\nTarget endpoints in Action Center and run. Progress, per-run logs, and a `scan_summary_\u003crun_id\u003e.json`\nland on the endpoint under the scanner directory (`C:\\yara_scanner\\` / `/opt/yara_scanner/`);\nmatches land in XDR as alerts + dataset rows as the scan runs.\n\nTo stop a running scan: run the `cancel` entry point on the same endpoint — the scan winds down\nwithin ~5 s, drains its uploaders, and writes a terminal `cancelled` lifecycle row.\n\n---\n\n## 3. How results are delivered (XDR edition)\n\n### 3.1 Alerts — sized for triage\n\n**One alert per finding (file × rule).** A SOC triages *\"this file matched this rule\"*; per-string\nevidence belongs in the dataset. Each alert carries the string-hit count and a sample, and its\nidentity is stable per (rule, file path, host):\n\n- **1:1 with findings** within a scan — a rule with 90 string hits in one file is *one* alert\n- **Idempotent across re-scans** — re-scanning updates the existing alert instead of duplicating it\n- Severity comes from the `alert_severity` run input\n\n**Storm cap.** Past `CONFIG_ALERT_MAX_PER_SCAN` findings (default 500), per-finding alerts stop and\neach affected rule reports the remainder as **one rollup alert** — `YARA Match Storm: \u003crule\u003e |\nHost: \u003chost\u003e` with the suppressed count. Alert volume is bounded by design; nothing goes silent.\n\n**Paced, batched, retried.** Alerts POST in batches (platform cap 60/call), paced under the\nplatform's shared per-key alert budget, honor `Retry-After`, and requeue rate-limited batches for a\nlater delivery window. The end-of-scan drain scales with the backlog.\n\n### 3.2 Lookup datasets — sized for forensics\n\nTwo datasets per endpoint per month:\n\n- **`yara_scanner_matches_v2_\u003chost\u003e_\u003cYYYYMM\u003e`** — one row per matched string: `rule`, `filename`,\n  `file_size`, `file_sha256`, `offset`, `matched_length`, `string`, `severity`, `os_type`,\n  `scan_folder`, `tenant_id`, `scan_id`/`run_id`, timestamps\n- **`yara_scanner_scans_v2_\u003chost\u003e_\u003cYYYYMM\u003e`** — scan lifecycle: `initiated` / `running` heartbeat /\n  `completed` / `cancelled` / `failed`, with counts, throttle posture, and paused time\n\nWhy this shape (both are XDR `add_data` platform characteristics):\n\n- **Sharding (`_\u003chost\u003e`)** — concurrent writers to one dataset collide server-side and lose rows;\n  one writer per dataset lands 100% at any fleet scale.\n- **Rotation (`_\u003cYYYYMM\u003e`)** — `add_data` merge time grows with the dataset's total size, so a\n  bounded dataset keeps bounded write time, permanently.\n\nDashboards and queries are unaffected by either: they fan in with a wildcard\n(`dataset = yara_scanner_matches*`). Old months are pruned explicitly with\n`xdr_action_center.py prune-datasets` / the `delete_dataset` API. The `_v2` tag is the row-schema\nversion — bump it on any row-shape change (datasets can't alter schemas in place).\n\n### 3.3 Delivery accounting — the books always balance\n\nEvery run's `scan_summary_\u003crun_id\u003e.json` reports exactly what landed:\n\n```json\n\"alert_delivery\":   {\"total_matches\": 36243, \"findings\": 401, \"alerts_queued\": 401,\n                     \"successful_uploads\": 401, \"failed_uploads\": 0, \"suppressed\": 0,\n                     \"rollups\": 0, \"undelivered\": 0, \"requeued\": 0},\n\"dataset_delivery\": {\"queued\": 36246, \"batches_sent\": 59, \"records_added\": 27527,\n                     \"records_skipped\": 0, \"send_failures\": 1, \"rows_unconfirmed\": 0,\n                     \"undelivered\": 7719, \"dropped\": 0}\n```\n\n- `findings = successful + failed + undelivered` — anything a bounded drain window can't deliver is\n  **counted and logged**, never silently discarded\n- `suppressed` findings are reported via `rollups`\n- `rows_unconfirmed` marks dataset batches whose *read* timed out — the server merge often commits\n  after the client hangs up, so these are retried once and then counted (blind retries would\n  duplicate rows)\n- The uploads log closes with a one-line truth statement, e.g.\n  `Alert delivery final: findings=401 queued=401 ok=401 failed=0 undelivered=0 ...`\n\n---\n\n## 4. ⚠️ Limitations \u0026 best practices\n\nThe scanner rides two hard platform ceilings. Both are **shared-tenant characteristics of the\nCortex APIs, not tunables** — the scanner is engineered to degrade *predictably and visibly*\nagainst them, and well-tuned rule packs never come near them.\n\n### 4.1 The two ceilings\n\n| Ceiling | What it is | What you see at the limit |\n|---|---|---|\n| **Alert budget** | The Insert Parsed Alerts API allows ~600 alerts/min **per API key, shared across every endpoint using that key** | Batches are paced/retried; a saturated key requeues and, past the delivery budget, counts `undelivered` |\n| **Dataset write time** | Each `add_data` POST triggers a server-side merge whose duration **grows with the dataset's total size** (measured: ~13 s/POST at 15k rows → ~31 s at 77k) | Rows queue behind slow merges; at scan end the drain runs up to its budget (10 min), then counts the remainder `undelivered` |\n\n### 4.2 When you would actually hit them\n\nOne condition produces both: **a rule pack that matches far more than intended** on a large\nfilesystem — e.g. a string common in benign files (a config keyword, a library banner, a copyright\nline) matching tens of thousands of files on a full-drive scan. A measured worst case: one\nover-broad rule on a 465k-file Windows system produced **36,243 string matches across 401 files**\nin a single scan. The finding-grain alert model absorbed it (401 alerts, all delivered), but the\ndataset channel — which records every string hit — queued 36k rows against write times of ~35 s per\n500-row batch, and 7,719 rows hit the drain budget: counted, logged, but absent from the dataset.\n\nA very large fleet scanning concurrently on one API key can also saturate the *alert* budget alone,\neven with tuned rules.\n\n### 4.3 How to avoid it\n\n1. **Tune out false-positive-prone rules before fleet rollout.** Test every new pack against a\n   small representative folder first (`scan_folder` = one directory, not a drive) and read\n   `top_rules` in the scan summary. A rule matching hundreds of files in a small sample will match\n   tens of thousands fleet-wide — fix the rule (anchor strings, add `filesize`/path conditions,\n   require multiple strings) or drop it. **Prefer fewer, specific rules over broad packs.**\n2. **Watch the books.** `alert_delivery.suppressed`, `.undelivered`, and\n   `dataset_delivery.undelivered` in the scan summary (and the dashboard's delivery widgets) are\n   your early-warning signals — non-zero values mean a rule needs tuning, not that data was lost\n   silently.\n3. **Stagger fleet scans** (scheduling waves in the Job/playbook) and/or use **separate API keys\n   per wave** if you must scan thousands of endpoints in one window — the alert budget is per key.\n4. **Let rotation work for you.** Keep `CONFIG_LOOKUP_ROTATION=monthly` (default) so dataset write\n   time stays bounded; prune old months periodically with `prune-datasets`.\n5. **Storm behaviour is a policy knob.** `CONFIG_ALERT_MAX_PER_SCAN` (default 500) decides how many\n   per-finding alerts a runaway scan may emit before rolling up. Raise it only with a tuned pack\n   and a dedicated API key.\n\n\u003e **Design position:** past the ceilings, alerts stay complete at *finding* grain (cap + rollups),\n\u003e the dataset holds everything the write budget allows, and every shortfall is **counted** in the\n\u003e summary. If `undelivered` is consistently non-zero, the fix is in the rules or the schedule — not\n\u003e the endpoint.\n\n---\n\n## 5. XSIAM edition (`xsiam_yara_scanner.py`)\n\nThe XSIAM edition ships every event as standardized JSON to an **HTTP Event Collector** — matches,\nstatistics, performance snapshots, and resource telemetry — and leaves alerting to XSIAM\ncorrelation rules over the ingested dataset.\n\n- **Setup:** set `DEFAULT_API_KEY` / `DEFAULT_API_ENDPOINT` to your collector, upload via the\n  console, entry point `main(yarafile, scan_folder, alert_severity)`. A scan **aborts loudly** if\n  uploads are enabled while the collector credentials are still placeholders.\n- **Delivery:** one JSON event per matched string with bounded per-item retries and backoff.\n  Repetitive per-item log lines are rate-limited on the endpoint (first 20, then periodic\n  summaries), so a sustained failure can't bloat endpoint logs.\n- **Accounting:** the uploads log closes with\n  `Match delivery final: matches=N ok=A failed=B undelivered=C` — items still queued when the\n  shutdown drain expires are counted, never silently dropped.\n- **Rule support:** the same engine features as XDR, plus detailed fallback summaries for\n  condition-only matches.\n- **Dashboards:** `dashboards/Yara Matches.json` and `dashboards/Yara Scan Performance.json` (with\n  their editable XQL under `widgets/`).\n\n---\n\n## 6. Dashboards\n\n| Dashboard | Edition | Contents |\n|---|---|---|\n| `dashboards/Yara XDR Scanner (Lookup).json` | XDR | **40 widgets** over the lookup datasets: detection KPIs, top rules/hosts/files, match timelines, scan throughput, cancellations/failures, alert-vs-dataset delivery health |\n| `dashboards/Yara Matches.json` | XSIAM | Threat-detection view over collector events |\n| `dashboards/Yara Scan Performance.json` | XSIAM | Scan operations: throughput, workers, cache, resources |\n\nImport via **Dashboards → Import**. Every widget's XQL is in `widgets/` (XSIAM) and\n`widgets/xdr_lookup/` (XDR) for customization. The XDR queries use wildcard dataset references, so\nthey span all endpoint shards and months automatically.\n\nExample ad-hoc XQL against the XDR datasets:\n\n```sql\ndataset = yara_scanner_matches*\n| filter severity in (\"High\", \"Medium\")\n| comp count() as hits by rule, hostname\n| sort desc hits | limit 20\n```\n\n---\n\n## 7. Automation \u0026 tooling\n\n### Playbooks (`playbooks/`)\n\n`YARA_Scanner_Runner.yml` / `YARA_Scanner_Canceller.yml` — Action Center automation via the\n**Cortex Core - IR** integration (`core-get-scripts` → `core-get-endpoints` → `core-script-run`),\nplus scheduling guidance for recurring scan Jobs. See `playbooks/README.md` for the required\n3-input script upload.\n\n### API toolkit (`xdr_action_center.py`)\n\nA single CLI/library for driving the whole lifecycle from anywhere with API access:\n\n```bash\npython3 xdr_action_center.py endpoints                    # list agents\npython3 xdr_action_center.py run-scanner --hostname H --rules rules.yar --scan-folder /tmp\npython3 xdr_action_center.py cancel --hostname H\npython3 xdr_action_center.py verify --hostname H          # matches/scans landed?\npython3 xdr_action_center.py xql \"dataset = yara_scanner_scans* | limit 10\"\npython3 xdr_action_center.py prune-datasets --dry-run     # retire legacy/old datasets\n```\n\nCredentials come from `.env` / environment (`XDR_API_URL`, `XDR_API_ID`, `XDR_API_KEY`); both auth\nmodels are auto-detected. Corporate-proxy TLS is supported via `XDR_CA_BUNDLE`.\n\n### Automation skill (`.claude/skills/xdr-action-center-api/`)\n\nA self-contained bundle documenting **which supported public APIs automate each YARA-scan\noperation** (run / cancel / track / results / verify), with a runnable end-to-end example\n(`scripts/yara_scan_automation.py`) usable by humans or LLM agents. Includes a full\nendpoint map (`references/public-api-map.md`) — including why console-internal\n`/api/webapp/*` endpoints must not be scripted, and the supported equivalent for each.\n\n### Test harness (`tests/`)\n\n`gen_rules.py` (rule packs of every shape, 1→500 rules), `seed_corpus.py`, `run_matrix.py`\n(multi-host scan matrix), `analyze.py` (results → report tables). The\n`.claude/skills/xdr-yara-scan-test` skill packages the same flow for assistant-driven testing.\n\n### Guides (`docs/guides/`)\n\n- `XDR_YARA_Scanner_Guide.md` / `.docx` — deployment + operations, XDR edition\n- `XSIAM_YARA_Scanner_Guide.md` / `.docx` — deployment + operations, XSIAM edition\n- `YARA_Scanner_Test_and_Performance_Report.md` / `.docx` — measured performance \u0026 test coverage\n\n---\n\n## 8. Performance\n\nMeasured on 2-worker light profile (agent-friendly defaults), e2-medium-class VMs:\n\n| Scenario | Result |\n|---|---|\n| Linux full-system scan (133k files, 10 rules) | ~2.6 min wall, ~850 files/s |\n| Windows full-drive scan (465k files, 10 rules) | ~25 min wall, ~470–540 files/s |\n| 500-rule pack compile | ~0.2 s (then cached on disk for re-runs) |\n| Small scan end-to-end (scan + alerts + datasets) | ~30–60 s including delivery drains |\n| Finding alerts | delivered 1:1 up to the cap, idempotent across re-scans |\n\nCPU stays under the configured thresholds via throttling; memory footprint is bounded by the scan\nqueue and batch sizes. All figures come from live tenant runs recorded in the performance report.\n\n---\n\n## 9. Security considerations\n\n- **Credentials live in the script** (uploaded to the console script library) or in environment\n  variables for the CLI toolkit — never commit real keys to source control (`.env` is gitignored).\n- The XDR key needs only **Insert Parsed Alerts** + **XQL/lookups** permissions; scope it to a\n  dedicated role. The XSIAM collector key is write-only ingestion.\n- Runs against protected paths degrade gracefully (permission errors are counted + logged, not\n  fatal). Evidence collection (`CONFIG_COLLECT_FILES`) copies matched files — leave it off unless\n  your handling process requires it.\n- All uploads are HTTPS. On TLS-intercepting networks, point `XDR_CA_BUNDLE` /\n  `REQUESTS_CA_BUNDLE` at your CA chain for the CLI toolkit (endpoint agents are unaffected).\n\n---\n\n## 10. Troubleshooting\n\n| Symptom | Meaning / fix |\n|---|---|\n| Result says `SCAN ABORTED — … credentials are not set` | Delivery is enabled but the script still has placeholder creds — edit the `DEFAULT_*` values and re-upload |\n| `alert_delivery.undelivered \u003e 0` | Alert budget saturated (fleet too concurrent, or a match storm) — see §4.3 |\n| `dataset_delivery.undelivered \u003e 0` | Dataset write budget exhausted by a match storm — tune the offending rule (`top_rules` in the summary) |\n| `records_skipped \u003e 0` in dataset delivery | Row shape doesn't match the dataset's schema — bump `LOOKUP_SCHEMA_VERSION` so a fresh dataset is created |\n| A rule never matches | Check `rules_failed` + the failed-rules log on the endpoint: unavailable module imports are skipped by design |\n| Scan is slow on a busy host | That's the throttler honoring CPU thresholds; use `CONFIG_THROTTLE_MODE=os` or raise thresholds for maintenance windows |\n| Alerts don't appear in XDR | Verify the key type/permissions; the scanner auto-detects Advanced (HMAC) vs Standard auth — check `uploads_\u003crun_id\u003e.log` for HTTP status lines |\n\nPer-run logs on the endpoint (`logs/` under the scanner directory): `scanner_`, `uploads_`,\n`scan_errors_`, `statistics_`, `performance_`, `system_`, `yara_processing_` + the\n`scan_summary_\u003crun_id\u003e.json`.\n\n---\n\n## 11. Repository layout\n\n```\n├── xdr_yara_scanner.py            # XDR edition (Action Center: main / cancel)\n├── xsiam_yara_scanner.py          # XSIAM edition (HTTP Collector)\n├── xdr_action_center.py           # API toolkit: run/cancel/verify/xql/prune\n├── encode_rules.py                # rules.yar -\u003e base64 for the yarafile input\n├── test_rules.yar                 # sample rules (stock-binary matches for smoke tests)\n├── dashboards/                    # 3 importable dashboards (XDR lookup + 2 XSIAM)\n├── widgets/                       # per-widget XQL (XSIAM) + xdr_lookup/ (XDR)\n├── playbooks/                     # Runner / Canceller + README\n├── docs/guides/                   # deployment guides + performance report (md + docx)\n└── tests/                         # rule generator, corpus seeder, scan matrix, analyzer\n```\n\n---\n\n## 12. License \u0026 support\n\nMIT — see [LICENSE](LICENSE). Issues and contributions via GitHub. For Cortex platform questions,\nsee the [Cortex XDR](https://docs-cortex.paloaltonetworks.com/p/XDR) and\n[Cortex XSIAM](https://docs-cortex.paloaltonetworks.com/p/XSIAM) documentation; for YARA rule\nauthoring, the [YARA documentation](https://yara.readthedocs.io/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fayman-m%2Fyarascanner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fayman-m%2Fyarascanner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fayman-m%2Fyarascanner/lists"}