Back to Function Hooks

Admin Capability Lockdown

Function Hooks enterprise
Install Command
npx claude-code-templates@latest --function-hook enterprise/admin-capability-lockdown
View on GitHub

Content

JSON
{
"description": "Organization control plugin: withholds the http and process nouns from $ so no p..."
"modules": [
"./admin-capability-lockdown.ts"
]
}
Experimental. Function hooks are an Anthropic proposal under community review (anthropics/claude-code#91870), not a shipped feature. The modules key and every $ API name are provisional.

Module: hooks/admin-capability-lockdown.ts

ts
/**
 * admin-capability-lockdown — Function Hook (EXPERIMENTAL)
 *
 * An organization-level plugin that (1) withholds nouns from $ so no plugin
 * registered beneath it can reach the network or spawn processes, and
 * (2) allowlists which plugins may register at all, and (3) optionally
 * withholds the Bash tool. Only (1) and the "deny" shell policy are real
 * boundaries; the "guardrail" denylist is bypassable by design and is
 * labelled as such.
 *
 * It only works if it is PREPENDED in managed settings: the first plugin in
 * the list returns last from engine.create and sees plugin.register first
 * (design doc §2.3, §4.2, §5).
 *
 * Function hooks are an Anthropic proposal under community review:
 * https://github.com/anthropics/claude-code/issues/91870
 * Every API name below is provisional. The plugin.register event shape and
 * the exact noun names on $ ("http", "process") are assumptions the author
 * has hinted at in the issue thread, not documented API.
 */

type Engine = any;
type Next = ((e: any) => Promise<any>) & { event: string; origin: string; signal: AbortSignal };

export function register(on: any, options: Record<string, any> = {}) {
  const withhold: string[] = options.withhold ?? ["http", "process"];
  const allowedPlugins: string[] | undefined = options.allowedPlugins; // undefined = allow all
  const ownName: string = options.pluginName ?? "admin-capability-lockdown";

  // 1. Shape $ itself. Everything below has already added its nouns when we
  //    get the table back from next(e); we return it minus the withheld ones.
  on("engine.create", async ($: Engine, e: any, next: Next) => {
    const below = await next(e);
    const shaped: Record<string, unknown> = {};
    for (const [noun, api] of Object.entries(below)) {
      if (!withhold.includes(noun)) shaped[noun] = api;
    }
    return shaped;
  });

  // 2. Decide which plugins may exist.
  on("plugin.register", ($: Engine, e: any, next: Next) => {
    if (!allowedPlugins || e.name === ownName || allowedPlugins.includes(e.name)) return next(e);
    $.ui.log(`[admin-capability-lockdown] refused plugin "${e.name}" (not in allowlist)`);
    return { deny: `Plugin "${e.name}" is not on the organization allowlist.` };
  });

  // 3. Shell policy. The real security boundary is step 1 (no $.http / $.process
  //    for plugins below). A Bash denylist can always be bypassed with an
  //    unlisted client, quoting, or a Python one-liner, so this is NOT a
  //    boundary. Two modes:
  //      shellPolicy: "deny"      -> withhold the Bash tool entirely (default,
  //                                  the only mode that actually enforces "no egress")
  //      shellPolicy: "guardrail" -> keep Bash, deny the obvious network clients
  //                                  as a speed bump against accidental egress
  //      shellPolicy: "allow"     -> leave Bash alone
  const shellPolicy: "deny" | "guardrail" | "allow" =
    options.shellPolicy ?? ((options.blockShellNetwork ?? true) ? "deny" : "allow");
  if (shellPolicy === "deny") {
    on("tool.call", { tool: "Bash" }, () => ({
      deny: "The Bash tool is disabled by your organization's admin-capability-lockdown plugin.",
    }));
  } else if (shellPolicy === "guardrail") {
    const NETWORK_CLIENTS = /\b(curl|wget|nc|ncat|netcat|socat|ssh|scp|sftp|rsync|telnet|ftp|openssl\s+s_client)\b/i;
    on("tool.call", { tool: "Bash" }, ($: Engine, e: any, next: Next) => {
      const command: string = e.command ?? "";
      if (NETWORK_CLIENTS.test(command)) {
        return { deny: "Outbound network commands are disabled by your organization's admin-capability-lockdown plugin (guardrail mode: not a hard boundary)." };
      }
      return next(e);
    });
  }
}

Stack Builder

0 components

Your stack is empty

Browse components and click the + button to add them to your stack for easy installation.