A cross-platform osquery extension (Go) that gives Fleet visibility into the
agentic software layer that traditional EDR/MDM and osquery's built-in tables
miss: MCP servers, AI agent CLIs, AI desktop apps, AI browser extensions, IDE plugins, live AI/MCP
network sockets, and agent instruction files. (AI-native browsers like Comet and Dia appear as apps.)
Beyond inventory, every row carries a security posture: a sha256 content
fingerprint for change detection / threat-intel matching, and risk_flags
surfacing supply-chain exposure (unpinned npx/uvx remote-exec), inferred MCP
capabilities (shell-exec, fs-write), plaintext secrets in configs, agent
autonomy mode (auto-approve / skip-permissions), and prompt-injection markers or
hidden Unicode in instruction files.
Agent discovery is multi-signal, not keyword-only. A shared evidence engine
fuses tool homes (e.g. ~/.grok, ~/.hermes), binaries, package/framework
fingerprints, workspace shape (skills + MCP + instruction packs), and live
processes. Known catalog tools always emit; unknown CLIs, harnesses, and
custom agents can still surface with a confidence score and evidence tokens.
Name matching alone never creates a row.
It is detection-only — read-only tables, no remediation. It never executes a discovered binary, and never connects to an MCP server to enumerate its tools (capability is inferred statically); files are read and hashed, never run.
One table covers everything. A type column discriminates the row type; common
fields are first-class columns; type-specific extras live in a compact JSON
detail column. The extension emits one row per user per host —
enumerating all home directories (/Users/*, /home/*+/root, C:\Users\*),
not just the daemon account's.
type |
Row represents |
|---|---|
mcp_server |
An MCP server declared in any client config (Claude Desktop/Code, Cursor, Windsurf, VS Code, Zed, Cline, Roo, Continue, Hermes, OpenClaw, Grok, Codex, Jan, Gemini/Antigravity) and/or a running MCP server process. |
ide_plugins |
An installed editor plugin (VS Code family incl. Cursor/Windsurf/VSCodium/Trae/Antigravity/code-server, JetBrains, Zed, Sublime, Neovim/Vim, Emacs). |
agents |
An AI agent CLI or harness: catalog tools (Claude Code, Gemini, Codex, Grok, aider, goose, opencode, Cline, Continue, cursor-agent, Amazon Q/Kiro, …) plus multi-signal candidates (tool homes, frameworks, strong workspace shape — e.g. Hermes, OpenClaw-class, custom agents). |
apps |
An installed AI desktop app (Claude Desktop, ChatGPT, Ollama, LM Studio, Jan, GPT4All, Msty, AnythingLLM, Perplexity, Cursor, Windsurf, Antigravity). |
sockets |
A live AI/MCP network socket — local inference/MCP listener or outbound AI/MCP egress. |
agent_instruction |
An agent instruction file the AI auto-loads and obeys (CLAUDE.md, AGENTS.md, GEMINI.md, .cursorrules, .github/copilot-instructions.md, Cursor .mdc rules, …) — a prompt-injection / agent-hijack surface. |
browser_extension |
An AI extension installed in a Chromium-family browser (Chrome, Edge, Brave, Arc, Opera, Vivaldi, Chromium, Comet, Dia) or a Gecko-family browser (Firefox, Zen, LibreWolf, Waterfox). Comet and Dia browser applications themselves also surface as apps rows. |
type, name, identifier, category, location, source, version, path, endpoint, running, pid, port, risk_flags, sha256, confidence, evidence, uid, username, detail
Every row is an AI tool by construction (collectors emit only AI/agent artifacts), so there is no is_ai column — presence in the table is the signal.
| Column | Meaning (varies by type) |
|---|---|
name |
server / plugin / agent / app / process / instruction-file name |
identifier |
mcp server name · publisher.name · agent binary · bundle id · socket service · instruction tool |
category |
classification bucket (coding-assistant, agent-runtime, agent-harness, inference-api-local, mcp-remote-egress, ai-api-egress, mcp-server, agent-instruction, …) |
location |
local or remote |
source |
provenance: MCP client · editor · install method · platform source · socket direction · instruction tool · evidence for multi-signal candidates |
path |
config / install / binary / app / process / instruction-file path |
endpoint |
remote MCP url, or socket remote addr:port |
running,pid,port |
liveness; port = listening / api / local port |
risk_flags |
comma-separated security risk tokens, "" = none (see below) |
sha256 |
content hash of the primary artifact (MCP config, agent/app binary, instruction file) — a diffable identity for change detection and threat-intel matching |
confidence |
integer 0–100 multi-signal confidence (catalog / known tools = 100; candidates lower) |
evidence |
CSV of detection signals (e.g. catalog,binary,running,tool_home or workspace_shape,mcp_config,instructions) |
detail |
JSON of type-specific extras (transport, args, env_keys (names only), capabilities, launch_hash, permission_mode, markers, scope, size, publisher, editor_family, runtime, protocol, remote_host, cmdline, kind = catalog|candidate, …) |
Common columns are shared field slots, but only some are populated per type —
the rest are empty for that row. Type-specific data lives in detail instead.
| Column | mcp_server |
ide_plugins |
agents |
apps |
agent_instruction |
browser_extension |
sockets |
|---|---|---|---|---|---|---|---|
name |
✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
identifier |
server name | plugin id | binary | bundle id | tool | extension id | service |
category |
mcp-server |
AI category | agent category | — | agent-instruction |
✓ | ✓ |
location |
local/remote | local |
local |
local |
local |
local |
local/remote |
source |
client | editor | install method | platform source | tool | browser | direction |
version |
— | ✓ | ✓ | ✓ | — | ✓ | — |
path |
config path | install path | ✓ | ✓ | ✓ | ✓ | process path |
endpoint |
remote URL | — | — | — | — | — | remote addr:port |
running, pid |
✓ | — | ✓ | ✓ | — | — | ✓ |
port |
listening port | — | — | API port | — | — | local port |
risk_flags |
✓ | — | ✓ | — | ✓ | ✓ | — |
sha256 |
✓ | — | ✓ | ✓ | ✓ | ✓ | — |
confidence, evidence |
— | — | ✓ | — | — | — | — |
uid, username |
✓ | ✓ | ✓ | — | ✓ | ✓ | username only |
detail keys per type:
| Type | detail keys |
|---|---|
mcp_server |
transport, command, args, env_keys, scope, source_type, enabled, capabilities, launch_hash |
ide_plugins |
editor_family, publisher, manifest_path |
agents |
runtime, binary, binary_path, permission_mode, kind (catalog|candidate) |
apps |
vendor, bundle_id, scope, serves_local_api |
agent_instruction |
scope, size, markers |
browser_extension |
browser, profile, engine, manifest_version, scope, host_perms, from_webstore, signed_state |
sockets |
protocol, local_address, remote_host, service, cmdline |
| Band | Range | Meaning |
|---|---|---|
| Known | 100 | Catalog / allowlisted agent CLI |
| High | 70–99 | Multi-signal (e.g. tool home + binary + running) |
| Medium | 40–69 | Strong workspace shape offline, or framework fingerprint alone |
| Low (still emitted) | 30–39 | Borderline multi-signal |
| Not emitted | — | Name-only, or a single weak marker (e.g. only AGENTS.md) |
For a strict inventory of high-trust rows only:
SELECT name, type, confidence, evidence FROM ai_tools WHERE confidence >= 80;| Token | Type | Meaning |
|---|---|---|
remote_fetch_exec |
mcp_server | Launched via npx/uvx/bunx/pnpx — fetches and runs code at every start |
unpinned_dependency |
mcp_server | …and that fetched package is unpinned / @latest (mutable supply chain) |
mcp_shell_exec, mcp_fs_write |
mcp_server | Inferred high-risk capability (shell execution / filesystem write) |
plaintext_secret |
mcp_server | A secret-shaped env var name is set inline in the config (value on disk) |
world_readable_config |
mcp_server | The declaring config file is group/other-readable |
cleartext_endpoint |
mcp_server | Remote MCP reached over plain http:// |
bypass_permissions, auto_accept_edits |
agents | Declared autonomy posture (Claude Code permissions.defaultMode) |
skip_permissions_runtime |
agents | Running with an unattended auto-approve / sandbox-disabled flag |
injection_markers |
agent_instruction | Content carries prompt-injection / exfiltration phrases (see detail.markers) |
hidden_unicode |
agent_instruction | Contains zero-width / Unicode-tag characters used to smuggle instructions |
world_writable |
agent_instruction | File is world-writable — any local user can hijack the agent |
broad_host_permissions |
browser_extension | Manifest grants <all_urls> / *://*/* host access — can read/modify every site (AI exfiltration surface) |
sideloaded_unverified |
browser_extension | Installed outside the store (Chromium: not from_webstore / unpacked / policy-forced; Gecko: unsigned/temporary or foreignInstall) — no store review |
Capability inference is static (from the known-server KB): the extension never connects to an MCP server to enumerate live tools, because that would mean executing untrusted code.
Lightweight by design: a query with WHERE type = '…' (or type IN (…))
only runs the collectors it needs (constraint pushdown); the process/connection
snapshot, home enumeration and config scan happen at most once per query and
are shared across collectors; type = 'ide_plugins' skips the process snapshot
entirely.
Run these in the osquery> shell (make run), or one-shot by passing the
SELECT as the last arg to osqueryi with the flags from
Local verification.
-- shell dot-commands (shell only, not one-shot):
.tables ai_tools -- confirm the table registered
.schema ai_tools -- list columns
.mode line -- readable output for wide rows
-- counts per type
SELECT type, count(*) FROM ai_tools GROUP BY type;
-- everything on the host (every row is an AI tool)
SELECT type, name, category, running FROM ai_tools LIMIT 20;
-- agent CLIs with multi-signal confidence (catalog + candidates)
SELECT name, category, confidence, evidence, running, pid, path
FROM ai_tools WHERE type = 'agents' ORDER BY confidence DESC;
-- Grok CLI (catalog + tool home + live process) — example live result shape:
-- name=grok confidence=100 evidence=binary,catalog,running,tool_home,workspace_shape
-- running=1 pid=<pid> path=/Users/<you>/.local/bin/grok
SELECT name, category, confidence, evidence, running, pid, path
FROM ai_tools WHERE type = 'agents' AND name = 'grok';
-- harnesses / multi-agent orchestrators (framework or strong workspace shape)
SELECT name, path, confidence, evidence
FROM ai_tools WHERE type = 'agents' AND category = 'agent-harness';
-- candidate / non-catalog agents only (shadow IT, custom agents)
SELECT name, path, confidence, evidence
FROM ai_tools WHERE type = 'agents' AND confidence < 100;
-- outbound AI/MCP connections — where data is going
SELECT name, endpoint FROM ai_tools WHERE type = 'sockets' AND location = 'remote';
-- running MCP servers, local stdio vs remote
SELECT name, source AS client, location, running, pid
FROM ai_tools WHERE type = 'mcp_server' AND running = 1;
-- AI editor plugins with versions
SELECT name, identifier, version, category
FROM ai_tools WHERE type = 'ide_plugins';
-- pull a type-specific extra out of the JSON detail column
SELECT name, json_extract(detail, '$.transport') AS transport, endpoint
FROM ai_tools WHERE type = 'mcp_server';
-- anything carrying a security risk flag, across every type
SELECT type, name, risk_flags, path FROM ai_tools WHERE risk_flags != '';
-- MCP servers that fetch unpinned remote code at launch (supply-chain risk)
SELECT name, json_extract(detail, '$.command') AS cmd, json_extract(detail, '$.args') AS args
FROM ai_tools
WHERE type = 'mcp_server' AND risk_flags LIKE '%unpinned_dependency%';
-- agents running unattended (auto-approve / skip-permissions)
SELECT name, risk_flags, json_extract(detail, '$.permission_mode') AS mode
FROM ai_tools WHERE type = 'agents' AND risk_flags != '';
-- instruction files flagged for prompt injection or hidden unicode
SELECT name, path, risk_flags, json_extract(detail, '$.markers') AS markers
FROM ai_tools WHERE type = 'agent_instruction' AND risk_flags != '';
-- AI browser extensions, with the browser and profile they live in
SELECT name, source AS browser, category,
json_extract(detail, '$.engine') AS engine,
json_extract(detail, '$.profile') AS profile, version
FROM ai_tools WHERE type = 'browser_extension';
-- risky browser extensions: read-every-site host access or installed outside the store
SELECT name, source AS browser, risk_flags,
json_extract(detail, '$.from_webstore') AS from_webstore,
json_extract(detail, '$.signed_state') AS signed_state
FROM ai_tools
WHERE type = 'browser_extension' AND risk_flags != '';.tables/.schema/.mode are osquery shell dot-commands — they only work
inside the interactive shell, not as a one-shot query string. The SELECTs work
both ways. Filtering on type keeps queries cheap: only the matching collectors
run (constraint pushdown).
- Browser extensions — per-profile enumeration across Chromium (
Extensions/<id>/<version>/manifest.jsonunioned with the profile'sPreferences/Secure Preferencesregistry for install provenance and unpacked recovery) and Gecko (extensions.json+ the.xpiarchive). i18n (__MSG_*) names are resolved from_locales. Capability/permission risk is read statically from the manifest — no extension is loaded or executed. - Config parsing — JSON/YAML/TOML across every known MCP client;
command⇒local,url/serverUrl⇒remote; VS Code'sserverskey vs everyone else'smcpServers; Hermes/Grok/Codexmcp_servers(YAML/TOML); OpenClaw nestedmcp.servers; Zed's nestedcommandobject; Jan/Gemini mcp_config.json; per-project.mcp.json/.cursor/.vscode/.roovia a bounded walk of common dev roots. - Process/connection snapshot — one
gopsutilsnapshot per query feeds liveness (running/pid), listening-port fill, and thesockets-type rows. - Classification KB —
internal/classify/kb.json(embedded) maps known extension ids, process-cmdline markers, inference ports, and MCP-server capability tags to categories. Egress is attributed process-first (an AI/agent process's connections are AI traffic — caught by cmdline markers, not a hostname list) before any DNS heuristic; no brittle IP allowlists. - Integrity fingerprints — every MCP config, agent/app binary, and instruction file is SHA-256 hashed (
sha256column) plus alaunch_hashover each MCP server's command/args/url, so a SIEM can detect a changed binary or a silently-mutated launch vector (rug-pull) by diffing snapshots. - Risk posture — static, KB-driven flags surface supply-chain exposure (
remote_fetch_exec/unpinned_dependency), inferred MCP capabilities (mcp_shell_exec/mcp_fs_write), plaintext secrets and world-readable configs, agent autonomy mode (bypass_permissions/skip_permissions_runtime), and prompt-injection markers / hidden unicode in instruction files. Seerisk_flagstokens. - No execution — files are read, hashed, and parsed but never interpreted or run; MCP capability is inferred from the known-server KB rather than enumerated by connecting, preserving the extension's no-exec posture even when running as root.
make check # gofmt + go vet + go test -race
make build-all # all platform binaries into ./build/ (Fleet-named)Outputs (named exactly as Fleet expects):
build/agentic_detector_macos.ext # universal (amd64 + arm64)
build/agentic_detector_linux.ext # amd64
build/agentic_detector_windows.ext.exe # amd64
Sign the binaries before distributing or running a downloaded copy — see Signing & trust below.
Each release attaches
the three platform binaries plus SHA256SUMS. Downloading needs the
gh CLI (the repo is private).
| Platform | Asset |
|---|---|
| macOS (Intel + Apple Silicon) | agentic_detector_macos.ext (universal) |
| Linux x86-64 | agentic_detector_linux.ext |
| Windows x86-64 | agentic_detector_windows.ext.exe |
The binaries are not code-signed, so a downloaded copy is quarantined — clear it (below) or sign it (Signing & trust).
macOS — download → clear quarantine → run:
gh release download v0.3.0 -R karmine05/agentic-detector -p 'agentic_detector_macos.ext'
xattr -d com.apple.quarantine agentic_detector_macos.ext # unsigned → clear quarantine
osqueryi --allow_unsafe --extension "$PWD/agentic_detector_macos.ext" \
--extensions_require=agentic_detector --extensions_timeout=10 \
"SELECT type, count(*) FROM ai_tools GROUP BY type"Linux:
gh release download v0.3.0 -R karmine05/agentic-detector -p 'agentic_detector_linux.ext'
chmod +x agentic_detector_linux.ext
osqueryi --allow_unsafe --extension "$PWD/agentic_detector_linux.ext" \
--extensions_require=agentic_detector --extensions_timeout=10 \
"SELECT type, count(*) FROM ai_tools GROUP BY type"Windows (PowerShell):
gh release download v0.3.0 -R karmine05/agentic-detector -p 'agentic_detector_windows.ext.exe'
Unblock-File agentic_detector_windows.ext.exe
osqueryi.exe --allow_unsafe --extension "$PWD\agentic_detector_windows.ext.exe" `
--extensions_require=agentic_detector --extensions_timeout=10 `
"SELECT type, count(*) FROM ai_tools GROUP BY type"Verify integrity before running:
gh release download v0.3.0 -R karmine05/agentic-detector -p SHA256SUMS
shasum -a 256 -c SHA256SUMS # Linux: sha256sum -c SHA256SUMS--extensions_require / --allow_unsafe are explained in
Local verification; more queries in
Example queries.
Two separate things gate running the extension — don't conflate them:
- OS trust (signing) — macOS Gatekeeper / Windows SmartScreen block downloaded, unsigned binaries from executing. This is what code-signing solves.
- osquery's load check — osquery refuses to autoload an extension that is
world-writable or not owned by root/Administrator (independent of any
signature), unless you pass
--allow_unsafe. Covered at the end.
The release binaries are unsigned. Sign per platform before distribution; for a
one-off local run you can ad-hoc sign (below) or just clear quarantine
(xattr -d com.apple.quarantine … / Unblock-File …).
# (a) Local / ad-hoc — enough to run on this machine. Also re-stamps the
# signature that `lipo` invalidates when it fuses the two arch slices.
codesign --force --sign - agentic_detector_macos.ext
codesign -dv --verbose=2 agentic_detector_macos.ext # verify
# (b) Distribution (other Macs / MDM) — Developer ID + notarization.
codesign --force --options runtime --timestamp \
--sign "Developer ID Application: <ORG> (<TEAMID>)" agentic_detector_macos.ext
ditto -c -k agentic_detector_macos.ext ext.zip # notarize a container
xcrun notarytool submit ext.zip --apple-id <id> --team-id <TEAMID> \
--password <app-specific-password> --waitA standalone Mach-O can't be stapled (no container) — the notarization ticket is checked online at first launch, or staple the distribution package instead. For fleetd/MDM autoload the binary is placed on disk by the agent (not quarantined), so Developer ID signing is recommended but notarization isn't strictly required.
# Production cert:
signtool sign /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 /a `
agentic_detector_windows.ext.exe
signtool verify /pa agentic_detector_windows.ext.exe # verify
# Dev / self-signed (testing only):
$c = New-SelfSignedCertificate -Type CodeSigningCert `
-Subject "CN=agentic-detector-dev" -CertStoreLocation Cert:\CurrentUser\My
Set-AuthenticodeSignature agentic_detector_windows.ext.exe -Certificate $cNo OS-level code signature is needed to execute. Trust is established by checksum (and optionally a detached GPG signature over the artifact):
sha256sum -c SHA256SUMS
gpg --detach-sign --armor agentic_detector_linux.ext # optional, publisher-side
gpg --verify agentic_detector_linux.ext.asc # consumer-sideBefore a production autoload (without --allow_unsafe):
# macOS / Linux — root-owned, not world-writable, parent dir likewise
sudo chown root agentic_detector_*.ext && sudo chmod 755 agentic_detector_*.extWindows: the .ext.exe and its parent directory must be owned by
Administrators with inheritance disabled. fleetd/orbit handles this placement
automatically when it deploys the extension.
Fleet's agent (fleetd/orbit) distributes custom extensions through a TUF
auto-update server and autoloads them. (Fleet Premium.)
-
Push each platform binary to your TUF repo:
fleetctl updates add --path <TUF_repo> \ --target build/agentic_detector_macos.ext \ --name extensions/agentic_detector_macos --platform macos --version 0.3.0 # repeat for linux / windows
-
Reference them in
agent_options(gitops orfleetctl apply):agent_options: extensions: agentic_detector_macos: { channel: 'stable', platform: 'macos' } agentic_detector_linux: { channel: 'stable', platform: 'linux' } agentic_detector_windows: { channel: 'stable', platform: 'windows' }
-
Query like any built-in table (live query or scheduled query). Filtering on
typekeeps it cheap (only the needed collectors run):-- remote MCP servers SELECT name, source, endpoint FROM ai_tools WHERE type = 'mcp_server' AND location = 'remote'; -- AI editor plugins SELECT name, identifier, version, category FROM ai_tools WHERE type = 'ide_plugins'; -- live AI/MCP egress + local inference listeners SELECT name, category, endpoint, port FROM ai_tools WHERE type = 'sockets'; -- everything on the host, one query (every row is an AI tool) SELECT type, name, category, running FROM ai_tools;
make check # gofmt + vet + race tests
make sec # gosec static security analysis
AED_SMOKE=1 go test -run TestSmokeLiveHost -v ./tables/ # run generators against THIS host
# Dependency CVE scan (Go vuln DB). govulncheck must build under the pinned
# toolchain — the base `go`/a prebuilt govulncheck binary can't load go1.26 pkgs:
GOTOOLCHAIN=go1.26.4 go run golang.org/x/vuln/cmd/govulncheck@latest ./...Against a real osquery (requires osqueryi on PATH — brew install --cask osquery):
make run # interactive osquery> shell with the extension loaded
make run-root # same, as root (sees all users + all sockets, like fleetd)
make osq-verify # one-shot: row counts per type (macOS, host-native)
make osq-verify-linux # load the linux .ext: native osqueryi on Linux, else a linux/amd64 container
make osq-verify-windows # load the windows .ext.exe — Windows host onlyosqueryi loads only the host-native extension, so the linux/windows
builds are verified by running osquery on (or emulating) those OSes:
osq-verify-linuxruns nativeosqueryion a Linux host; on macOS it loads the amd64 build inside alinux/amd64osquery container (needs Docker).osq-verify-windowsrunsosqueryi.exeon a Windows host. Windows containers can't run on a macOS/Linux Docker host, so there's no cross-host path — run it on Windows or awindows-latestCI runner.
A clean container / fresh host has no AI tools installed, so an empty result
is a pass: --extensions_require makes osqueryi exit non-zero if the
extension fails to register, which is the real cross-platform signal.
Inside the osquery> shell: .tables lists tables, .schema ai_tools
shows columns, .mode line makes wide rows readable, then run any SQL. Exit
with .exit, .quit, or Ctrl-D.
Raw equivalent — note the two flags that matter:
osqueryi --allow_unsafe \
--extension "$PWD/build/agentic_detector_macos.ext" \
--extensions_require=agentic_detector --extensions_timeout=10 \
"SELECT type, name, category, running FROM ai_tools"--extensions_require=agentic_detector— required for one-shot queries. Without it,osqueryi "QUERY"runs before the extension finishes its async registration and reportsno such table: ai_tools. (Interactiveosquery>sessions are fine without it — registration completes before you type.)--allow_unsafe— local testing only; in production osquery enforces root-owned, non-world-writable extension binaries.
- No execution of discovered binaries — versions come from manifests
(
package.json, pipxdist-info, Homebrew paths,Info.plist, registry); MCP capabilities are inferred from the KB, never enumerated by launching a server. Hashing reads file bytes only. - No secret exposure — the MCP
env_keysfield (indetail) lists env-var names only, never values. Theplaintext_secretflag is raised purely from a secret-shaped name; the value is never read or emitted. - Code-signature verification is deferred — the
sha256fingerprint is emitted, but signature/notarization checks (which require spawningcodesign/ Authenticode tooling) are intentionally left out to keep the no-subprocess posture; pair the hash with external threat-intel instead. - Bounded — project-config discovery walks a capped set of dev roots to a shallow depth, so arbitrary project locations are partial coverage.
- Egress attribution is process-first — a
socketsrow isai-api-egressbecause the owning process is an AI/agent tool, not because of the destination IP. Hosted-AI-API IPs are intentionally not matched: cloud providers share IPs across services, so IP-based attribution mislabels unrelated traffic. Loopback connections are treated as local IPC, not egress. The one place a hostname is resolved — mapping a user-declared remote MCP host to its IPs — uses a bounded (2 s/lookup), cancellable resolver that honors the query's context, so the root scanner never hangs on slow or hostile DNS for an attacker-supplied config hostname. - Multi-user as root — when
fleetdruns the extension as root it reads all users' homes; under an unprivileged run, unreadable homes yield partial rows rather than errors. - Dependency & code hygiene — the module is
govulncheck-clean (Go vuln DB) andgosec-clean; the Go toolchain is pinned (go 1.26.4) to keep reachable stdlib CVEs at zero. See Local verification for the scan commands.