Okta recently introduced advanced posture checks within the Okta Verify client for macOS and Windows. This feature leverages osquery, a lightweight endpoint agent, which can run a SQL query at the point of log in to detect critical device data — launchd services, file paths, running processes, package managers, listening ports, installed apps, and container artifacts — that collectively provide a device assurance signal at sign-in time. With advanced posture checks, if a device isn’t meeting the expected device hygiene standard, that user doesn’t get access.

As a follow up, we showed how you might use this capability to detect if security applications that should be running are disabled or not running. Our team published a security tooling watchdog detection that scores a device based on the expected security tools that should be running, from mobile device management (MDM) software to data leak prevention (DLP) tools to DNS security software. 

One of the great aspects of osquery is that it can adapt to an evolving threat environment. The real value isn't catching one threat but getting broad visibility into whatever is running on a device, including AI agents, coding assistants, and local model runtimes that have quietly become part of everyone's development environment. 

To make that easier on day one, we have published a broad set of sample checks in Okta's public customer-detections repository, covering 24 distinct AI tools across macOS and Windows.

Unauthorized AI tooling

Security teams have spent the last two years developing policies for the use of SaaS AI chat interfaces, but the work isn’t done. The next challenge is the second wave of tooling that is showing up alongside it:

  • Agentic coding assistants read and write files, execute shell commands, and call external services with little or no per-action confirmation — Cursor, Goose, Aider, Cline, Windsurf, OpenAI Codex CLI, Gemini CLI, and more.

  • Local LLM runtimes like Ollama, LM Studio, GPT4All, and llama.cpp run models directly on the endpoint and, in several default configurations, expose an unauthenticated REST API on the local network.

  • Cloud-connected desktop apps and IDE extensions transmit code, files, and conversation history off the device by design. These include ChatGPT Desktop, GitHub Copilot, Microsoft Copilot, Sourcegraph Cody, Tabnine and Supermaven.

  • Enterprise-credentialed agents such as Kiro (Amazon Q's successor) inherit AWS IAM Identity Center sessions and can carry the same permissions as the signed-in user, including access to production infrastructure.

These agentic applications fall into two categories. One class of agent authenticates, such as a Claude Code session authenticating through SSO. But most are in a different class — a developer installing Ollama or connecting Cursor to a private repo without registering the agent with an identity provider. This is “shadow AI” and is one of the most common feedback points that Okta hears in AI-related conversations. The majority of organizations report AI agents in production with no formal governance and no consistent ownership assigned. This introduces risk to every organization.

Sensitive source code and secrets may leave the organization through an agentic channel a DLP tooling was never built to inspect. An autonomous agent with shell access running unattended on a device may authenticate into a sensitive app, with admins wondering later what tool rm -rf’d the database. Administrators cannot shut down an agent that security doesn't know exists. 

There is a way to provide visibility and clarity. Endpoint-level detection is what turns a guess — "we assume engineers are running local AI tools" — into assets that can be managed and incorporated into a device assurance policy.

Even for the tools that do have a real identity story — Kiro's AWS IAM Identity Center session or an OAuth grant for Copilot's GitHub OAuth grant — device posture is still a separate, necessary signal. Knowing an agent authenticated correctly doesn’t mean the device it's running on should be trusted. That's the gap these checks are aimed at, and it's complementary to identity-layer controls. Advanced posture checks let you turn a tool’s posture into a condition of access.

Cross-platform tool repository

The sample_osquery_checks folder is organized by platform:

sample_osquery_checks/
├── Cross/     # checks that apply to any OS (supply-chain / malware campaigns)
├── macOS/     # macOS-specific osquery tables
└── Windows/   # Windows-specific osquery tables

Every check is a YAML file with the same style:

title: <Human-readable name>
id: <Unique identifier>
description: <What the check detects and why it matters>
references:
  - <Links to vendor docs or threat intel>
author:
  - <Author email>
platform:
  - macOS | Windows | Linux
query: |
  <osquery SQL query>

 

In this example, "query" is a standard SQL query against osquery's virtual tables. It should return a non-empty result when the condition is detected, and an empty result on a clean device. That result feeds directly into the device assurance policy evaluation in Okta Verify.

Of the 24 tools covered in the repository, 23 have both macOS and Windows variants (adapted to each platform's osquery schema — apps and launchd on macOS versus programs and services on Windows); Microsoft Copilot is Windows-only, for obvious reasons.

Category

Tools

Agentic coding CLIs / IDE agents

Aider, Cline/Roo, Continue.dev, Cursor, Goose, Kimi Code, OpenCode, Sourcegraph Cody, Supermaven, Tabnine, Windsurf/Codeium

Cloud coding assistants

GitHub Copilot, Microsoft Copilot, OpenAI Codex CLI, Gemini CLI, Claude (Desktop + Code), Kiro (Amazon Q)

Local LLM runtimes

Ollama, LM Studio, GPT4All, llama.cpp, Jan, AnythingLLM

Desktop chat clients

ChatGPT Desktop

Four risk types 

Every check follows the same structure the original post introduced: a set of independent Common Table Expressions (CTEs), each checking one artifact type, summed into a score, and thresholded. Two or more independent positive indicators (score > 1) are required before a check fires. This is a deliberate false-positive control. A stray file left over from an uninstall or a process name that happens to substring-match isn't enough to trip a check on its own. A binary and a config file and a running process together are much higher-fidelity signals. It's the same correlation logic that should be applied to any noisy single-source alert.

Here's the macOS check for Cursor, the AI-native VS Code fork, as a representative example:

title: Cursor AI Editor Detection
id: e9b3f6d2a7c1450e8f3b9d6a2c5e7f1b
description: |
    Detects the presence of Cursor, an AI-native code editor built on VS Code, on macOS devices.
    Cursor embeds AI coding assistance directly into the editor and by default sends code context
    — including open files, terminal output, and repository history — to Cursor's servers and
    third-party AI providers (OpenAI, Anthropic, Google). The editor's Agent mode can autonomously
    execute code, run terminal commands, and modify files without per-action confirmation. Privacy
    mode is available but requires explicit opt-in.
platform: macOS
query: |
    WITH launchd_cursor AS (
        SELECT COALESCE(COUNT(*), 0) AS total
        FROM launchd
        WHERE name LIKE '%cursor%'
    ),
    file_cursor AS (
        SELECT COALESCE(COUNT(*), 0) AS total
        FROM file
        WHERE path LIKE '/Applications/Cursor.app'
            OR path LIKE '/Users/%/.cursor/mcp.json'
            OR path LIKE '/Users/%/.cursor/extensions/%'
            OR path LIKE '/Users/%/Library/Application Support/Cursor/User/settings.json'
    ),
    process_cursor AS (
        SELECT COALESCE(COUNT(*), 0) AS total
        FROM processes
        WHERE name LIKE '%cursor%'
            AND path NOT LIKE '/System/%'
            AND path NOT LIKE '/Library/%'
    ),
    apps_cursor AS (
        SELECT COALESCE(COUNT(*), 0) AS total
        FROM apps
        WHERE (name LIKE '%cursor%' OR bundle_identifier LIKE '%cursor%')
            AND bundle_identifier NOT LIKE 'com.apple.%'
    ),
    final_score AS (
        SELECT
            launchd_cursor.total + file_cursor.total
            + process_cursor.total + apps_cursor.total
            AS score
        FROM launchd_cursor, file_cursor, process_cursor, apps_cursor
    )
    SELECT
        CASE WHEN score <= 1 THEN 0 ELSE 1 END AS cursor_detected
    FROM final_score;



Now let’s address a different tool: Ollama, a local LLM server. Ollama runs entirely on device, which means a DLP tool that inspects cloud API traffic is not applicable.


Ollama's REST API also binds to 0.0.0.0:11434 unauthenticated by default, which makes it reachable by anything else on the local network:



title: Ollama Local LLM Server Detection
platform: macOS
query: |
    WITH launchd_ollama AS (
        SELECT COALESCE(COUNT(*), 0) AS total FROM launchd WHERE name LIKE '%ollama%'
    ),
    file_ollama AS (
        SELECT COALESCE(COUNT(*), 0) AS total FROM file
        WHERE path LIKE '/Applications/Ollama.app'
            OR path LIKE '/Users/%/.ollama/models/%'
            OR path LIKE '/opt/homebrew/bin/ollama'
    ),
    process_ollama AS (
        SELECT COALESCE(COUNT(*), 0) AS total FROM processes WHERE name LIKE '%ollama%'
    ),
    netports_ollama AS (
        SELECT COALESCE(COUNT(*), 0) AS total FROM listening_ports
        WHERE port = '11434' OR path LIKE '%ollama%'
    ),
    final_score AS (
        SELECT launchd_ollama.total + file_ollama.total
            + process_ollama.total + netports_ollama.total AS score
        FROM launchd_ollama, file_ollama, process_ollama, netports_ollama
    )
    SELECT CASE WHEN score <= 1 THEN 0 ELSE 1 END AS ollama_detected
    FROM final_score;

Including the listening_ports table as an indicator alongside the process and file checks is what lets this query also flag a misconfigured installation — one that's exposed on the network — rather than just presence of the binary.

Goose, which is Block's open-source autonomous engineering agent, illustrates a third type of risk: an agent designed for unattended, multi-step task execution such as running test suites, modifying build pipelines and calling external APIs. It may do this with plaintext configurations that can contain API keys:

title: Goose AI Agent Detection
platform: macOS
query: |
    WITH file_goose AS (
        SELECT COALESCE(COUNT(*), 0) AS total FROM file
        WHERE path LIKE '/opt/homebrew/bin/goose'
            OR path LIKE '/Users/%/.config/goose/profiles.yaml'
            OR path LIKE '/Users/%/.local/share/goose/sessions/%'
    ),
    process_goose AS (
        SELECT COALESCE(COUNT(*), 0) AS total FROM processes
        WHERE name = 'goose' OR cmdline LIKE '%block-goose%'
    ),
    final_score AS (
        SELECT file_goose.total + process_goose.total AS score
        FROM file_goose, process_goose
    )
    SELECT CASE WHEN score <= 1 THEN 0 ELSE 1 END AS goose_detected
    FROM final_score;

And Kiro (AWS's successor to Amazon Q Developer) presents a potential fourth risk scenario — credential inheritance. Kiro authenticates through AWS IAM Identity Center, so a compromised Kiro session may include  signed-in user's actual AWS permissions:

title: Kiro (Amazon Q) AI Developer Tool Detection
platform: macOS
query: |
    WITH file_kiro AS (
        SELECT COALESCE(COUNT(*), 0) AS total FROM file
        WHERE path LIKE '/Applications/Kiro.app'
            OR path LIKE '/Users/%/.kiro/settings/mcp.json'
            -- residual Amazon Q artifacts from the Q-to-Kiro migration
            OR path LIKE '/Users/%/.amazonq/scopes/scope.json'
            OR path LIKE '/Users/%/.vscode/extensions/amazonwebservices.aws-toolkit-vscode-%'
    ),
    process_kiro AS (
        SELECT COALESCE(COUNT(*), 0) AS total FROM processes
        WHERE name LIKE '%kiro%' OR name LIKE '%amazon-q%'
    ),
    apps_kiro AS (
        SELECT COALESCE(COUNT(*), 0) AS total FROM apps
        WHERE name LIKE '%kiro%' OR bundle_identifier LIKE '%amazonq%'
    ),
    final_score AS (
        SELECT file_kiro.total + process_kiro.total + apps_kiro.total AS score
        FROM file_kiro, process_kiro, apps_kiro
    )
    SELECT CASE WHEN score <= 1 THEN 0 ELSE 1 END AS kiro_detected
    FROM final_score;

This query will catch installations of Amazon Q Developer, as it contains the legacy config path  (~/.amazonq/) and is included alongside Kiro's own paths.

We recommend tuning the threshold per tool as you collect fleet data. The default > 1 score in these samples is a reasonable starting point. Tools that ship fewer detectable artifacts (for example, Goose has two CTEs but Claude has eight) will have different false-positive/false-negative curves. Also, residual files from uninstalled tools can be a source of noise that is worth observing before you flip a check from monitoring mode to enforcement.

From score to sign-in decision

Each of these checks returns a single 0/1 column, which is what a device assurance policy condition expects. From there, it’s up to administrators to decide what, if any, action to take. These decisions may depend on the type of users and their roles. You may find that the same signal supports very different responses depending on the audience it's applied to. In practice that means you can go well beyond a binary allow/block per tool. Consider the following approach:

  • Block sign-in to sensitive apps from devices running unsanctioned agentic coding tools, particularly those with shell and/or file access.

  • Warn and notify an admin when a local LLM runtime is detected with a network-exposed port, so IT can follow up on the OLLAMA_HOST (or equivalent) configuration rather than blocking outright.

  • Allow with conditions — e.g., permit GitHub Copilot or Cursor for engineering groups, but block the agentic application for finance or legal.

  • Track adoption passively, without any enforcement, to understand shadow AI usage across the fleet before deciding on policy.

Every query can be run standalone through osqueryi (the interactive command-line shell of osquery) against a local instance to validate results before wiring it into a policy. We recommend monitoring these detections before you enforce. Incorporate the check into a policy in report-only mode first, and then review the hit rate across a representative slice of the fleet. Make sure the positives are real installations and not uninstall artifacts before moving to "block" mode. This will prevent a help-desk queue of locked out software engineers. 

Because every check follows the same CTE-and-threshold pattern, extending coverage to a new tool is a matter of copying one of these files and swapping in the paths, process names, and ports specific to that tool.

Closing the coverage gap

These queries represent a path to creating an inventory of AI tooling running across your fleet today. Security teams won’t have to guess — or more likely, sweat feverishly at night — wondering what agentic tools are running on devices. 

If writing osquery isn't your jam, Okta’s Identity Security Posture Management (ISPM) can do everything described in this blog post (and much more), with detection logic managed by Okta. When licensed under Okta for AI Agents it can detect unmanaged OAuth grants related to AI tools and flag administrators to bring those agents under management. 

The full set of 24 queries are available on Okta’s GitHub here. Contributions are welcome. If you're tracking an AI tool we haven't covered yet, fork the repository and submit a PR with a new check in the same YAML format. This is the fastest way to get it in front of every other team using this repo. 

Continue your Identity journey