|
| 1 | +<!-- SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. --> |
| 2 | +<!-- SPDX-FileCopyrightText: Copyright (c) 2026, Shrike Security, Inc. All rights reserved. --> |
| 3 | +<!-- SPDX-License-Identifier: Apache-2.0 --> |
| 4 | + |
| 5 | +# Shrike Security — Agent Action Governance |
| 6 | + |
| 7 | +Govern what an OpenClaw agent is allowed to **do**. This recipe installs a |
| 8 | +Shrike PreToolUse hook into a NemoClaw/OpenShell sandbox so every matched tool |
| 9 | +call is evaluated by Shrike's enforce plane before it runs, and denied when the |
| 10 | +verdict is `block` or `require_approval`. |
| 11 | + |
| 12 | +OpenShell contains *where* an agent can act (network, filesystem, syscalls). |
| 13 | +Shrike governs *what* a specific action is — a benign shell command is allowed; |
| 14 | +a destructive command, a SQL injection, an injected instruction, or a secret |
| 15 | +exfiltration attempt is denied — with the decision made server-side against |
| 16 | +organizational policy and returned as `allow` / `warn` / `require_approval` / |
| 17 | +`block`. The two compose: the sandbox is the cage, Shrike is the judgment. |
| 18 | + |
| 19 | +## Intended users and support boundary |
| 20 | + |
| 21 | +For operators running OpenClaw agents inside NemoClaw who want an action-level |
| 22 | +policy decision on tool calls without building approval logic into each agent. |
| 23 | + |
| 24 | +**Support boundary.** This is a community-maintained recipe contributed by |
| 25 | +Shrike Security, Inc. It is provided as-is under Apache-2.0. Product/API |
| 26 | +questions: <https://shrikesecurity.com>. Recipe issues: open a GitHub issue on |
| 27 | +this repository identifying the example. It is not covered by an NVIDIA support |
| 28 | +agreement. |
| 29 | + |
| 30 | +## Data-sharing boundary (read before enabling) |
| 31 | + |
| 32 | +When the hook evaluates an action, the **action content** — the shell command, |
| 33 | +SQL text, file-write body, web-search target, or message content of the matched |
| 34 | +tool call — is transmitted over TLS to `api.shrikesecurity.com` for evaluation. |
| 35 | +A decision and a short reason are returned; no other sandbox data is sent. If no |
| 36 | +Shrike credential is configured, the hook cannot obtain a verdict and (by |
| 37 | +default) denies the action fail-closed — nothing is transmitted without a key. |
| 38 | +Retention, GDPR/CCPA, and data-deletion posture: <https://shrikesecurity.com/privacy>. |
| 39 | + |
| 40 | +Do not enable this recipe on a workload whose tool-call content must never leave |
| 41 | +the sandbox. |
| 42 | + |
| 43 | +## Provenance |
| 44 | + |
| 45 | +Contributed by **Shrike Security, Inc.** Attribution is preserved in the SPDX |
| 46 | +headers of every file. Shrike Security authored the hook, policy, and lifecycle |
| 47 | +scripts; the recipe targets the public NemoClaw/OpenShell CLIs. |
| 48 | + |
| 49 | +## Prerequisites and supported environments |
| 50 | + |
| 51 | +- NemoClaw installed with a working OpenShell gateway (`nemoclaw`, `openshell` |
| 52 | + on `PATH`). Install: `curl -fsSL https://www.nvidia.com/nemoclaw.sh | NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 bash` |
| 53 | +- An inference provider (NVIDIA-hosted `build` endpoints, or any OpenAI-compatible endpoint). |
| 54 | +- A Shrike API key (free tier available): <https://shrikesecurity.com/signup> |
| 55 | +- `bash`, `node`, and `curl` available in the sandbox (present in the OpenClaw runtime). |
| 56 | +- Verified on macOS (arm64) and Linux hosts with a CPU-only OpenShell gateway. |
| 57 | + |
| 58 | +## Architecture and major components |
| 59 | + |
| 60 | +``` |
| 61 | +OpenClaw agent --(tool call)--> PreToolUse hook --(action content)--> Shrike enforce |
| 62 | + | | | |
| 63 | + | | allow/warn -> allow | server-side |
| 64 | + | <---------- decision ------------+ block/require_approval -> deny | 9-layer policy |
| 65 | +``` |
| 66 | + |
| 67 | +- `hooks/shrike-preaction-hook.mjs` — classifies the action (sql / command / |
| 68 | + file_write / web_search / general), calls the enforce plane, maps the verdict |
| 69 | + to an OpenClaw permission decision. Fail-closed by default. |
| 70 | +- `providers/shrike.yaml` — OpenShell v2 provider profile: declares the |
| 71 | + `SHRIKE_API_KEY` bearer credential and scopes egress to |
| 72 | + `api.shrikesecurity.com` with `enforcement: enforce`. Imported at onboard time. |
| 73 | +- `agents.yaml` — keeps the full toolset; governance is at the hook, not by |
| 74 | + removing tools. |
| 75 | +- `scripts/` — `onboard.sh`, `install.sh`, `verify.sh`, `status.sh`, `teardown.sh`. |
| 76 | + |
| 77 | +## Credential and secret handling |
| 78 | + |
| 79 | +`onboard.sh` imports the v2 provider profile (`providers/shrike.yaml`) and |
| 80 | +creates a provider instance with `openshell provider create`, supplying |
| 81 | +`SHRIKE_API_KEY` to the **gateway** once through a clean sub-environment. The |
| 82 | +sandboxed agent and hook reference only the placeholder |
| 83 | +`openshell:resolve:env:SHRIKE_API_KEY`; the OpenShell L7 proxy substitutes the |
| 84 | +real value on egress to `api.shrikesecurity.com`. The raw key is never written |
| 85 | +into the sandbox environment, filesystem, or agent context. `.env` holds the key |
| 86 | +on the host only (for the one `provider create` call) and is git-ignored. |
| 87 | + |
| 88 | +## Setup and configuration |
| 89 | + |
| 90 | +```bash |
| 91 | +cp .env.example .env # set SHRIKE_API_KEY + your inference provider vars |
| 92 | +bash scripts/onboard.sh # import provider profile + create provider (key held gateway-side) + onboard sandbox |
| 93 | +bash scripts/install.sh # install the PreToolUse hook into the sandbox |
| 94 | +``` |
| 95 | + |
| 96 | +Overridable knobs (in `.env`): `NEMOCLAW_SANDBOX_NAME`, `SHRIKE_PROFILE_ID`, |
| 97 | +`SHRIKE_PROVIDER_NAME`, `SHRIKE_FAIL_MODE` (`closed` default = deny on enforce |
| 98 | +error; `open` = allow). |
| 99 | + |
| 100 | +## Sandbox, network, and policy permissions |
| 101 | + |
| 102 | +The provider profile (`providers/shrike.yaml`) scopes egress to |
| 103 | +`api.shrikesecurity.com:443` with `enforcement: enforce` and permits `curl` + |
| 104 | +`node` for the hook. The Shrike enforce API itself accepts only the |
| 105 | +`/agent/api/scan/enforce[/specialized]`, `/agent/api/session/status`, and |
| 106 | +`/health` paths. No other network destination is reachable from the sandbox. |
| 107 | + |
| 108 | +## Startup behavior |
| 109 | + |
| 110 | +Governance is active as soon as `install.sh` registers the PreToolUse hook — |
| 111 | +there is no long-running service to start. Every matched tool call is evaluated |
| 112 | +inline before it executes. |
| 113 | + |
| 114 | +## Verification steps and expected results |
| 115 | + |
| 116 | +```bash |
| 117 | +bash scripts/verify.sh |
| 118 | +``` |
| 119 | + |
| 120 | +Drives the installed hook with representative payloads and asserts: |
| 121 | + |
| 122 | +| Action | Expected | |
| 123 | +| --- | --- | |
| 124 | +| Benign shell command (`ls -la`) | **allow** | |
| 125 | +| Destructive command (`rm -rf /`) | **deny** | |
| 126 | +| SQL injection (`... OR 1=1; DROP TABLE`) | **deny** | |
| 127 | +| Prompt injection (ignore-instructions + exfil) | **deny** | |
| 128 | +| Secret exfiltration (key in URL) | **deny** | |
| 129 | + |
| 130 | +`scripts/verify.sh` exits `0` only when every case matches. A full transcript of |
| 131 | +a real run is in [docs/verify-functionality.md](docs/verify-functionality.md). |
| 132 | +Inspect wiring any time with `bash scripts/status.sh`. |
| 133 | + |
| 134 | +## Teardown and cleanup |
| 135 | + |
| 136 | +```bash |
| 137 | +bash scripts/teardown.sh # remove hook + Shrike provider/profile + sandbox |
| 138 | +KEEP_SANDBOX=1 bash scripts/teardown.sh # only un-wire Shrike; keep the sandbox |
| 139 | +``` |
| 140 | + |
| 141 | +Teardown-safe: leaves no service or credential active. |
| 142 | + |
| 143 | +## Known limitations |
| 144 | + |
| 145 | +- The hook governs **matched tool calls**; content the agent never routes |
| 146 | + through a tool is out of scope (that is OpenShell's containment layer's job). |
| 147 | +- Enforce adds a network round-trip per governed action (typically well under a |
| 148 | + second warm). `SHRIKE_FAIL_MODE=open` trades containment for availability if |
| 149 | + the enforce plane is unreachable. |
| 150 | +- Action classification is heuristic by tool/field shape; unusual tool schemas |
| 151 | + fall back to the general enforce path. |
| 152 | + |
| 153 | +## Third-party dependencies and license obligations |
| 154 | + |
| 155 | +No new third-party libraries are added by this recipe. It uses the NemoClaw and |
| 156 | +OpenShell CLIs, `node`, and `curl`, all already present in the runtime. The |
| 157 | +recipe is licensed under Apache-2.0. The Shrike service it calls is operated by |
| 158 | +Shrike Security, Inc. under its own terms (<https://shrikesecurity.com>). |
0 commit comments