Skip to content

Back to the catalog

Secret Scanning Dev Workstations with bagel + Fleet
recyclebin.zipwriteup

Secret Scanning Dev Workstations with bagel + Fleet

Describes an open-source workflow combining bagel (a Go-based CLI secret scanner for developer home directories, from Boost Security) with Fleet/osquery to detect and enforce policy on clear-text secrets on macOS workstations. The author's PoC repo, fleebag, packages bagel as a scheduled LaunchAgent, provides an osquery policy query using Fleet's parse_json table to flag critical findings, and shows how to gate SSO login via Entra Conditional Access until secrets are remediated, framed as a response to infostealer/supply-chain worm campaigns like Shai-Hulud.

TL;DR Open-source recipe using bagel + Fleet/osquery to detect clear-text secrets on dev workstations and block SSO login until they're remediated.
Document

What it is

A working osquery/Fleet detection query for surfacing bagel's clear-text secret findings from developer macOS workstations, plus the concrete gaps of the author's fleebag proof-of-concept. The summary names the workflow; the page hands you the actual SQL and the deployment caveats that decide whether it is safe to run.

How it works

bagel writes findings to /Users/<user>/Library/Logs/fleebag/results.json. Fleet's parse_json table flattens that JSON into path/parent/key/value rows, and the query reassembles findings via three CTEs joined on path and parent.

The non-obvious mechanics the page establishes:

  • One finding is exactly parent = 'findings/N'. The guard AND pj.parent NOT LIKE 'findings/%/%' is required — without it, sub-groups like findings/N/metadata and findings/N/locations emit NULL-filled rows carrying only a timestamp.
  • line_number lives at findings[N].metadata.line_number, not findings[N].line, so it needs its own CTE that strips the /metadata suffix from the parent.
  • locations[] is optional (present only when the same secret appears in multiple places) and is stitched back with GROUP_CONCAT.
  • Results order by severity (critical→low) via a CASE rank.

The policy query is a modified version that returns 1 when the file is fresh AND contains no critical findings — Fleet treats "rows returned" as pass, "none" as fail. Change critical to high to tighten tolerance.

What to do

Deploy the SQL above as a Fleet saved query for visibility, and its policy variant as the gate. Package bagel as a .pkg with a scheduled LaunchAgent, ship a full-disk-access MDM profile so bagel reads secret files without end-user prompts, and wire the failing policy to your IdP (Entra Conditional Access) to block SSO until remediated.

Caveats (stated by the author)

  • The glue repo is "vibe-coded" PoC quality; bagel/Fleet/osquery are serious, fleebag is not.
  • bagel ships ad-hoc signed, and the .pkg and MDM profile are unsigned/placeholder — review and sign your own build before any scale deployment.
  • It only detects; nothing removes secrets. It also has no view of installed packages or whether a found secret was already exfiltrated.
  • The full-disk-access profile identity must be replaced with your signed build's identity.
  • For actual storage hardening the author points to 1Password dev tools, YubiKeys for SSH/GPG, and file-access authorization via Santa or Phorion — none of which fleebag implements.

Organisations named here

  • Boost Security
  • Shai-Hulud

Technologies named here

  • Developer workstations
  • bagel
  • Fleet
  • PyPI
  • npm
  • osquery
  • VS Code extensions
  • TruffleHog
  • Fleebag
  • Open VSX
  • Homebrew
  • n8n
  • Phorion
  • Microsoft Entra
  • Santa
  • 1Password developer tools
  • YubiKey
  • macOS
  • Microsoft Entra ID
  • Slack

Techniques named here

  • Credential theft from developer workstations
  • Scheduled local secret scanning
  • Policy-based compliance enforcement
  • Conditional access blocking on policy failure

Threat actors named here

  • Shai-Hulud