Industry Analysis

Elastic Security Supply Chain Signals

How to surface software supply chain threats in Elastic Security using EQL, detection rules, and the Elastic Common Schema for build pipeline and registry events.

Nayan Dey
Senior Security Engineer
7 min read

Elastic Security has carved out a credible spot in the SIEM market largely because of two things: the Elastic Common Schema gives you a sane way to normalize data from dozens of sources, and EQL makes sequence-based detection surprisingly ergonomic. Both strengths become relevant when you start thinking about software supply chain detection, because supply chain attacks are rarely a single event. They are sequences: a package gets published, a developer installs it, a build consumes it, an artifact gets pushed, and eventually something exfiltrates credentials weeks later.

I spent most of Q2 working with a financial services team that had Elastic Security deployed primarily for endpoint telemetry. We added supply chain data sources over several sprints and built out detection content that surfaces the signals unique to this attack surface. What follows is the practical outcome of that work.

Mapping Supply Chain Data to ECS

The first decision was how to map non-standard data sources into ECS. Elastic provides official integrations for GitHub and GitLab, and those cover most of what you need from SCM. For Jenkins I used the Filebeat module for generic JSON logs combined with a custom ingest pipeline that maps Jenkins fields like buildNumber and workflowRun.name to ECS equivalents like process.pid and process.name when it made sense, and to custom fields under supply_chain.* when no clean ECS equivalent existed.

The supply_chain.* namespace ended up containing:

  • supply_chain.package.name
  • supply_chain.package.version
  • supply_chain.package.ecosystem
  • supply_chain.package.publish_date
  • supply_chain.build.id
  • supply_chain.build.commit_sha
  • supply_chain.artifact.digest
  • supply_chain.attestation.status

Keeping this consistent across sources made downstream EQL and KQL queries dramatically easier. The alternative, which is what most teams end up with, is a mess of source-specific field names that require every rule to hardcode three different ways of spelling "package version."

Detection One: Package Install Followed by Outbound Connection

This is the classic supply chain pattern. A developer runs npm install some-package, and within seconds that package establishes a connection to an unexpected external host. EQL handles this cleanly:

sequence by host.name with maxspan=30s
  [process where process.name == "npm" and process.args : "install*"]
  [network where event.category == "network" and destination.ip != "10.0.0.0/8" and destination.port not in (443, 80)]

The maxspan=30s window captures the typical behavior where malicious postinstall scripts phone home immediately. The destination filter excludes expected traffic to npm's CDN and internal networks. When this fires, the alert includes both events so analysts see the package name and the destination together.

In production this detection caught a developer who had installed a typosquatted version of chalk. The malicious package opened a WebSocket connection to a Cloudflare Workers endpoint that was harvesting environment variables. The entire attack chain took 11 seconds from npm install to first exfiltration attempt.

Detection Two: Build Agent Executes Unsigned Binary

Build agents should only execute known tooling. If a Jenkins build suddenly runs a binary that has no code signature and was not present on the agent an hour ago, that is a strong signal. Combining Elastic Defend process telemetry with file integrity monitoring:

sequence by host.id with maxspan=1h
  [file where event.action == "creation" and file.path : "/tmp/*" and file.size > 1000000]
  [process where event.type == "start" and process.executable : "/tmp/*" and process.code_signature.status != "trusted"]

This catches the pattern where a malicious postinstall or build step drops a binary into /tmp and then executes it. The signed binary check eliminates most legitimate tooling.

Detection Three: SCM Push from Unusual Geography

GitHub audit logs include source IP for most events. If a developer who normally pushes from one country suddenly pushes from a different continent, and that push touches a .github/workflows/ file, it deserves a look. The KQL query:

event.module:"github" and event.action:"git.push" and 
file.path: ".github/workflows/*" and 
not user.geo.country_iso_code: ("US" or "IN" or "GB")

I wire this into a Transform that tracks each actor's typical geography and alerts on new countries rather than hardcoding allowed countries. The transform runs every hour and maintains an enrichment index keyed by user.name.

Detection Four: Package Publisher Change

When the publisher of an internal or critical open source package changes, it matters. The detection requires maintaining an index of expected publishers per package, which I populate from an initial scan of npm view <package> maintainers. The rule compares each new install event against the expected publishers:

FROM logs-supply_chain-* 
| WHERE event.action == "package_install" 
| ENRICH expected_publishers ON supply_chain.package.name 
| WHERE supply_chain.package.publisher NOT IN (expected_publishers) 
| STATS count BY supply_chain.package.name, supply_chain.package.publisher

This is an ES|QL query, which Elastic made the default query language for new detection rules in 8.11. It reads more naturally than EQL for enrichment-heavy patterns and runs reasonably well on hot data.

Detection Five: Attestation Verification Failure

Production deployments should only accept signed artifacts with valid attestations. When a deployment pipeline tries to pull an artifact and attestation verification fails, that is a security event, not just a build problem:

event.dataset:"kubernetes.events" and 
event.reason:"AttestationFailed" and 
kubernetes.namespace: ("production" or "prod-*")

The Kyverno or Sigstore policy controllers emit these events. Routing them into Elastic and alerting on any production occurrence gives the security team visibility they would otherwise lack.

Building Dashboards That Security Directors Actually Read

The detection rules are the technical core, but security leaders want a supply chain dashboard that shows the overall posture at a glance. I built a dashboard with four main panels:

  • Total supply chain alerts over the last 30 days, segmented by MITRE technique
  • Top packages by install volume overlaid with packages that have vulnerabilities
  • Build pipeline success rate versus attestation coverage
  • Map of push events by geography for the top 20 contributors

The map panel surfaced two compromised developer accounts in the first month of deployment. Both cases involved credential theft leading to pushes from countries the legitimate developers had never visited.

Tuning the Rule Set

Elastic Security's rule tuning workflow is better than most SIEMs, but supply chain rules have specific tuning needs. The package install plus outbound connection rule, for example, generates noise when legitimate postinstall scripts pull dependencies from their own CDNs. I added an allowlist of known good destinations maintained as a value list, which the rule references directly.

The geography rule needed a bootstrap period. For the first 30 days the rule only logged matches to a baseline index rather than generating alerts, so I could see what "normal" looked like before switching to alerting mode.

Performance Considerations

Supply chain data volume is usually modest compared to endpoint or network telemetry. The whole GitHub audit log for a 2,000-developer organization fits in a few hundred megabytes per day. The challenge is not ingestion cost but query performance on sequence-based rules. I split detection rules into hot-data versions (last 24 hours) that run every five minutes, and historical versions (last 30 days) that run every hour to catch slower multi-stage patterns.

How Safeguard Helps

Safeguard integrates directly with Elastic Security via the Elastic Agent integration framework, streaming supply chain findings and component risk scores into your existing indices. The integration maps cleanly to the supply_chain.* ECS extensions used throughout this post, so your detection rules can reference Safeguard enrichment data without custom transforms. Teams typically use Safeguard findings as a reference enrichment for alert triage, surfacing upstream context like package maintainer reputation and CVE exploitability directly in the Elastic Security alert view. When a detection fires, the linked Safeguard finding provides the remediation path your response team needs.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.