Implementing Detection as Code as a multi-platform MSSP

What was once considered to be a niche within a niche, Detection as Code has become a very popular method of managing detection rules across your SIEM environment. Seeing Detection as Code pipelines become commonplace has been incredibly heartening to watch over the last few years, as it brings with it very tangible benefits — removes the risk of configuration drift, allows for unit testing and strict style guides through CI/CD, and automated deployments. With AI in the picture, the benefits multiply massively with huge efficiency boosts in terms of writing and tuning rules, using those rules for threat hunting, and more.

I’ve spent a long time tracking the evolution of Detection as Code in the Detection Engineering space in my last few years as a security engineer at an MSSP. I tried many different approaches to implementing DaC in a way that could truly scale, and scale in a way that could function cross-platform, as we support not one but four platforms simultaneously! I found very online discussing how they were dealing with the complexities that arise from dealing with this large of an environment. This article intends to address this use-case.

First and foremost, a lot of the initial inspiration came from the incredible work done by NVISO Labs on their Detection Engineering: Practicing Detection-as-Code — NVISO Labs series of blogs. Many of the design decisions taken were inspired heavily by concepts outlined in this series, a lot of which will be readily apparent as I dig into the design principles.

The Approach

The number one consideration when it comes to implementing DaC is managing the downstream consumers of our detections. During the design phase, I played with a couple different methodologies for managing code:

  • Specific git branches for different environments
  • Monorepo vs. Multiple repos per client with submodules
    Multiple branches seemed like a good idea initially, but it’s really not what branches are designed for. Keeping branches synced up with rules is untenable, and the same kinds of issues presented themselves when it came to managing multiple repositories. It also led to valuable context being spread across different folders rather than being centralised in one place.

The best and simplest approach I settled on was the same as NVISO’s — organising detection content into ‘Content Packs’ — JSON definitions that group detections up based on a similar purpose. We typically group detections based on their underlying log source, but other content packs cover particular attack stories or are customer-agnostic (e.g. the ‘Baseline’ content pack, a group of detections that all customers receive). This allowed for the simplest and best use for Git which was to keep the ‘main’ branch as production, and put work in progress detection rules behind ‘feature’ branches and gate any merge behind CI/CD tests.

In-line with NVISO, a typical content pack looks something like:

{
"platform": "sentinel",
"description": "Contains detections relating to Azure and Azure resource deployment and modification. Most detections require AzureActivity logs or other common tables.",
"content": [
"detections/Sentinel/azure/Rare subscription-level operations in Azure",
"detections/Sentinel/azure/Suspicious Resource Deployment",
"detections/Sentinel/ueba/First time Azure Custom Script or Run command deployment",
"detections/Sentinel/azure/Mass secret retrieval from Azure Key Vault",
...
]
}

Once I had settled on the concept of content packs for managing which rules are deployed to who, it completely opened the door for all kinds of use-cases, and is how we deploy specific sets of detections to specific environments. With content packs, the Detection Engineering team can seamlessly add detections onto a new or existing content pack and ship it out the door to all environments who need it.

Content packs simplify the deployment process massively by controlling everything through a singular JSON file. Each customer is tracked individually through this file, and it specifies the platforms they have, and what content packs they should receive.

...
"content-packs": [
"sentinel-baseline",
"sentinel-azure",
"sentinel-defenderxdr",
"sentinel-active-directory",
"sentinel-platform-alerts",
"sentinel-monitored-domains"
],
...j

Some customers may combine different SIEM and EDR platforms. Our configuration allows for mix and matching of content packs and platforms, with specific CI/CD pipelines that kick in for each. Detection as Code ensures each environment receives exactly the same detection rule, no matter what.

Detections are stored as discrete files in native formats. For Sentinel, that’s JSON ARM templates, for Splunk it’s .conf files, etc. Each file is kept within a simple file structure:

detections /
sentinel/
active-directory/
aws/
azure/
Cloud Resource Deletion Time Anomaly.json
...
splunk/
active-directory/
aws/
azure/
Cloud Resource Deletion Time Anomaly.json
...

While working with the native files is not the most intuitive thing to a human, we’ve been able to build a toolchain that simplifies the process of managing and editing these rules which has allowed us to bypass many of the issues others run into — compiling pseudo-code into detection rules, generating rule metadata at deployment time, etc. We found that for our purposes, just storing the actual raw rule itself provided all the same benefits. With an AI agent in the picture, editing a JSON file is no issue at all.

But what about Sigma and Cross-Platform rules?

I decided early on to de-scope pseudo-code from the codebase altogether and rely on actual detection artifacts. Personally, I prefer to use Sigma rules as reference material rather than as a piece of code to be translated off of directly. While there are some automated tools that have gotten decently good at this, in 2026 it’s much quicker and accurate to throw an AI agent at that task instead. AI agents can also create the requisite metadata around the rule itself, further reducing the need for these tools.

Managing cross-platform rules is indeed trickier without a shared piece of pseudo-code. But again, with AI agents being such a massive part of the detection development lifecycle, maintaining changes between multiple query languages and platforms and accounting for each nuance is shockingly easy. This has been one of the biggest enablers of this particular Detection as Code implementation.

What about documentation?

Each rule is stored alongside a markdown file in the same folder. The markdown file contains:

  • The rule description
  • A technical description explaining how the rule works
  • Blindspots, gaps, and special SOC considerations
  • Other bespoke info aligned to our SOC team

This doco is stored as code and is linted and checked as part of the PR process. This ensures documentation is always updated in lockstep with the rule. The documentation is then rendered in our custom frontend (more on that later) and synced into Confluence at deployment time.

For more information on writing good documentation, I would point you to this article I wrote a couple years ago on the subject.

Deployment Workflow

Pictured above is a high level diagram describing the deployment workflow. It’s not overly complicated — work is done on a new branch with simple tests run locally pre-commit to prevent any stupid mistakes slipping through. There, a PR is raised, where a much more complex validation pipeline is executed.

The validation pipeline:

  • Identifies the changes based on file type and platform (modified version of NVISO’s logic)
  • Routes the change to the relevant platform validators
  • Checks metadata and style against dozens of custom tests
  • Remotely runs queries against lab environments
  • Stages the rules in a lab environment to test the deployment will succeed in production
  • And more 

Assuming the tests pass and the senior Detection Engineer is happy, the PR can be merged, where it is then checked into the main branch. The deployer will pick up the change if it’s part of a content pack, and any customer subscribed to that pack will receive that rule.

In instances where the rule already exists and the platform supports it, the deployer will update the rule in-place rather than create a new one. For Splunk deployments, rules are tarred and uploaded to remote storage for retrieval and installation by other automated steps outside the scope of this article.

The Detection Engineering Toolchain

To support testing, we also have the capability to run searches against any environment from the DaC repository. This initially started as a way to manually test detection rules prior to deployment, but quickly grew to become a full-blown agent harness, fully capable of orchestrating long and detailed threat hunts fully autonomously. We then built integrations into threat intelligence products, custom skills, and other bespoke API tools that could empower an engineer or an AI agent to carry out full SOC and IR investigations completely.

One of the other concepts I built was the idea of a data map. A data map is essentially a CSV inventory of all the tables going into an environment, alongside an event count. This data map is generated once daily per environment. For each table, an equivalent schema markdown file is generated, along with an entry added to an index.md file. This schema is not auto-generated, but rather hand curated with the MITRE data components it provides, the SIEM field it maps to, the fields in the table, and a section for analysts to make notes.

---
type: logsource
platform: sentinel
mitre_datacomponent_name:
- Cloud Service Modification
- Instance Creation
- Instance Deletion
- Instance Modification
- Cloud Service Enumeration
- Cloud Service Disable
mitre_datacomponent_id:
- DC0069
- DC0076
- DC0081
- DC0073
- DC0083
- DC0090
mitre_logsource_name: azure:activity
siem_logsource_name: AzureActivity
---
# Context
Entries from the Azure Activity log that provides insight into any subscription-level or management group level events that have occurred in Azure. Source: https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/azureactivity

# Suggested Queries
## Check for ...
```kql
AzureActivity
| where TimeGenerated > ago(1d)
...
```

# Schema
| Field Name | Data Type | Description |
|------------|-----------|-------------|
| _ResourceId | string | A unique identifier for the resource that the record is associated with |
| ActivityStatus | string | |
...

This concept was inspired by a post on the blog Cauchy which discussed a workflow for automatically maintaining documentation on each sourcetype in Splunk. We’ve expanded the scope to include Sentinel and the various other platforms we support, with the overlay of MITRE data components for downstream reporting.

Detection Development Efficiencies

Bringing all development into one repository has significantly decreased the time it takes to develop, test and deploy new rules. With an AI agent in the mix, an almost fully autonomous development process can be achieved:

  1. A CTI agent intakes a piece of CTI and synthesises it into potential detection opportunities.
  2. A detection agent for each platform with knowledge of each platform’s major log sources and style can enumerate the repository for similar detections and common query patterns.
  3. The detection agent can autonomously test the rules against live staging environments and adjust for any syntax errors or false positives it may turn up.
  4. The final output is generated onto a new branch ready for a detection engineer to review and put finishing touches on.
    This also has implications in other areas of the SOC, such as smooth integration into automated threat hunting (ATHF) and much more. Internally, I maintain a heavily modified fork of ATHF that runs on the toolchain discussed in this article for producing timely threat hunts.

Potential Pitfalls

In this kind of environment, ensuring mistakes don’t slip through the validation phase is absolutely critical, as the potential impact is now much larger. For this reason, QA needs to be rigorously implemented. Some of the methods we utilise:

  • Branch protection
  • Linting tests
  • Automated staging against representative lab environments
  • Required Approvers
  • CI/CD security scanning
  • Robust secret management for agents
  • Agent sandboxing
    It’s also important that, if you choose to adopt a similar practice, you go through the effort of hand-selecting the rules you want to manage as code. There is an element of “wiping the slate clean” involved where we decided which rules we’d keep, and which rules offered little value (or just weren’t worth the time to update). It was then a very long and arduous process to manually transition each environment onto the new ruleset without compromising on detection capability.

The Detection Engineering Frontend

One of the many benefits AI has given us is the ability to create bespoke applications for specific purposes. Detection as Code is wonderful but not everyone likes engaging with a Git repository and raw markdown (especially when you want to open up to non-technical folks). Thus, the need for a frontend was born.

Below is a fictionalised version of the ‘Detection Grid’, the part of the app which SOC analysts interface with for viewing rules. Here they can filter the list down, view alert stats (plugged into live ITSM data), and view the content packs a detection belongs to.

A rule may be drilled down into to reveal its metadata and documentation, alongside a summary of how the alert is typically closed and the reasoning behind each closure:

The metadata of a rule and alert volume stats.AI generated summary of closure reasons and the documentation section rendered from the markdown file in the DaC repository.

Of course, a MITRE gap analysis tool is provided as well.

By bundling the full MITRE STIX library into your app, you can do all kinds of enrichment on the info within your detection library.

This is probably only 5% of the capabilities of the platform I’ve built around Detection as Code, but the point is that Detection as Code gives you an organic knowledge base of detection and security information you can build on top of. You can overlay threat hunting, gap analysis, data integrity, reporting, testing and validation and so much more. Detection as Code in 2026 is more than just version control, it’s a fusion centre for your whole SOC.

I hope this article has given you some reading material and given you some food for thought on where you might take your Detection as Code implementation in the future. A big shoutout to NVISO and Cauchy who directly inspired the design of my particular configuration. Please consider reading them and the other authors on this publication, as without them none of this would have been possible.

Implementing Detection as Code as a multi-platform MSSP was originally published in Detect FYI on Medium, where people are continuing the conversation by highlighting and responding to this story.

Introduction to Malware Binary Triage (IMBT) Course

Looking to level up your skills? Get 10% off using coupon code: MWNEWS10 for any flavor.

Enroll Now and Save 10%: Coupon Code MWNEWS10

Note: Affiliate link – your enrollment helps support this platform at no extra cost to you.

Article Link: https://detect.fyi/implementing-detection-as-code-as-a-multi-platform-mssp-6518cc5289b4?source=rss----d5fd8f494f6a---4