Skip to content

[Enhancement] Windows: Add scheduled task parsing support#19193

Draft
w0rk3r wants to merge 12 commits into
mainfrom
scheduled_tasks_parser
Draft

[Enhancement] Windows: Add scheduled task parsing support#19193
w0rk3r wants to merge 12 commits into
mainfrom
scheduled_tasks_parser

Conversation

@w0rk3r

@w0rk3r w0rk3r commented May 25, 2026

Copy link
Copy Markdown
Contributor

Proposed commit message

windows, system: parse Security scheduled task XML

Extract selected TaskContent XML fields into winlog.scheduled_task.* for
Security scheduled task events. Add pipeline tests, field definitions,
generated docs, and a pipeline benchmark for the hot parsing path.

Summary

Related issue: github.com/elastic/ia-trade-team/issues/892

Windows Security scheduled task events expose high-value task definition metadata primarily as raw XML in winlog.event_data.TaskContent and winlog.event_data.TaskContentNew. This makes scheduled-task detection and tuning rely too heavily on TaskName, which is attacker-controlled and easy to masquerade.

This PR parses selected scheduled task XML fields into winlog.scheduled_task.* for Security scheduled task events in the System and Windows forwarded integrations.

Why

Windows scheduled tasks are a common mechanism for persistence, remote execution, privilege abuse, and ransomware deployment. Security events already capture useful scheduled task metadata, but most of the task definition is stored as raw XML in winlog.event_data.TaskContent and winlog.event_data.TaskContentNew, with TaskName being the only readily queryable field today.

That XML contains the behavioral details needed to understand the task: what it runs, when it runs, which account it uses, and whether it is configured in suspicious ways such as hidden execution or elevated run level. Today, those details are not available as structured fields for search, visualization, tuning, or reliable detection logic.

As a result, some detections have to rely on TaskName, which is attacker-controlled and easy to make look benign. This weakens detection quality and can make detections bypassable.

This PR extracts scheduled task metadata into structured winlog.scheduled_task.* fields. That makes scheduled task activity easier to investigate and enables more durable detections based on what the task actually does, not just what it is called.

What changed

This PR adds scheduled task XML parsing for Windows Security events in both the System security data stream and the Windows forwarded data stream.

The new parsing extracts selected task definition metadata from TaskContent and TaskContentNew into winlog.scheduled_task.*, including:

  • task URI and name
  • configured actions
  • executable command, arguments, and working directory
  • COM handler class ID
  • run-as user or group
  • logon type and run level
  • trigger type and enabled state
  • repetition interval, duration, and stop-at-duration-end setting
  • selected task settings such as hidden and enabled

The pipeline handles scheduled task creation, update, enable, disable, and delete events. Delete events do not contain task XML, so they continue to populate the scheduled task name from TaskName only.

Performance

A dedicated system/security pipeline benchmark was added for the scheduled task parsing path. The benchmark uses Security scheduled task events where every document triggers the new XML parser, so it represents the expected worst-case ingest cost for this change.

Warm-run results from the same local environment:

Target EPS Processing time Scheduled task parser avg Scheduled task parser share
main 17,241.38 0.14s n/a n/a
This branch 9,578.54 0.26s 18.8µs/doc 18.01%

This is a worst-case benchmark because every event in the fixture set is a scheduled task event with task XML. In normal Security event streams, the impact should scale with the proportion of events that are scheduled task events carrying TaskContent or TaskContentNew.

Checklist

  • I have reviewed tips for building integrations and this pull request is aligned with them.
  • I have verified that all data streams collect metrics or logs.
  • I have added an entry to my package's changelog.yml file.
  • I have verified that Kibana version constraints are current according to guidelines.
  • I have verified that any added dashboard complies with Kibana's Dashboard good practices

How to test this PR locally

Run the System security pipeline tests:

cd packages/system
elastic-package test pipeline --data-streams security

Run the Windows forwarded pipeline tests:

cd packages/windows
elastic-package test pipeline --data-streams forwarded

Run the dedicated pipeline benchmark for the scheduled task parsing path:

cd packages/system
elastic-package stack up -d --services=elasticsearch
elastic-package benchmark pipeline --data-streams security --use-test-samples=false
elastic-package stack down

Screenshots

image

@w0rk3r w0rk3r self-assigned this May 25, 2026
@w0rk3r w0rk3r added the documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. label May 25, 2026
@w0rk3r w0rk3r requested review from a team as code owners May 25, 2026 21:23
@w0rk3r w0rk3r added the enhancement New feature or request label May 25, 2026
@w0rk3r w0rk3r requested review from a team as code owners May 25, 2026 21:23
@w0rk3r w0rk3r requested review from khushijain21 and leehinman May 25, 2026 21:23
@github-actions

github-actions Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor

✅ Elastic Docs Style Checker (Vale)

No issues found on modified lines!


The Vale linter checks documentation changes against the Elastic Docs style guide. To use Vale locally or report issues, refer to Elastic style guide for Vale.

@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

🚀 Benchmarks report

To see the full report comment with /test benchmark fullreport

@andrewkroh andrewkroh added the Team:Security-Windows Platform Security Windows Platform team [elastic/sec-windows-platform] label May 26, 2026
@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

Pinging @elastic/sec-windows-platform (Team:Security-Windows Platform)

---
description: Pipeline for parsing Windows Security scheduled task XML.
processors:
- script:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of parsing this in the ingest node with a custom painless script, would it be possible to use the decode xml processor on the agent? Renames and cleanup could still be done at the ingest node, but it should greatly reduce the size of this script and mitigate the worse cast performance impact.

@marc-gr marc-gr Jul 2, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should test it as the xml processor in filebeat has some conventions that might need attention IIRC. I tried to make elastic/elasticsearch#130337 but it is stalled due to the performance of xpath evaluation. I might try to revisit that and see if we can make it happen on the pipelines and if not I'll see what needs to be done to use the filebeat processor instead.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, what action should I take? As the XML processor is also something "more experimental" and the script is tested and restricted to a smaller subset of event codes, should we just continue with this approach? @marc-gr @leehinman

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather try using filebeat xml processor and have the pipeline make any needed transformations as @leehinman suggested. We can later on switch to the xml decode in the pipeline if we end up merging the ingest processor. The performance hit of such a script is hard to tell and it looks like it would be also a bit harder to maintain than if we do it in filebeat.

@w0rk3r w0rk3r marked this pull request as draft July 6, 2026 22:03
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

TL;DR

Buildkite failed before any package tests ran: the post-checkout hook could not merge tested commit 6cb670ad3b1595e676d45206b7974d320a5f6686 with current main because packages/system/changelog.yml and packages/system/manifest.yml conflicted. The PR now has a newer merge-from-main commit (49de1f80481bf80d14dd5c1f8466a2e98734012f), so this failure is likely stale; rerun CI on the current head.

Remediation

  • If the newer merge commit was intended to resolve this, rerun Buildkite for the current PR head.
  • If resolving manually, keep the System package version bump in packages/system/manifest.yml as 2.21.0 and keep the PR's 2.21.0 changelog entry above the existing 2.20.0 entry from main.
Investigation details

Root Cause

This is a merge conflict during Buildkite checkout/pipeline upload, not a code or test failure. The failing job checked out 6cb670ad3b1595e676d45206b7974d320a5f6686, then the repository post-checkout hook switched to main at ad003d1c14e7f1c9407c931510549898180b928b and attempted to merge the PR commit. Git reported conflicts in the System package metadata files:

  • packages/system/changelog.yml: both the PR and main modified the top changelog entries.
  • packages/system/manifest.yml: both the PR and main modified the package version line.

The current PR head is already 49de1f80481bf80d14dd5c1f8466a2e98734012f (Merge branch 'main' into scheduled_tasks_parser), created after the failed Buildkite commit, so the next build should test the resolved state.

Evidence

Auto-merging packages/system/changelog.yml
CONFLICT (content): Merge conflict in packages/system/changelog.yml
Auto-merging packages/system/manifest.yml
CONFLICT (content): Merge conflict in packages/system/manifest.yml
Automatic merge failed; fix conflicts and then commit the result.
Merge failed: 1
Error: running "repository post-checkout" shell hook: The repository post-checkout hook exited with status 1

Verification

  • Not run: the Buildkite failure happened before pipeline generation/tests, and this workflow is read-only.
  • Confirmed the PR contains a newer commit after the failed build commit: 49de1f80481bf80d14dd5c1f8466a2e98734012f.

What is this? | From workflow: PR Buildkite Detective

Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.

@elastic-vault-github-plugin-prod

Copy link
Copy Markdown
Contributor

✅ All changelog entries have the correct PR link.

@infra-vault-gh-plugin-prod

Copy link
Copy Markdown

💚 Build Succeeded

History

cc @w0rk3r

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. enhancement New feature or request Integration:system System Integration:windows Windows Team:Security-Windows Platform Security Windows Platform team [elastic/sec-windows-platform]

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants