Claude Code mods and what they can reach
A Claude Code mod runs TypeScript inside the agent with your credentials in reach. See what it can touch on a VPS and the checks to run before you install one.
What a Claude Code mod is
A Claude Code mod is a plugin that ships function hooks. These are TypeScript functions that run inside Claude Code and wrap its engine events and UI surfaces. Each one controls both the input and the result of the event it wraps. The code runs in the same process as the agent, with the access of your user account. So a mod can reach every file and every network address that Claude Code itself can reach. On a VPS (virtual private server) that usually includes the login credential for your Claude account. This guide covers how a mod differs from the other ways to extend Claude Code. It then covers what security researchers showed a mod can touch, and the checks to run before you install one.
Status as of October 2026: early access
Mods began as a proposal in anthropics/claude-code issue #91870 on 2026-09-03. The proposal put them behind an environment variable, CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1. On 2026-10-01 Anthropic staff announced that the feature was live. The announcement carries an EARLY ACCESS label, which says the surface may change between releases without notice.
That label matters for everything below. Hook names and admin controls may both change. Treat each specific name in this guide as true for the builds the sources tested. Check the release notes for your own version before you depend on one.
To see whether the flag is set on your server, check four places: the version, the current shell, your profile files and any running tmux server.
claude --version
env | grep CLAUDE_CODE_ENABLE_FUNCTION_HOOKS
grep -n CLAUDE_CODE_ENABLE_FUNCTION_HOOKS ~/.bashrc ~/.profile 2>/dev/null
tmux show-environment -g 2>/dev/null | grep CLAUDE_CODE_ENABLE_FUNCTION_HOOKSIf the last three commands print nothing, the flag is not set in those places. They do not check a systemd unit, or a script that sets the variable on its own command line. If Claude Code starts from one of those, check it too.
How a mod differs from hooks, skills, MCP and plugins
Claude Code already had four ways to extend it. A mod is a fifth way, and it sits closer to the engine than any of the others.
- Classic shell hooks. A command listed in
settings.jsonthat Claude Code runs at an event such asPreToolUse. It runs as a separate process, reads the event as JSON and answers with an exit code or JSON. Our guide to classic Claude Code hooks and their exit codes covers the events and how a hook answers. - Skills. Markdown instructions, sometimes with helper scripts, that the model loads into its context when a task matches. A skill is text the model reads. Any command it leads to still passes through the normal tool permission flow.
- MCP servers. An MCP (Model Context Protocol) server is a separate program that offers tools to the model. Each tool call is a request from the model, and Claude Code applies its permission rules to that request.
- Ordinary plugins. A plugin is a package that bundles slash commands, subagents, skills, classic hooks and MCP server configs. The format and the marketplaces are covered in what a Claude Code plugin contains and how to install one.
A mod is a plugin whose package also holds a TypeScript module of function hooks. The difference is where that code runs and what it controls. A classic hook watches an event from outside and returns a verdict. A function hook wraps the event, like middleware in a web framework. It receives the input and decides whether to call the next handler. It can also replace the result before anything else sees it. The issue describes plugins that nest in the order they are registered, so the first one registered wraps all the rest. A hook can also register for a wildcard and see every event.
Mods can also draw UI. Function hooks attach to UI surfaces as well as to engine events, so a mod can render its own content inside the Claude Code interface. A classic Claude Code status line is a script, and Claude Code shows its printed text in one fixed place. A mod draws into the interface itself. The fake-prompt result further down depends on exactly that.
The $ interface: one object for every privileged action
Every privileged action a mod takes goes through one object, called $. Reading a file, running a command, reaching the network and drawing UI are all done through $. The design goal in the issue is tracking. If every side effect passes through one object, Claude Code can record what a mod does, and an admin can wrap that object.
Tracking is not a boundary. vanja.io looked at an engine.create hook that strips nouns such as $.fs from $ before other mods receive it. Their note is direct: stripping $.fs removes that API entry, and it "is not sandboxing". The model's own tools are untouched. Other parts of $ can still reach the filesystem, for example by running a process. Removing $.fs takes away one obvious path to your files and leaves the other paths open.
What pluto.security showed a mod can reach
On 2026-09-22 pluto.security published tests of mods against Claude Code v2.1.274. Four results matter for anyone who runs Claude Code on a server.
It read the Claude credential file. A test mod used its $ interface to read ~/.claude/.credentials.json. That file holds the OAuth credential for the Claude account. File permissions do not help here, because the mod runs as your user inside the Claude Code process. Setting chmod 600 on that file stops other users. It does not stop code that you loaded as yourself.
It reached the network. The same mod sent what it read to a server the researchers controlled. Most VPS firewalls allow all outbound traffic by default (ufw ships with default allow outgoing). So nothing on a typical box stops that request.
It drew UI that imitates Claude Code. A mod showed a prompt styled like Claude Code's own prompts and asked for a credential. A user who types a key into that prompt hands the key to the mod. In the test, nothing on screen showed that the prompt came from a plugin.
Plugin details under-reported it. pluto.security found that the plugin details view can report a mod that hooks everything as having zero hooks. A plugin with one classic hook was listed correctly. So the screen you would use to judge a mod can tell you that the mod does nothing.
Why a mod on a VPS reaches more than you expect
On a laptop, Claude Code shares the machine with your browser and your documents. On a VPS it often shares the machine with everything you deploy. A typical agent box holds the Claude login, a git deploy key in ~/.ssh, .env files with database passwords, and cloud CLI credentials. The agent often runs for days inside tmux. A mod loaded at session start stays loaded for as long as that session lives.
A mod can reach all of that, because it has the access of the user that started claude. The controls that work are the ones that limit that user. Run Claude Code as a dedicated account that owns only the project it works on, as described in running Claude Code safely on a VPS. Keep long-lived secrets out of that account's reach. The guide on keeping secrets out of AI coding agents covers this step by step. To try a plugin you do not trust yet, use a machine you can delete afterwards, as in running coding agents in a disposable VM.
A checklist before you install a Claude Code mod
pluto.security's main advice is to treat a mod as a program that you run. Each step below follows from that.
- Read the module source, not the listing. The plugin details view can under-report hooks, so open the TypeScript files yourself. Note which events the mod hooks, whether it registers a wildcard, and which parts of
$it uses. A status-line mod that hooks every event needs a good reason. - Pin the version you read. A plugin that follows a branch can change after you install it. Record the exact commit you reviewed. If you install from a marketplace you control, point its entry at that commit and not at a branch name. Read the diff before each update.
- Distrust mods that fetch remote code at runtime. A mod that downloads code and runs it can turn malicious after your review, because the code you read is not the code that runs. Reject any mod that fetches a URL and then evaluates or imports the response.
- Search the installed files for network calls and generated code. Plugins install under
~/.claude/plugins/. The search below lists every line that names a URL or builds code at runtime. - Treat any credential prompt inside a session as hostile. If a prompt inside Claude Code asks you to paste an API key or a password, do not type it. Exit the session. Start a new one, open
/pluginand review what is installed.
The search for step 4:
grep -rnE 'https?://|eval\(|new Function|import\(' ~/.claude/plugins/Each hit is a line to read, not proof of harm. A mod that names a URL may only link to its own documentation. A mod that builds code from a string it downloaded is the case to reject.
Admin levers: what the sources name
If you run Claude Code for a team, the sources name a short list of controls. Do not read more into them than the sources say.
disableAllHooksis a managed setting. pluto.security names it as the switch that blocks all hooks across the organisation.allowManagedHooksOnlyis a managed setting that runs only the hooks an admin installed. It blocks hooks from user-installed plugins.sec-defaultis a built-in mod. vanja.io describes it as keeping an organisation's classic hooks, prompt content, managed settings and tool policy isolated from user-installed plugins. It "adds no policy of its own", so enabling it does not block anything by itself.
On Linux, managed settings live in /etc/claude-code/managed-settings.json. Settings in that file take precedence over user and project settings. The file is owned by root, so a normal user cannot edit it. A minimal file that allows only admin-installed hooks looks like this:
{
"allowManagedHooksOnly": true
}Use "disableAllHooks": true instead if you want no hooks at all. Remember the EARLY ACCESS label. Before you rely on these settings for a team, check the documentation for your version to confirm they cover function hooks.
When a mod is the right tool
The reach that makes mods risky also makes them useful. A mod can enforce a policy at the engine, before a tool call happens, instead of asking the model to follow a rule. It can add a live pane to the interface, which a shell script cannot draw. An admin can register a mod first so that it wraps every user plugin.
Most changes do not need that reach. If you want the agent to follow a procedure, writing your own agent skill does that with text the model reads, and no new code runs as your user. If you want a check before each tool call, a classic hook works. It is a separate process with a short, documented contract. Choose a mod when the job needs to control an event's input or result. Then apply the checklist above to your own mod, as you would to anyone else's.
FAQ
What is the difference between a Claude Code mod and a plugin?
A plugin is a package format. It can bundle slash commands, subagents, skills, classic shell hooks and MCP server configs. A mod is a plugin that also ships function hooks. These are TypeScript functions that run inside the Claude Code process and wrap engine events and UI surfaces. They control both the input and the result of those events. Every mod is a plugin, but most plugins are not mods.
Can a Claude Code mod read my Claude login credentials?
Yes. pluto.security tested Claude Code v2.1.274 on 2026-09-22. In that test, a mod read ~/.claude/.credentials.json through its $ interface and sent data to an outside server. File permissions do not prevent this, because the mod runs as the same user as Claude Code. Limit what that user can read, and read a mod's source before you install it.
Does removing $.fs from a mod sandbox it?
No. An engine.create hook can strip nouns such as $.fs from the $ interface. vanja.io points out that this "is not sandboxing". It removes one API entry. The model's own tools still work. Other parts of the interface can still reach the filesystem, for example by running a process.
How do I stop users on a shared server from loading mods?
The sources name two managed settings. allowManagedHooksOnly runs only the hooks an admin installed and blocks hooks from user-installed plugins. disableAllHooks blocks hooks entirely. On Linux both go in /etc/claude-code/managed-settings.json. The built-in sec-default mod keeps organisation settings isolated from user plugins, but it adds no policy of its own. The feature is in early access, so check that these settings cover function hooks in your version.
Are Claude Code mods stable enough to depend on?
Not yet. Mods were proposed on 2026-09-03 in anthropics/claude-code issue #91870, behind the CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 flag. Anthropic staff announced them as live on 2026-10-01 under an EARLY ACCESS label. That label says the surface may change between releases without notice. Expect hook names and the $ interface to change. Pin any mod you use to a version you have read.