Open-source project
mandiant/capa-rules avatar
mandiant/capa-rules

capa-rules: the rule corpus behind Mandiant's capability detection

Standard collection of rules for capa: the tool for enumerating the capabilities of programs

743 stars248 forksUnknownApache-2.0

At a glance

What is it?
The YAML rule collection that turns capa from a disassembler viewer into a capability identifier, organised into hierarchical namespaces and including a library rule mechanism that lets one rule match on another. It is the part of capa that most users never touch and that most contributors actually work on.
Who is it for?
Adopt capa-rules if you run capa against binaries and want to recognise a technique the default corpus does not cover, since writing a rule is the documented extension path. Skip it if you are looking for a standalone scanner, because this repository contains no tool, only the rules that the capa engine interprets.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
GitHub does not report a main language for this repository.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

capa reads behaviour, not signatures

The repository is the standard collection of rules for capa, described in the project as the tool for automatically identifying capabilities of programs, and in the readme as the tool for enumerating the capabilities of programs.

The distinction from signature matching is the point. capa does not ask whether a binary is a known sample. It asks what the binary is capable of doing. The readme frames the contribution culture around that idea: anytime you see something neat in malware, we want you to think of expressing it in a capa rule.

That reframing has an effect on the whole workflow. A signature match tells you the file is in a known family. A capability match tells you the file can create a reverse shell, write to a registry run key, or speak a specific protocol, regardless of who wrote it. The first is a lookup, the second is an inference, and the second generalises to unseen samples in a way the first cannot.

The audience is two groups. One is analysts who want a richer answer from an existing capa setup. The other is reverse engineers who want a way to encode what they know, share it, and have it applied automatically to the next sample. The project states plainly that the rules are easy to write, even for those new to reverse engineering, and that a large rule corpus benefits everyone in the community.

The licence is Apache-2.0, and the repository is not archived, with the last push on 2026-10-16 alongside the v10.0.0 release.

A rule is YAML with metadata and a boolean feature tree

The rule format is described in the doc/format.md file, and the readme gives a full worked example that is the clearest explanation of how matching works.

The example is a rule for creating a reverse shell, with a name, a namespace of communication/c2/shell, authors, scopes, ATT&CK and MBC identifiers, and an example reference.

The scopes field is worth pausing on. It declares where the rule applies: a static scope of function and a dynamic scope of span of calls. A capability that only exists as a call site needs a different scope from one that lives in a whole function, and encoding that in the rule metadata is what lets the engine avoid matching on fragments.

The features block is a boolean tree. The reverse shell rule is an or of three and branches. The first branch is an and of a match on create pipe and four Windows API references, kernel32.PeekNamedPipe, kernel32.CreateProcess, kernel32.ReadFile and kernel32.WriteFile. The second is an and of a match on a process creation interaction and matches on reading and writing the pipe. The third combines a pipe creation match, a process creation match, and an or of a basic block and a call, each of which requires two or more calls to SetHandleInformation and the number one equal to HANDLE_FLAG_INHERIT.

So a rule is not a pattern to search for. It is a formula: a set of conditions over API calls, strings, byte patterns, subrules and nested boolean logic, which the engine evaluates against the disassembly and the extracted features of a binary.

The readme notes that in some regards capa rules are a mixture of the OpenIOC, Yara and YAML formats, which is a useful pointer for anyone arriving from one of those.

Library rules let one rule match on another

The most interesting mechanism in the corpus is the library rule, and it is the part that distinguishes capa from a flat pattern set.

capa supports rules matching other rule matches. The example given is a rule named persistence that matches if either a run key or a service match against a sample. The run key rule matches a string pattern, and the service rule matches an API call:

yaml
rule:
  meta:
    name: write file
    lib: True
  features:
    or:
      api: WriteFile
      api: fwrite

A library rule is declared with rule.meta.lib=True and lives in the lib rule directory. The rules have some important properties. Library rules should not have a namespace. They are not rendered as results. And capa will only attempt to match lib rules that are referenced by other rules, so there is no performance overhead for defining many reusable library rules.

That last point is the design insight. The library namespace in the corpus holds building blocks to create other rules, and the readme gives the reason: there are quite a few ways to write to files on Windows, so a single library rule makes it easy for other rules to thoroughly match file writing. Rather than every rule that cares about file writing repeating the same disjunction of APIs, they reference the library rule and the corpus stays readable.

This also means the corpus is compositional. A rule can be written in terms of a capability, and that capability can be defined once in terms of the concrete API calls it represents. For a large collection maintained by many contributors, that is the difference between a rule set that stays coherent and one that drifts.

Namespaces are the taxonomy and the report structure at once

The directory layout of the repository mirrors the namespaces of the rules it contains, and capa uses namespaces to group like things together, especially when it renders its final report. Namespaces are hierarchical, so the children of a namespace encode its specific techniques.

The top level list in the readme is effectively the taxonomy of what a program can do. anti-analysis covers packing, obfuscation and anti-X. collection covers data that may be enumerated and collected for exfiltration. communication covers HTTP, TCP and command and control traffic. compiler covers detection of build environments such as MSVC, Delphi or AutoIT. data-manipulation covers encryption and hashing. executable covers characteristics of the executable such as PE sections or debug info. host-interaction covers access or manipulation of system resources like processes or the Registry. impact is the end goal. internal is used internally by capa to guide analysis. lib is the building blocks to create other rules. linking detects dependencies such as OpenSSL or Zlib. load-code covers runtime load and execution of code such as embedded PE or shellcode. malware-family detects malware families. nursery is the staging ground. persistence covers the ways to maintain access. runtime detects language runtimes such as the .NET platform or Go. targeting covers special handling of systems such as ATM machines.

Two observations. First, the taxonomy mixes what the program does with how it was built and what it depends on, because for an analyst all three are evidence. Second, the project says more top level namespaces can be added easily as the need arises, so the taxonomy is expected to grow.

The tree at the root mirrors this exactly, with a directory per namespace, plus doc, .github for the continuous integration workflow, and LICENSE.txt.

The nursery and the linter, and why a rule might not fail the build

The quality control mechanism has two halves, and the second one is unusual.

The nursery is a staging ground for rules that are not quite polished. The documentation is clear that nursery rule logic should still be solid, though metadata may be incomplete, for example rules that miss a public example of the technique. The examples given for what would place a rule in the nursery are no real-world examples, missing categorization, and maybe questions about fidelity, such as the RC4 PRNG algorithm.

Contributors are encouraged to create rules in the nursery, with the hope that the community will work to graduate the rule once things are acceptable.

Then there is the linter. The rule linter status badge in the readme points at a workflow named CI, and the readme describes what the linter does with nursery rules precisely: the rule engine matches regularly on nursery rules, however, our rule linter only enumerates missing rule data, but will not fail the CI build, because its understood that the rule is incomplete.

So a nursery rule is fully live in the engine, and only advisory in the linter. That is a good design, because a rule that is 90 percent right and missing an example is more useful in the corpus than one held back until it is perfect. It also means a green CI badge does not tell you the corpus is complete, only that nothing is malformed.

For a user, the practical consequence is that a capa result may come from a nursery rule, and its metadata may be thinner than the metadata of a graduated one. The rule name and namespace in the output are your guide to how much weight to put on a particular match.

What a rule corpus cannot do for you

The limits are structural, and they are worth being honest about before you build a detection workflow on top of this.

The first is that the corpus can only find what somebody has already encoded. A technique that nobody has written a rule for does not exist as far as capa is concerned, and the report will not tell you it is missing. This is the central weakness of any capability detection approach, and the nursery exists precisely to shorten the gap, but a gap is a gap.

The second is the false positive problem, which is the mirror image. The reverse shell rule requires a combination of API calls and pipe semantics rather than a single string, and rules like the write file library rule are deliberately permissive, matching WriteFile or fwrite or any of a set of alternatives. That breadth is what makes a rule robust across compilers and obfuscation, and it is also what produces a match on a program that has the capability but never exercises it. capa tells you what a binary can do, and it says so, but the output is not a claim that the behaviour occurred.

The third is that this repository contains no engine. The readme points at the capa repository for the tool, and the homepage for this project is the capa GitHub page. The rules here are data consumed by that tool, so you cannot run capa from this repository, and a rule written here only does anything once it is loaded by a capa installation of a compatible version.

The fourth is the versioning relationship between rules and engine. The releases here are numbered, v10.0.0 on 2026-10-16 and v9.4.0 on 2026-04-01, and a rule corpus is tightly coupled to the engine that interprets its features. A rule using a feature your capa build does not understand is not going to work, and the corpus evolving faster than your installed engine is the normal state of affairs.

Against your own YARA rules, and against writing detections from scratch

Two comparisons clarify where this corpus earns its place.

The first is against your own YARA rules. The difference in approach is the level of abstraction. A YARA rule matches bytes, strings and patterns in the file, which makes it excellent at detecting a specific family or a specific artefact, and it runs in microseconds over a whole corpus. A capa rule matches the disassembly and the extracted features of a program, which makes it slower and dependent on the engine, and which is able to answer a question YARA cannot: what could this binary do, regardless of who wrote it. The two are complementary rather than competing, and analysts typically run both.

The second is against writing detections from scratch for a single investigation. If you have one sample and one question, writing a quick YARA string or a small script is faster and more precise than authoring a capa rule and iterating on the feature tree. The payoff of a capa rule comes from reuse: it applies to every future sample, it is reviewable by other people, and it can be shared with the community and merged back into the standard corpus.

There is also a contribution angle that is genuinely open. The project says rule writing should be easy and fun, that a large rule corpus benefits everyone in the community, and that all kinds of contributions are encouraged. A reverse engineer who has just spent an afternoon working out how a sample phoned home can turn that knowledge into a rule that the whole community benefits from, and the mechanism for doing it is a YAML file, a linter and a pull request.

Editorial conclusion

Adopt capa-rules if you run capa against binaries and want to recognise a technique the default corpus does not cover, since writing a rule is the documented extension path. Skip it if you are looking for a standalone scanner, because this repository contains no tool, only the rules that the capa engine interprets. Verify first that your capa version matches the rule version, that the technique you need is not already in the corpus or the nursery, and that a rule you write passes the linter in continuous integration before you rely on its result.

Frequently asked questions

What is capa-rules and how does it relate to capa?

capa-rules is the standard collection of YAML rules for capa, the tool for automatically identifying capabilities of programs. The repository contains no analysis engine, only the rules that the capa tool interprets when it inspects an executable.

How do I write a capa rule?

A rule is YAML with a meta section carrying the name, namespace, authors, scopes, ATT&CK and MBC identifiers, and a features section holding a boolean tree of conditions over API calls, strings and subrules. The doc/format.md file in the repository describes exactly how to construct rules.

What is a library rule in capa?

A library rule matches on the results of other rules and acts as a reusable building block. You declare it with rule.meta.lib=True, place it in the lib rule directory, give it no namespace, and it is not rendered as a result. Capa only attempts to match library rules that other rules reference.

What is the nursery in capa-rules?

The nursery is a staging ground for rules that are not quite polished, where the logic should still be solid but metadata may be incomplete. Nursery rules are matched by the rule engine as normal, and the linter reports missing rule data without failing the CI build.

What namespaces do capa-rules cover?

The top level namespaces are anti-analysis, collection, communication, compiler, data-manipulation, executable, host-interaction, impact, internal, lib, linking, load-code, malware-family, nursery, persistence, runtime and targeting. The repository directory layout mirrors these.

What licence is capa-rules released under?

Apache-2.0, recorded in LICENSE.txt at the root of the repository. The project is not archived, the last push was on 2026-10-16, and the most recent release is v10.0.0 published on the same day.

Official sources

  1. License: Apache-2.0
  2. mandiant/capa-rules on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mandiant-capa-rules.svg)](https://hysenlabs.com/projects/mandiant-capa-rules)

Was this useful?