# osquery-defense-kit is a query pack that stays silent until something is wrong

> Chainguard's osquery-defense-kit collects more than 250 osquery SQL queries written for detection and incident response, with the unusual constraint that a detection query must return zero rows during normal behaviour so that any row can be treated as an alert. The catch is that the queries are POSIX first, and the newest release is from mid 2025.

**chainguard-dev/osquery-defense-kit** — Production-ready detection & response queries for osquery

- Repository: https://github.com/chainguard-dev/osquery-defense-kit
- Stars: 650 · Forks: 50
- Language: Makefile
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/chainguard-dev-osquery-defense-kit

## The unusual premise: a detection query that returns nothing

osquery-defense-kit is a collection of osquery SQL queries for detection and incident response, and the README says it contains more than 250 of them. The interesting part is not the count but the design rule.

The kit is described as unique in that the queries are designed to be used as part of a production detection and response pipeline, and the detection queries are formulated to return zero rows during normal expected behaviour, so that they may be configured to generate alerts when rows are returned.

That is a stricter standard than most published detection content meets. A query that returns every suspicious looking file, including the ones your software distribution installed, is not an alert, it is noise. Writing queries that are silent on a healthy fleet and loud on a compromised one is the hard part of the work, and it is the part this project is organised around.

The cost of that standard is obvious and worth stating before anyone deploys it. A query that says nothing on your fleet may be saying nothing because it does not apply to your fleet. An unexpected cron entry query is silent on a machine that has no cron, and a query about unexpected shell parents is silent on a fleet where every process starts from a login shell. You will need to tune, and the README is clear that tuning is a user responsibility.

The requirements are short: osquery v5.7.0 or above, and macOS or Linux. Local development also needs Go v1.20 or later, because the pack tooling is a Go program called osqtool.

## Three directories that do three different jobs

The repository is organised into directories that correspond to operational jobs rather than to data sources.

The detection/ directory holds threat detection queries tuned for alert generation. The policy/ directory holds security policy queries, also tuned for alert generation, which is the category where you would ask whether a machine follows a standard you decided on rather than whether it is under attack. The incident_response/ directory holds data collection to assist in responding to possible threats, tuned for periodic evidence collection rather than for immediate alerts. That distinction matters operationally, because the two alert directories want to be low frequency and high signal, while the incident response directory wants to be broad, regular and cheap.

On top of those three, the repository root carries a vulnerabilities/ directory, a fragments/ directory, an osquery.conf file, a Makefile and a LICENSE.txt.

The detection queries are further divided by MITRE ATT&CK tactics, and the README's case study section shows the directory names directly, with tactics such as execution, c2, initial_access, evasion, privesc and persistence. That mapping is the reason the structure is worth keeping: when an incident report describes a technique by ATT&CK id, the query that would have caught it is a predictable path, and the reverse holds too, a new technique tells you which directory to add to.

The fragments/ directory suggests the queries are assembled from shared pieces rather than each being a standalone file, which is how a rule like an unexpected executable directory can be expressed once and reused across several tactics.

## Packs are assembled at release time and by osqtool

The queries are not shipped as loose SQL files for you to schedule. At release time they are packed into the osquery query pack format, and the packs stanza of your osquery.conf points at those files. The released artefacts also include a vulnerabilities pack, based on the vulnerabilities/ directory that is in the repository but not described in the README's usage section.

Pack assembly is done by osqtool, and the Makefile shows exactly how. The tool is built from source with the Go toolchain at a pinned version:

```make
OSQTOOL_VERSION=v1.4.2
```

and then invoked per directory. The detection pack gets a longer per query budget than the others:

```bash
	./out/osqtool-$(ARCH)-$(OSQTOOL_VERSION) --max-query-duration=16s --verify --exclude-tags=disabled,disabled-privacy,extra --output  out/detection.conf pack detection
```

The policy, vulnerabilities and incident response packs use the same shape with an eight second budget instead of sixteen, which reflects the expectation that detection queries are the expensive ones, since they are the ones doing correlation against process and file history.

Three things in that command line matter. The --verify flag asks osqtool to check the queries as it assembles them. The tag exclusions drop anything tagged disabled, disabled-privacy or extra, which is how a query is parked without deleting it. And the --max-query-duration setting is the guard against a query that scans a large table and slows the host down.

The README also tells you that you can invoke osqtool directly for more control, to override default intervals or exclude checks, which is the escape hatch when the generated pack does not fit your fleet.

## make detect, make collect, make packs, make verify

Four make targets cover the workflows, and the distinctions between them are the practical part of using this kit.

make detect runs point-in-time detection locally. The README is candid that this will not detect as much as a production installation, because a local run has no access to historical events. That is the key constraint of osquery detection in general: many of the interesting signals are temporal, a process that has disappeared, a file that was written and deleted, a binary that existed only between two scheduled runs, and a one shot query can only see what is true right now.

make collect is for local data collection for incident response, and the README says it is particularly useful for before and after analysis. That is the incident_response/ directory in action, gathering evidence you can then diff across two points in time.

make packs performs local pack generation, which is what you run to produce the .conf files that the production deployment points at. make verify runs local verification testing.

The production path is different from the local path in a way that is easy to miss. Instead of running the queries yourself, you download a released query pack into a convenient location and point to those files from the packs stanza of your osquery.conf file. The server then schedules them on the intervals the pack defines.

The Makefile also produces a zip of the generated configuration files, and it rewrites the local osquery.conf so the paths in it point at the right place. Formatting is handled separately through a reformat target that runs the sql-formatter over the .sql files with the sqlite dialect, which keeps the query files consistent enough to review in a pull request.

## Two intrusions the kit claims it would have caught

The README includes case studies, and they are the most useful part for judging the queries, because they connect a named intrusion to specific files in the repository.

The first is Shikitega, a stealthy Linux malware campaign from September 2022 that the case study links to research published by the cybersecurity team at AT&T. The README lists which queries would have fired and at which stage of the attack. Initial dropper execution is attributed to execution/tiny-executable-events.sql and execution/tiny-executable.sql. Next stage dropper execution adds execution/unexpected-shell-parents.sql. Escalation prep is covered by execution/sketchy-fetchers.sql and execution/sketchy-fetcher-events.sql, together with c2/unexpected-talkers-linux.sql and c2/exotic-command-events.sql. Escalation tool execution pulls in execution/unexpected-executable-permissions.sql, execution/unexpected-executable-directory-linux.sql and execution/unexpected-tmp-executables.sql, along with evasion/missing-from-disk-linux.sql. Privilege escalation is detected by privesc/unexpected-setxid-process.sql and privesc/unexpected-privilege-escalation.sql, and persistence by persistence/unexpected-cron-entries.sql.

The second is CloudMensis, macOS spyware from April 2022. Here the initial dropper is caught by c2/unexpected-talkers-macos.sql, the second stage by execution/unexpected-executable-directory-macos.sql and persistence/unexpected-launch-daemon-macos.sql, the TCC bypass by evasion/unexpected-env-values.sql, and the spy agent execution by c2/unexpected-talkers-macos.sql again alongside execution/exotic-command-events.sql.

Two observations. First, the same query appears against several stages, which shows the queries are written to detect behaviours rather than to be mapped one to one onto intrusion stages. Second, note the platform suffix on the file names, such as -linux and -macos, which is the practical face of the POSIX first design.

## Windows is an invitation, and false positives are everyone's job

The project is explicit about the limits of its coverage, and the honesty is useful.

On platform support, the README says the queries are predominantly designed for execution on POSIX platforms, Linux and macOS, and that pull requests to improve support on other platforms are fully welcome. On Windows specifically, the explanation is practical rather than technical: Chainguard doesn't have any Windows machines, but if you have Windows queries that you think would be useful and match the project's philosophy, they are willing to accept them. That is a clear statement that Windows coverage is whatever the community supplies, and no more.

On false positives, the policy is stated twice. The project endeavors to exclude real world false positives from the detection queries, and managing false positives is described as easier said than done. For contributions, the rule is that new queries are welcome so long as they can be easily updated to address false positives. Users may submit false positive exceptions for popular well known software packages, but may be asked to provide evidence for the behaviour. In other words, a suppression request is a request with a burden of proof attached.

There is a performance budget too. The README states that in aggregate, queries should not consume more than 2% of the wall clock time across a day on a deployed system. That figure is a design constraint on the query authors rather than a promise about your fleet, but it is the number to keep in mind when you add queries of your own, and it is why the per query duration caps exist in the pack commands.

One more operational detail closes the picture. Deployed intervals are automatically determined based on the tags supported by osqtool, which is used for pack assembly. So the schedule of your queries follows the tags in the pack, and if you are used to choosing your own intervals, you will need to invoke osqtool directly.

## Conclusion

Adopt osquery-defense-kit if you already run osquery on Linux or macOS fleets and need a vetted starting point for detections rather than writing queries from scratch, and you accept that the same silence that makes a detection useful also makes it environment specific. Do not adopt it as the whole of your detection coverage, since the pack is POSIX focused, the Windows support is explicitly an invitation for outside contributors, and the README does not document how a false positive is suppressed once a package is deployed. Before you deploy, build the packs locally with make packs, run make verify, and confirm the query pack files are pointed at from the packs stanza of your osquery.conf.

## FAQ

### What is osquery-defense-kit?

It is a collection of more than 250 osquery SQL queries for detection and incident response, maintained by Chainguard. The detection queries are written to return zero rows during normal expected behaviour, so that any returned row can be treated as an alert.

### How do I install and use osquery-defense-kit?

The project needs osquery v5.7.0 or above on macOS or Linux, plus Go v1.20 or later for local development. Run `make packs` to generate the query packs locally, `make detect` for point-in-time detection, `make collect` for incident response data collection, and `make verify` for verification testing.

### Does osquery-defense-kit support Windows?

The queries are predominantly designed for POSIX platforms, Linux and macOS, and the README explains that Chainguard does not have any Windows machines. Windows queries are still accepted from outside contributors if they match the project's philosophy.

### How are the query packs configured on a fleet?

You download a released query pack and point to those files from the packs stanza of your osquery.conf file. The packs are assembled at release time with osqtool, which also determines the deployed intervals from the query tags, and you can invoke osqtool directly to override intervals or exclude checks.

## Sources

- [chainguard-dev/osquery-defense-kit on GitHub](https://github.com/chainguard-dev/osquery-defense-kit)
- [Issues](https://github.com/chainguard-dev/osquery-defense-kit/issues)
- [License: Apache-2.0](https://github.com/chainguard-dev/osquery-defense-kit/blob/main/LICENSE)
- [README](https://github.com/chainguard-dev/osquery-defense-kit/blob/main/README.md)
- [Releases](https://github.com/chainguard-dev/osquery-defense-kit/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/chainguard-dev-osquery-defense-kit
