Binaries and Libraries Sensor
Discover_Binary scans compiled executables and libraries for the cryptography they carry. It identifies which cryptographic library a binary uses, which version, and whether the binary itself is code-signed — answering the question a software inventory cannot: not "is OpenSSL installed" but "which of these programs will actually use it".
Overview and what gets scanned
The sensor walks the paths it is given, examines every binary it finds, and applies four independent detection methods to each.
| Method | What it catches |
|---|---|
| Dependency | The libraries the binary links — DT_NEEDED entries on ELF, the import table on PE, the module list on a Go binary. The strongest signal: a binary that links libcrypto uses OpenSSL. |
| Symbol | Function symbol names in the image. Finds a statically linked library, which has no dependency entry to find. |
| String | Signature strings in the raw bytes. The last resort for a stripped or statically linked binary. |
| Filename | The file's own name, so libcrypto.so.3 identifies itself. |
Each detection carries a weight, so a dependency match and a stray string match are not reported as equally certain.
Which libraries it recognises. OpenSSL, BoringSSL, AWS-LC, libsodium, GnuPG, OpenSSH, Windows CNG, Windows CryptoAPI, Go's standard library crypto, golang.org/x/crypto and CIRCL, plus a generic catch-all for binaries that reference algorithm names without a recognisable library. The set is extensible — see the signature fields below.
Versions. Where the image carries a version string, it is extracted and recorded: OpenSSL 3.0.14, OpenSSH_9.6. This is what turns the inventory from "uses OpenSSL" into something a vulnerability question can be asked of.
Linked libraries are followed. The scan does not stop at the binaries in the scan paths. Each library a binary links is resolved to a file and examined in turn, out to a configurable depth — so a program that uses no crypto directly but links a library that does is still reported correctly.
Code signatures. Each binary's signature is checked, and the result is one of three states, not two: signed and verified, unsigned, or signed with a signature that did not verify. The third is the interesting one, and collapsing it into "unsigned" would lose it. Where a signature verifies, the signing certificate is recorded as a certificate in the inventory alongside the binary.
How binaries are classified. The file extension sets the kind: application, shared library, static library, driver, or JVM artefact. This is what lets the dashboard answer "which drivers carry crypto" separately from "which applications do".
What it does not produce. No key or certificate material is extracted from inside a binary — an embedded key is not read out. The sensor reports what a binary links and what signed it.
Prerequisites
Where it runs. On the host whose binaries are being scanned. This is a filesystem sensor, so it is deployed to a target rather than pointed at one from the platform. It is not cloud-capable.
Required access rights. Read access to the paths being scanned, and permission to execute the platform's signature verification tooling. An unprivileged service account is enough for most paths; system directories on Windows and /usr/sbin on Linux may need more. Grant read, not administrator — the sensor never writes to the paths it scans.
Target-side prerequisites. None beyond the agent itself. Signature verification uses tooling already present on the platform — Get-AuthenticodeSignature on Windows, the package manager's own verification on Linux.
Execution models. Remote execution on an agent, and off-grid bundles. Platform execution is only meaningful for scanning the platform host itself. Not cloud-capable: there is no filesystem to walk on a cloud API.
Configuration fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
ExtName | string | Yes | Discover_Binary | The sensor name. Set for you by the form. |
paths | list | Yes | — | Paths to scan. A directory is walked recursively; a path naming a single file scans that file. |
config_name | string | No | BinaryDiscovery | A label recorded on every document from this scan, so results can be traced to the configuration that produced them. |
Scope and performance
| Field | Type | Default | Description |
|---|---|---|---|
include_patterns | list | — | Only files matching one of these are scanned. A pattern with no slash matches any path segment at any depth. |
exclude_patterns | list | — | Files and directories matching one of these are skipped. Exclude wins over include. |
max_file_size_mb | integer | 100 | Files larger than this are not read. The whole image is hashed and string-scanned, so an install image or a game asset bundle costs real time for nothing. |
max_depth | integer | 6 | How many levels of linked libraries to follow out from each scanned binary. |
library_paths | list | — | Directories searched when resolving a library name to a file, for libraries not on the default search path. |
max_workers | integer | 5 | How many binaries to analyse at once. |
follow_symlinks | boolean | false | Descend into symlinked directories. Off by default: a symlink loop, or one pointing at a network share, turns a bounded scan into an unbounded one. |
Detection and signatures
| Field | Type | Default | Description |
|---|---|---|---|
detect_dependency | boolean | true | Match against linked libraries. |
detect_symbol | boolean | true | Match against symbol names. |
detect_string | boolean | true | Match against strings in the image. |
detect_filename | boolean | true | Match against the file name. |
version_extraction | boolean | true | Extract library version strings. Turn off for a faster scan when only the library matters. |
version_max_scan_bytes | integer | 0 | Read only this many bytes of each image when looking for versions. 0 scans the whole file. |
crypto_signature_file | string | — | Path to a JSON file of additional detection signatures, merged over the built-in set by id. |
additional_signatures | list | — | Inline signature definitions. Each needs id, type, patterns, family and optionally weight. An entry sharing an id with a built-in overrides it. |
log_level | string | INFO | DEBUG emits three lines per file examined — what you want when diagnosing why a binary was not matched, and far too much otherwise. |
A minimal configuration:
ExtName: Discover_Binary
Config:
config_name: "linux-system-binaries"
paths:
- /usr/bin
- /usr/lib
- /opt
A realistic configuration, scoped and with a custom signature for an in-house library:
ExtName: Discover_Binary
Config:
config_name: "app-tier-binaries"
paths:
- /opt/payments
- /usr/local/lib
exclude_patterns:
- "*/node_modules/*"
- "*/test/*"
- "*.debug"
max_file_size_mb: 50
max_depth: 4
max_workers: 8
version_extraction: true
additional_signatures:
- id: acme_crypto_dep
type: dependency
patterns: ["libacmecrypto"]
family: "ACME Crypto"
weight: 0.9
Scoping. This is the sensor where scope matters most. Pointing it at / or C:\ reads every file on the host, and the time is spent on install images, media and build artefacts that carry no crypto. Name the directories where your software actually lives — the system binary directories plus your application roots — and exclude dependency and build trees. A scan that takes twenty minutes and answers the question beats one that takes six hours and is cancelled.
Execution modes
On an agent. The normal mode. Include the sensor in a deployment to the host, with paths appropriate to that host's operating system. A template intended for both Linux and Windows hosts needs the paths for both, since a path that does not exist is skipped rather than failing the scan.
Off-grid. Fully supported, and a common choice for isolated build hosts and appliance images. The bundle runs on the host, writes its results to a file, and that file is imported.
Through the API. Deploy the task carrying the sensor and read the ingestion counts back. See the Scan and Discovery API reference.
Platform execution. Only scans the platform host's own filesystem. Useful for the platform's own inventory, not for anything else.
Known limitations
| Limitation | Effect |
|---|---|
| Packed and obfuscated binaries | A packed executable reveals neither imports nor strings until it unpacks itself at run time. The sensor sees the packer, not the payload. |
| Interpreted and bytecode artefacts | A JVM artefact is classified as such, but the sensor reads it as a binary image rather than decompiling it. Crypto called from Java source is found by the source code sensor. |
| Statically linked and stripped | With no dependency entries and no symbols, only the string and filename methods remain, and confidence drops accordingly. This is reflected in the weight, not hidden. |
| Dynamic loading at run time | A library loaded by dlopen or LoadLibrary from a name computed at run time has no static reference to find. |
| Embedded key material | Not extracted. A key compiled into a binary is not reported as a key. |
| Vulnerability correlation | The sensor records library and version. Correlating those against CVE feeds is a separate capability and is not part of this scan. |
| Signature verification tooling | Where the platform's verification tooling is unavailable, signature state is reported as unknown rather than as unsigned. |
Troubleshooting
The scan takes hours. The scope is too wide. Check paths first, then add exclude_patterns for dependency and build directories, then lower max_file_size_mb. Turning off version_extraction is the last resort — it is the field that makes the results useful.
Binaries found, no crypto detected. Expected for most of a filesystem: most binaries carry no cryptography. If a binary you know uses crypto is not matched, set log_level: DEBUG and re-run against that one file. Check that the detection method it would need is enabled — a statically linked binary needs detect_symbol or detect_string.
A library is detected but has no version. The image carries no version string, or version_max_scan_bytes cut the search short before reaching it. Set it to 0.
Everything reports as unsigned. The signature verification tooling is not available to the account running the agent, or the account cannot execute it. This reports as unsigned where it should report as unknown — check the log for verification errors before treating it as a finding.
Permission denied on system directories. The agent account lacks read access. Grant read on the specific directories rather than elevating the account.
A linked library was not resolved. The library is not on the default search path. Add its directory to library_paths.
The same binary appears on many hosts. That is correct and intended: one binary deployed to forty hosts is one material with forty deployments, which is what makes "how many hosts run this vulnerable version" answerable.
Getting support
Collect the platform version, the sensor configuration, the task and template names, the operating system and version of the scanned host, and a DEBUG-level log extract for the specific file in question. Where the issue is a binary that was not matched, the most useful single thing to include is that binary's dependency list — ldd on Linux, dumpbin /dependents on Windows. Redact file paths only where your organisation requires it.