Safeguard
Supply Chain Security•

When an Agent Writes and Installs Its Own Tools: The Supply Chain Risk

A self-extending agent installs packages and writes skills, scripts, cron jobs and MCP configs. Treat each as a supply chain artifact: pin, review, sign.

Safeguard Security Team
47 min read

A self-extending agent adds to its own toolset while it works: it installs packages, writes scripts and skills, schedules jobs and wires in MCP servers. Later sessions, and often other people, run all of it. Treat each addition as a supply chain artifact: pin installs, review what the agent writes, keep it in signed version control and inventory it.

That is the short answer. The rest of this post works through it with one concrete, well documented example, Nous Research's open source Hermes Agent, whose docs describe in unusual detail what the agent is allowed to write and where it puts it. We checked those docs and the repository on 23 October 2026, when the latest release was v0.22.5 (published 23 October 2026 on GitHub). Hermes ships several releases a week, so check the current docs before you copy a setting.

Key takeaways

  • A self-extending agent produces five kinds of durable artifact during ordinary work: installed packages, scripts, skill files, configuration entries (MCP servers, plugins, hooks) and scheduled jobs. Each one outlives the session that created it.
  • In Hermes Agent, skill writes by the agent are on by default and unreviewed by default: skills.write_approval defaults to false and the skills.guard_agent_created content scanner defaults to false (Hermes configuration docs, checked 23 October 2026). Both can be switched on.
  • An agent-authored skill is a supply chain artifact because it is executable instruction plus optional code, it loads into future sessions automatically, and it can be published, shared through a common directory or vendored into a repository.
  • Agent package installs fail in four familiar ways: unpinned versions, hallucinated package names, on-demand "lazy" installs, and transitive drift. A USENIX Security 2025 study measured hallucinated package names at an average of at least 5.2% for commercial models and 21.7% for open source models across 576,000 generated code samples.
  • The controls are not new. Lockfiles, hash pinning, a curated package source, staged review with an owner, signed history and an SBOM all apply. What changes is that you have to point them at the agent's home directory and not only at your application repository.
  • NIST SP 800-218 (the SSDF) already covers most of this through PO.5.1, PS.1.1, PS.3.2, PW.4.1, PW.4.4 and PW.7.1. SP 800-218A adds AI model development practices but does not specifically address code written by an agent at runtime.

What "self-extending" means, and what it does not

The phrase covers a narrow, practical behaviour. A self-extending agent changes the set of things it can do next time by writing to disk or to configuration, not by changing its model weights. Hermes Agent's README calls its version of this a learning loop: agent-curated memory, autonomous skill creation after complex tasks, and skills that improve during use. Nous Research describes Hermes Agent on its releases page as an agent that "remembers what it learns, and gets more capable the longer it runs."

None of that is recursive self-improvement in the research sense. Hermes does not train the model it runs on. What grows is a directory of procedures, scripts, configuration and installed software, which you can diff, version, sign and roll back. That is why this is a supply chain problem: the risk lives in files that execute.

Third-party skill marketplaces are a related but different risk, and we have covered them separately in agent skill marketplaces as the next frontier for supply chain attacks and vetting third-party agent skill marketplaces. This post is about artifacts the agent authors or pulls in itself, during a task, on your machine.

What a self-extending agent adds to your environment

The fastest way to see the risk is to list everything an agent can leave behind after one long session. For Hermes Agent, the docs are specific. The table below maps each artifact to where it lands, who or what can create it, and the default gate, as documented on 23 October 2026.

ArtifactWhere it lands (Hermes docs)Created byDefault gate
Python or Node packages installed by a commandThe active environment, a project's virtual environment or node_modulesThe agent through the terminal tool or an execute_code scriptDangerous-command approval (approvals.mode: smart by default); skipped entirely on container backends
Optional Hermes extras ("lazy installs")Writable storage outside the signed base artifactHermes itself when a backend requests a missing extrasecurity.allow_lazy_installs; limited to declared extra names, tool archives pinned by SHA-256 in pm/lock.json
Skills (SKILL.md plus scripts/, references/, templates/, assets/)~/.hermes/skills/, or skills.create_dir if setThe agent via skill_manage, the background review after a turn, the curator's consolidation pass, /learnskills.write_approval: false by default (writes land immediately)
Edits to existing skills, including shared onesWherever the skill lives, including skills.external_dirsThe same pathsSame; the docs warn external directories "are not a write-protection boundary"
Memory entries~/.hermes/memories/MEMORY.md and USER.mdThe agent and the background reviewContent scanning on write; memory.write_approval optional
Scheduled jobs~/.hermes/cron/jobs.json, scripts under HERMES_HOME/scriptsThe agent via the cronjob_manage tool when you ask in plain languageScheduled runs cannot create jobs unless cron.allow_agent_scheduling: true
MCP server entriesmcp_servers in ~/.hermes/config.yamlYou, the catalog installer, or a file write by the agent (the docs list config.yaml as read-denied but writable)Catalog manifests are PR-reviewed in the Hermes repo; bootstrap commands still run on install
Plugins~/.hermes/plugins/ or pip entry pointshermes plugins installOff until named in plugins.enabled; install prompt defaults to No
Gateway event hooks~/.hermes/hooks/<name>/ (HOOK.yaml plus handler.py)Anyone or anything that can write the directoryNone: "trusted by placement", imported in-process at gateway start

Three entries in that table deserve a second look.

Skills are written freely by default. The Hermes skills page says it plainly: "By default the agent writes skills freely, including from the background self-improvement review that runs after a turn." The system prompt asks the agent to save a skill when it has worked out a multi-step workflow, when it hit errors and found the working path, and when a user corrected its approach. That is exactly when you would want to capture knowledge, and it is also exactly when an agent may have just read a web page, an issue thread or a log file that you did not write.

Configuration is writable. The Hermes file-write safety layer hard-blocks writes to credential stores such as ~/.ssh/, ~/.aws/ and the Hermes .env, but its own table notes that control files such as config.yaml "are read-denied but stay writable." A stdio MCP server entry in that file is a command line that Hermes will start. That is ordinary for a configuration file, and it means the configuration file belongs in your review scope.

Hooks are trusted by placement. The security docs describe gateway event hooks as a deliberate exception to the opt-in model: any subdirectory of ~/.hermes/hooks/ with a valid HOOK.yaml and handler.py is imported by the gateway at startup "with the gateway's own privileges," and HERMES_SAFE_MODE does not skip it. The docs explain the reasoning (anyone who can write the profile home can already run code through config.yaml) and give the advice that matters: review a handler.py before you place it and include ls ~/.hermes/hooks/ in every audit, because the directory "is not on the protected-paths denylist."

None of this is a flaw in Hermes. The same categories appear, under different names, in any agent framework that can run commands and save procedures; Hermes is a useful example because its docs spell them out.

A worked inventory of one session

To make the table concrete, imagine a common request on a developer laptop: "Write me a script that pulls last week's failed CI runs from our repo and posts a summary to the team channel every Monday." A capable agent working through that task could plausibly leave behind:

  1. A new package installed into a virtual environment, for example an HTTP client or a chat platform SDK, at whatever version the index served that minute.
  2. A Python script in the project or under the Hermes scripts directory.
  3. A skill describing the procedure, with the script copied into its scripts/ folder so the next session can reuse it.
  4. A cron job that runs the script every Monday, possibly in no-agent mode, where the docs say the scheduler "runs your script on schedule and delivers its stdout directly, skipping the agent entirely."
  5. A memory entry recording which channel and repository you prefer.

Five artifacts, one request, and only the first passed a command approval check. If your team shares the skills directory, item three is now available to everyone.

Why an agent-authored skill is a supply chain artifact

A supply chain artifact, in the sense SLSA and the SSDF use, is something produced in one place and consumed in another, where the consumer trusts it without rebuilding it from scratch. An agent skill fits that definition on three counts.

It is executable. The agentskills.io specification, which Hermes follows, defines a skill as a directory with a required SKILL.md and optional folders, including scripts/, which the spec labels "executable code." Even the Markdown part is executable in a practical sense: it is a set of instructions that an agent with shell access will follow. The spec also defines an experimental allowed-tools field, "a space-separated string of tools that are pre-approved to run," and notes that support varies between implementations. A skill that carries pre-approval hints is closer to a permissions manifest than to documentation. Our earlier post on whether an agent skill file can give shell access covers that mechanism in depth.

It is consumed automatically. Hermes uses progressive disclosure: skill names and descriptions sit in an index, and the full skill loads when the agent decides it is relevant. Nobody has to choose to run it. A skill written on Tuesday can shape a cron job's behaviour on Wednesday morning with no human in the loop. The Hermes docs note that cron jobs inherit your interactive trust decisions for project skills and "never prompt and never auto-trust," which is a sensible rule, but it also means a skill that is already trusted runs unattended.

It travels. A skill is designed to be reused. In Hermes, skills can move through at least five routes:

  • skills.create_dir, which the docs suggest for "a shared brain directory, a git-tracked repo, or a fleet-wide skills volume."
  • skills.external_dirs, for directories shared with other tools, which the agent can still modify if the process has write permission.
  • Project skills under <project-root>/.hermes/skills/, which travel with a repository and load after hermes skills trust.
  • hermes skills publish to a GitHub repository, and hermes skills tap add to subscribe to one.
  • Profiles: one person may run several Hermes profiles, and a skill copied between them carries whatever it learned in the first.

So an agent-written skill has an author (a model plus whatever it read), a build step (the session), a distribution channel (a shared directory or repo) and consumers (later sessions, other users, scheduled jobs). That is a supply chain in miniature, and it deserves the same controls: provenance, review, integrity and inventory.

What makes it different from human-written code

Human-written code usually passes through a pull request. Agent-written skills, by default, do not. They also have two properties that human code rarely has:

  • The author may have been steered. An agent that just summarised a hostile web page or an issue comment can carry that content into a skill it writes minutes later. That is indirect prompt injection turning into persistence. We cover the mechanism conceptually in AI agent memory poisoning and memory hardening; the point here is that the result is a file on disk, and file controls apply.
  • The author optimises for "worked this time." The Hermes docs ask skills to capture "lessons, not logs," which is good guidance. But the lesson an agent draws from a failing install can be "add --break-system-packages" or "pin to the version that happened to resolve," and those lessons then repeat across every future session.

How agent package installs go wrong

Package installs are where self-extension meets the public registries. The failure modes are the same ones human developers hit, but an agent hits them faster, more often and usually without anyone watching the terminal.

Unpinned versions

When an agent runs pip install requests or npm install axios, it gets whatever version the index serves at that moment. If the script it then writes into a skill does not record the version, the next session that follows the skill installs whatever is current then. You have reproducibility only by accident. The SSDF's PS.3.2 asks producers to "collect, safeguard, maintain, and share provenance data for all components of each software release," and an unpinned install inside a skill makes that impossible for the skill.

Hallucinated package names

Code-generating models sometimes recommend packages that do not exist. The most thorough measurement we know of is Spracklen and co-authors, "We Have a Package for You! A Comprehensive Analysis of Package Hallucinations by Code Generating LLMs" (arXiv 2406.10279, first version 12 June 2024, published at the 2025 USENIX Security Symposium). In the authors' own terms:

  • They tested 16 popular code-generation models with two prompt datasets and generated 576,000 code samples in Python and JavaScript.
  • The average share of hallucinated packages was "at least 5.2% for commercial models and 21.7% for open-source models."
  • They recorded 205,474 unique hallucinated package names.
  • They implemented mitigation strategies that "significantly reduce the number of package hallucinations while maintaining code quality."

What the paper measured is recommendations in generated code, not installs by agents in the wild. It does not tell you how often a live agent will run pip install on a hallucinated name, and the models it tested are older than the ones most agents run today. What it establishes is that the failure is systematic enough to plan for. A registry name that a model invents can be registered by someone else, which is the attack known as slopsquatting. We have a dedicated practical slopsquatting control set and an explainer on how slopsquatting exploits hallucinated package names, so we will not repeat them. The controls below close the door either way: if the agent can only install from a curated source, an invented name fails to resolve.

Lazy and on-demand installs

Many agent frameworks install optional dependencies the first time a feature needs them. Hermes documents its approach carefully. When a backend requests an unavailable extra, the package manager checks security.allow_lazy_installs, prepares a complete environment, validates it, and only then switches over. The helper "accepts project extra names, not arbitrary pip commands," and managed tool archives "have versions and SHA-256 hashes in pm/lock.json." The official Docker image disables on-demand installs.

That is a careful design, and the docs are also candid about its limit: "Plugin dependencies share the complete environment; they are not isolated Python sandboxes. Compatible transitive dependencies can change, but declared constraints and exact pins remain binding." In other words, enabling a plugin can change the versions of packages that the core agent and your other plugins use. If you need a fixed environment, turn lazy installs off with hermes config set security.allow_lazy_installs false and treat every dependency change as a reviewed event.

Transitive drift and install scripts

Even a pinned top-level package pulls in a tree. Without a lockfile, the tree changes under you. Without hash checking, you trust that the bytes you got today match the bytes you reviewed last week. And on npm, install lifecycle scripts run by default: the npm config docs list ignore-scripts with "Default: false," and when it is true "npm does not run scripts specified in package.json files." An agent that installs a package in a project where scripts are enabled has run that package's code, before any test or review.

A wrong or unexpected index

Agents often run inside environments with several package sources configured: a corporate mirror, the public index, a local cache. If the agent adds --extra-index-url to get past a resolution error, it has widened the set of sources a name can resolve from. The OpenSSF S2C2F lists "dependency confusion, package substitution attacks" as a threat, mitigated by ENF-1 (securely configure package source files such as .npmrc and pip.conf) and ENF-2 (enforce a curated feed).

How to constrain agent package installs

The goal is simple to state: the agent may install packages, but only from a source you control, only at versions you can reproduce, and only with integrity you can verify. The tools to do that already exist in every package manager.

Lockfiles and frozen installs

For Node projects, npm ci is the frozen install. The npm docs list its properties: the project "must have an existing package-lock.json or npm-shrinkwrap.json"; if the lock and package.json disagree, "npm ci will exit with an error, instead of updating the package lock"; and "it will never write to package.json or any of the package-locks." If your agent's scripts and skills say npm ci and not npm install, a session cannot silently add or upgrade a dependency while running a known procedure.

For Python, pip's secure installs page recommends two flags together: --require-hashes to enable hash-checking mode and --only-binary :all: to refuse source distributions. Hash checking "is an all-or-nothing proposition": once any requirement has a --hash, every requirement must have one. A requirements file generated with hashes turns "install what the skill says" into "install exactly these bytes."

A curated package source

Point the agent's environment at one internal mirror or curated feed and nothing else. The S2C2F frames this as a maturity path: ING-2 (use a repository manager that caches artifacts) at level 1, ENF-1 (configure package sources securely) at level 2, ENF-2 (enforce a curated feed with allow or deny lists) at level 3. For an agent, the curated feed is the single most effective control against hallucinated names, because a name that is not in the feed cannot be installed no matter what the model writes.

Install allowlists and deny rules

Hermes lets you add approvals.deny, a list of glob patterns that block matching terminal commands "before --yolo, /yolo, and approvals.mode: off are consulted." You can use it to block install forms you never want, such as an extra index URL or a pipe from a download to a shell. Two cautions from the docs apply. First, container backends skip dangerous-command checks entirely because "the container itself is the security boundary," so inside Docker your package source configuration has to do the work. Second, an execute_code script "can call subprocess, os or shutil directly, and those calls never pass through the patterns." Deny rules are a useful floor, not a package policy.

Which control for which situation

SituationPrimary controlWhyWhat it does not cover
Agent works in an existing project with a lockfileFrozen installs (npm ci, pip install --require-hashes -r requirements.txt) in skills and scriptsProcedures cannot change the dependency treeA session that deliberately runs a plain install outside the procedure
Agent needs new packages often (prototyping)Curated mirror as the only configured source, plus a sandboxed backendInvented or unvetted names fail to resolve; damage stays in the containerVulnerabilities in packages that are in the mirror
Agent runs unattended (cron, webhooks)Lazy installs off, approvals.cron_mode: deny, no network installs at run timeNobody is watching; nothing new should arriveScripts that were already approved with a bad dependency
Agent writes skills that others will reusePinned, hashed requirements stored inside the skill, reviewed with the skillThe skill carries its own reproducible environmentDrift in the base image or interpreter
Agent extends itself with plugins or MCP serversInstall by pinned commit (hermes plugins install owner/repo --ref <sha>), read the manifest, keep plugins.enabled shortThird-party code runs only after a deliberate decisionUpdates you apply later without review

How to review agent-written skills and scripts

Pinning controls what comes in from outside. Review controls what the agent writes itself. The pattern that works is the same one you already use for code: stage, diff, assign an owner, test, then merge.

Stage every write

In Hermes, the switch is one line:

skills:
  write_approval: true

With it on, "every skill_manage write (create / edit / patch / delete / write_file / remove_file) is staged instead of committed," whether it came from a foreground turn or the background review. Staged writes survive restarts under ~/.hermes/pending/skills/. You review them with /skills pending, /skills diff <id>, /skills approve <id> and /skills reject <id>. Because /learn writes through skill_manage, the same gate covers skills built from documents and URLs.

The Hermes docs are careful to separate this from the content scanner. skills.guard_agent_created is "a content scanner (dangerous-pattern heuristics), not an approval gate," and it is off by default because legitimate workflows that mention ~/.ssh/ or an API key variable "were tripping the heuristic too often." Turn on both. The scanner catches the obvious; the approval gate makes sure a person reads the rest.

Read the diff like code review, because it is

A skill diff needs the same questions as any pull request:

  • Does the procedure install anything? If so, is it pinned and hashed, and from which source?
  • Does scripts/ contain anything that talks to the network, writes outside the project, or reads credentials?
  • Does the skill tell the agent to change approvals, enable plugins, add MCP servers or create scheduled jobs?
  • Does it carry an allowed-tools field, and does the list make sense for the task?
  • Is any instruction phrased as if it came from you, but you do not remember saying it? That is the signature of content the agent read somewhere and promoted into a procedure.

Give skills owners and tests

A shared skill without an owner is an orphaned dependency. Put shared skill directories in a git repository, add a CODEOWNERS file, and require review from an owner for changes. For skills with scripts, add a small test that runs the script against a fixture in CI. The agentskills.io spec asks that scripts "be self-contained or clearly document dependencies," which gives you a natural check: a script that imports something not declared in the skill's requirements fails the build.

How one bad skill spreads, and the boundaries that stop it

The risk with shared skills is not that one is bad. It is that a bad one becomes everyone's. Here are the spread paths for Hermes, and the boundary that holds for each.

Spread pathHow a bad skill movesBoundary that stops it
Shared create_dir volumeEvery agent that writes there publishes to every agent that reads thereMake the shared directory a git repository with protected branches; agents write to a staging branch only
external_dirsThe agent can patch a skill in a directory other tools also useFilesystem permissions: mount shared directories read-only for the agent process, as the docs advise
Project skills in a repoA skill committed to a repo loads for everyone who trusts that repohermes skills trust per repo; scan-time quarantine; code review on .hermes/skills/ in the repo
Name shadowingA project skill named like a profile skill wins inside that repo, because precedence is project, then local, then create_dir, then external_dirsWatch the "shadowed" log line; reserve names for critical skills; review new project skills by name
Publishing and tapshermes skills publish pushes to GitHub; another team taps itTaps get community trust by default and go through the hub security scan; publish only from reviewed branches
ProfilesA skill copied between your own profiles carries what it learnedCopy through git, not by hand, so the change has a diff and an author
CronA trusted skill runs unattended on schedulecron.allow_agent_scheduling: false (the default), approvals.cron_mode: deny, and a review of hermes cron list

Two details from the Hermes docs are worth knowing. First, project skills are re-scanned whenever their content changes: "Trust is a repo-level decision, but a repo's skill content changes with every git pull," so a dangerous verdict quarantines the skill even in a trusted repo, and scans are cached "under ~/.hermes/cache/project_skill_scans/ (never inside your repo)." Second, hub installs record the "source URL, exact content hash, scanner version, findings, timestamp, and fresh-or-cached status in skills/.hub/lock.json." That lock file is the closest thing Hermes has to provenance for third-party skills. Agent-authored skills have no equivalent record by default, which is the gap that git and signing close.

Hermes also assigns trust levels to skill sources (builtin, official, trusted and community). Agent-authored skills sit outside that scheme altogether, because they are not installed from a source. They are simply written.

What the SSDF asks for that applies here

NIST SP 800-218, the Secure Software Development Framework version 1.1 (published February 2022), is written for software producers. A team that runs a self-extending agent is a producer, because the agent produces software that the team then runs. The mapping is direct.

SSDF task (SP 800-218)What it says (paraphrased from the task text)What it means for a self-extending agent
PO.5.1Separate and protect each environment involved in software developmentRun the agent on a sandboxed backend, not on the host where your credentials live
PS.1.1Store all forms of code, including configuration-as-code, with least-privilege accessKeep skills, scripts, config.yaml, cron definitions and hooks in version control with restricted write access
PS.2.1Make software integrity verification information availableSign skill bundles you share; publish hashes for scripts other teams consume
PS.3.2Collect, safeguard, maintain and share provenance data for all components of each release, for example in an SBOMRecord what each skill installs; generate an SBOM for the agent's environment and for shared skill repos
PW.4.1Acquire and maintain well-secured third-party componentsInstall only from a curated source; prefer maintained packages
PW.4.4Verify that acquired components comply with your requirements throughout their life cyclesRe-check agent-installed packages for known vulnerabilities on a schedule, not only at install time
PW.7.1Decide whether code review or code analysis should be used, as defined by the organisationDecide, in writing, that agent-written skills and scripts get the same review as human code

NIST SP 800-218A (July 2024) is the SSDF Community Profile for generative AI and dual-use foundation models. It adds practices for "AI model development throughout the software development life cycle": protecting training data and model weights, tracking "the provenance of an AI model and its components and derivatives," and verifying the integrity and provenance of acquired models. Those matter if you fine-tune or host models. What 800-218A does not do is address code that an agent writes at runtime on a user's machine; it is a profile for producers of AI models and AI systems. For agent-written skills and scripts, the base SSDF tasks above are the ones to apply. Our earlier post asks whether SP 800-218A covers AI-written code in more detail.

Two other frameworks fill in specifics:

  • OWASP Top 10 for LLM Applications 2025. LLM03 (Supply Chain) recommends maintaining "an up-to-date inventory of components using a Software Bill of Materials (SBOM) to ensure you have an up-to-date, accurate, and signed inventory." LLM06 (Excessive Agency) recommends that teams "minimize extensions," "minimize extension functionality" and "avoid open-ended extensions where possible (e.g., run a shell command, fetch a URL, etc.)." A self-extending agent is, almost by definition, one that keeps adding extensions, which is why LLM06 and LLM03 have to be read together.
  • SLSA. The SLSA v1.2 build track defines Build L1 as "provenance showing how the package was built," Build L2 as "signed provenance, generated by a hosted build platform," and Build L3 as a hardened build platform that resists tampering during the build. An agent session is not a hosted build platform, so agent-authored skills start at L0. Moving the "build" of a shared skill into CI, where a reviewed commit produces a signed bundle, is how you reach L1 and L2 for the things other people consume.

Threat and control map

This table pulls the threads together. Each row is a way a self-extending agent introduces risk through artifacts, the Hermes control that addresses it (from the docs, checked 23 October 2026), and the general control that works for any agent.

ThreatHermes control (docs)General controlFramework reference
Agent installs an unpinned or hallucinated packageCommand approvals (smart by default); approvals.deny patternsCurated package source; frozen installs; hash pinningS2C2F ENF-1, ENF-2; SSDF PW.4.1
On-demand extras change the environmentsecurity.allow_lazy_installs; extras limited to declared names; SHA-256 pinned tool archivesTurn off on-demand installs in production profiles; rebuild images insteadSSDF PS.3.2
Agent writes or edits a skill that carries harmful instructions or scriptsskills.write_approval; skills.guard_agent_created; advisory linterStaged review, owner, tests, signed git historySSDF PW.7.1, PS.1.1; OWASP LLM03
A shared skill directory is modified by one agent and loaded by manyDocs warn external_dirs is not a write boundary; precedence rules; shadow warningsRead-only mounts; git with protected branches; CODEOWNERSSSDF PS.1.1
A repo ships a project skill that runs for everyone who opens ithermes skills trust per repo; scan-time quarantineCode review on the repo's skill folderSSDF PW.7.1
Agent schedules recurring executioncronjob_manage only on request; cron.allow_agent_scheduling: false; approvals.cron_mode: denyInventory scheduled jobs; alert on new onesOWASP LLM06
Agent adds an MCP server or pluginPlugins off until in plugins.enabled; catalog manifests reviewed; MCP tool include filters; filtered environment for MCP subprocessesPin by commit; review manifests; keep config.yaml in gitOWASP LLM06; SSDF PW.4.4
Code dropped into the hooks directory runs at gateway startNone by design ("trusted by placement"); docs advise review and auditFile integrity monitoring on the profile homeSSDF PS.1.1
A known-compromised Python package is present in the agent's own environmentBuilt-in supply-chain advisory check at startup and in hermes doctorSBOM of the agent environment; vulnerability matching on a scheduleSSDF PW.4.4; S2C2F INV-1, SCA-1
Host damage from agent commandsHardline blocklist; file-write denylist; Docker backend with dropped capabilitiesSandboxed execution; separate credentialsSSDF PO.5.1

One honest note on the advisory check. Hermes describes it as a built-in scanner that flags Python packages "in the active venv that match a curated catalog of known-compromised versions," shown on a startup banner and in hermes doctor. It is a useful safety net for the agent's own environment. It is not a scan of the projects the agent works on, and it only knows what is in its catalog.

A step by step control set for a team running a self-improving agent

The steps below assume Hermes Agent on Linux or macOS, a team that wants to keep the agent's learning loop on, and a shared skills repository. The commands are standard tools; the Hermes keys are taken from its docs on 23 October 2026. Adapt the paths to your setup.

Step 1: Back up the profile home before you change anything

Several later steps change agent state. Take a dated backup first, and confirm it is readable.

# Back up the whole Hermes profile home (skills, memories, config, cron, hooks)
STAMP=$(date +%Y%m%d-%H%M%S)
tar -czf "$HOME/hermes-backup-$STAMP.tar.gz" -C "$HOME" .hermes
tar -tzf "$HOME/hermes-backup-$STAMP.tar.gz" | head

Step 2: Take an inventory of everything the agent has added

Before you set policy, find out what is already there. This is read-only.

hermes --version
hermes skills list                 # every skill the agent can load
hermes skills list --source hub    # hub-installed skills only
hermes skills audit                # re-scan hub-installed skills
hermes cron list                   # scheduled jobs, including agent-created ones
hermes plugins                     # discovered plugins and whether they are enabled
ls -la ~/.hermes/hooks/            # trusted-by-placement gateway hooks
hermes doctor                      # includes the supply-chain advisory check

Then look for skills written locally. Bundled skills are tracked in ~/.hermes/skills/.bundled_manifest and hub skills in ~/.hermes/skills/.hub/lock.json; a skill in neither list was written on this machine, by you or by the agent. The first command below is a rough first pass: it lists SKILL.md files changed since the last bundled sync, which you then check against the two lists.

find ~/.hermes/skills -name SKILL.md -newer ~/.hermes/skills/.bundled_manifest -print
find ~/.hermes/skills -path '*/scripts/*' -type f -print

Step 3: Put skills and configuration under version control

Make ~/.hermes/skills a git repository so every change, by you or the agent, has a diff, an author and a timestamp. Use signed commits for the changes you approve.

cd ~/.hermes/skills
git init
printf '.hub/quarantine/\n' > .gitignore
git add -A
git commit -S -m "Baseline: skills as of $(date +%F)"

For a team, use a shared repository as the agent's create_dir and keep personal profiles pulling from it:

git clone git@github.com:your-org/agent-skills.git ~/agent-skills

Keep config.yaml in a separate private repository or a configuration management system, never with secrets. The Hermes .env and credential files stay out of git entirely.

Step 4: Turn on staging, scanning and the other gates

Add these keys to ~/.hermes/config.yaml. Each one is documented in the Hermes configuration, skills, cron or security pages.

skills:
  write_approval: true          # stage every skill write for review (default: false)
  guard_agent_created: true     # dangerous-pattern scanner on agent skill writes (default: false)
  create_dir: ~/agent-skills    # new agent skills land in the git-tracked team repo
  project_discovery: true       # keep project skill discovery, which requires explicit trust

memory:
  write_approval: true          # stage memory writes from the background review

approvals:
  mode: manual                  # prompt for every flagged command (default: smart)
  cron_mode: deny
  single_query_mode: deny
  unattended_mode: deny
  deny:
    - "*--extra-index-url*"
    - "*--index-url*"
    - "*--break-system-packages*"
    - "*curl*|*sh*"

cron:
  allow_agent_scheduling: false # scheduled runs cannot create or edit jobs (default)

security:
  allow_lazy_installs: false    # no on-demand extras; rebuild instead

checkpoints:
  enabled: true                 # snapshots before destructive file operations

The deny patterns are case-insensitive globs matched against the whole command, as the Hermes work-machine guide describes. They are a floor, not a fence: as noted above, execute_code scripts can bypass terminal patterns, and container backends skip these checks. That is why the next two steps matter more.

Step 5: Move execution into a container and keep secrets out

terminal:
  backend: docker
  docker_image: "nousresearch/hermes-sandbox:desktop"
  docker_forward_env: []        # explicit allowlist only; empty keeps secrets out

The Hermes docs describe the Docker backend as running with all Linux capabilities dropped except a minimal set, no-new-privileges, a process limit and size-limited tmpfs mounts. The official image also sets HERMES_WRITE_SAFE_ROOT=/opt/data, which hard-blocks write_file and patch outside that prefix. If you run on the local backend instead, set the safe root yourself and include the Hermes home as a second root, as the docs advise:

export HERMES_WRITE_SAFE_ROOT=/path/to/project:$HOME/.hermes

For network egress from the sandbox, see default-deny egress for an agent sandbox, and for credentials, the credential proxy pattern.

Step 6: Constrain package sources and pin what skills install

Inside the sandbox image (or the agent's environment), point pip and npm at your curated source only, and turn off npm lifecycle scripts by default.

# /etc/pip.conf in the sandbox image
[global]
index-url = https://packages.internal.example.com/pypi/simple
require-hashes = true
only-binary = :all:
# .npmrc in the sandbox image or project
registry=https://packages.internal.example.com/npm/
ignore-scripts=true

For any skill that installs Python packages, store a hashed requirements file inside the skill and install from it. With pip-tools:

cd ~/agent-skills/devops/ci-weekly-summary
pip-compile --generate-hashes --output-file=scripts/requirements.txt scripts/requirements.in
pip install --require-hashes --only-binary :all: -r scripts/requirements.txt

For Node scripts in a skill, commit package-lock.json and use the frozen install:

cd ~/agent-skills/devops/ci-weekly-summary/scripts
npm ci --ignore-scripts

Then make it a rule inside the skill itself, in its Procedure section, that the agent installs only with these commands. A skill that says "install the dependencies with npm ci" is easier to review than one that lets the agent decide.

Step 7: Review staged writes like pull requests

When the agent proposes a skill or memory change, review it in the CLI where diffs are not truncated:

/skills pending
/skills diff <id>
/skills approve <id>
/skills reject <id>

After you approve a change that landed in the git-tracked directory, commit it with a signed commit that names the source session, then open a pull request for the shared repository so a second person reviews it:

cd ~/agent-skills
git checkout -b skill/ci-weekly-summary
git add devops/ci-weekly-summary
git commit -S -m "Add ci-weekly-summary skill (agent-authored, reviewed by $(git config user.name))"
git push -u origin skill/ci-weekly-summary

Our post on labelling AI-assisted commits covers trailers that make agent authorship visible in history.

Step 8: Gate the shared repository in CI

Protect the main branch of the shared skills repository, require review from code owners, and run checks on every pull request. A minimal CODEOWNERS:

# .github/CODEOWNERS
*            @your-org/platform-security
/devops/     @your-org/platform-team

A minimal GitHub Actions workflow that fails a pull request when a skill script installs from an unpinned requirements file, runs the skill tests, and produces an SBOM for the repository:

name: skill-review
on: [pull_request]
permissions:
  contents: read
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Every Python requirements file must be fully hashed
        run: |
          for f in $(git ls-files '*/scripts/requirements.txt'); do
            echo "Checking $f"
            python -m pip install --dry-run --quiet --require-hashes --only-binary :all: -r "$f"
          done
      - name: Every Node script folder must have a lockfile
        run: |
          for d in $(git ls-files '*/scripts/package.json' | xargs -r -n1 dirname); do
            test -f "$d/package-lock.json" || { echo "Missing lockfile in $d"; exit 1; }
          done
      - name: Run skill tests
        run: |
          if [ -d tests ]; then python -m pip install --require-hashes -r tests/requirements.txt && python -m pytest -q tests; fi

Add your SBOM generation step to the same workflow using the tool your team already standardises on, and fail the job if a component crosses your vulnerability policy. If you use Safeguard, safeguard exec is the CI entry point and policies and gates decide whether the pull request passes.

Step 9: Sign what you share

When the shared repository cuts a release that other teams will tap, sign the bundle so consumers can verify it came from your CI and was not changed afterwards. With Sigstore's cosign, keyless signing writes a bundle that holds the signature, certificate and transparency log proof:

tar -czf agent-skills-v1.4.0.tgz --exclude .git -C ~/agent-skills .
cosign sign-blob agent-skills-v1.4.0.tgz --bundle agent-skills-v1.4.0.sigstore.json

Consumers verify before they unpack:

cosign verify-blob agent-skills-v1.4.0.tgz \
  --bundle agent-skills-v1.4.0.sigstore.json \
  --certificate-identity "https://github.com/your-org/agent-skills/.github/workflows/release.yml@refs/heads/main" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com"

Run the signing step inside CI, not on a laptop, so the certificate identity is the workflow and the bundle meets the spirit of SLSA Build L2: signed provenance from a hosted build platform.

Step 10: Review on a schedule, and roll back with care

Once a week, repeat the read-only inventory from Step 2 and compare it with the previous week. New hooks, new cron jobs, new plugins in plugins.enabled and new MCP servers in config.yaml should all have a matching approval.

If you find a skill or script you did not approve, roll back from git rather than deleting by hand.

Warning: the commands below change agent state. Take a fresh backup first (Step 1) and check which branch you are on.

STAMP=$(date +%Y%m%d-%H%M%S)
tar -czf "$HOME/hermes-backup-$STAMP.tar.gz" -C "$HOME" .hermes
cd ~/.hermes/skills
git status
git log --oneline -- devops/ci-weekly-summary
git restore --source=<last-good-commit> -- devops/ci-weekly-summary
git commit -S -m "Revert ci-weekly-summary to reviewed version"

For changes to project files made during a session, Hermes checkpoints let you preview before restoring. Warning: /rollback <N> restores files and also undoes the last chat turn; back up the project or commit your work first.

/rollback
/rollback diff <N>
/rollback <N>

If an unapproved cron job turns up, pause it before you investigate (hermes cron pause <id>), then remove it once you have kept a copy of its definition.

Where Safeguard fits

Safeguard does not scan, govern or monitor Hermes Agent, and it is not integrated with it. The honest connection is this: an agent that writes code, installs packages and authors skills produces software supply chain artifacts, and those artifacts need the same inventory, provenance, policy gates and patching as any other code. That is what Safeguard does for any codebase.

In practice, that means three things for a team running a self-extending agent. First, the shared skills repository and the agent's sandbox image are both things you can scan: safeguard scan --dir . for the repository, safeguard scan --image <name> for the image, or safeguard scan --sbom <file> for an SBOM you already produce, with results written as JSON under ./output. SBOM generation and analysis in SPDX and CycloneDX are generally available, so the "record what each skill installs" requirement from SSDF PS.3.2 becomes a file you keep, and the platform shows which projects contain a given component and version when the next advisory lands. Second, policies and gates evaluate in the platform and can block a pull request in CI, which is where Step 8 above plugs in, and attestation and signing (SLSA, Sigstore, in-toto) are generally available for the release in Step 9. Third, when a dependency that an agent installed turns out to be vulnerable, autonomous remediation can open a fix pull request; it ships switched off, so you decide what runs on its own. Where Safeguard does not help: it does not review the instructions inside a skill, it does not watch the agent's live behaviour, and it does not replace the Hermes approval gates or a sandbox.

Agent identity, which tracks which agent holds what access, is generally available; MCP Guardrail, the AI Gateway (an LLM firewall) and AI-BOM discovery are in early access, so ask what they cover today before you plan around them.

Common mistakes

  • Treating the agent's home directory as cache. ~/.hermes/skills, config.yaml, cron/jobs.json and hooks/ are executable configuration. Back them up, version them and review them.
  • Turning on the content scanner and calling it review. skills.guard_agent_created catches dangerous patterns. It does not read for intent. Use skills.write_approval as well.
  • Relying on deny patterns inside a container. Container backends skip dangerous-command checks by design. Inside the sandbox, package sources and network policy are the controls.
  • Pinning the top-level package and nothing else. Without a lockfile or hashes, the transitive tree drifts. Hash-checking mode is all or nothing for a reason.
  • Mounting a shared skills directory read-write for every agent. The Hermes docs say external directories are not a write boundary. Make shared directories read-only for agent processes and route changes through git.
  • Forgetting the hooks directory. Gateway hooks are trusted by placement. A file there runs at the next gateway start with the gateway's privileges.
  • Leaving lazy installs on in an unattended profile. A cron profile should never fetch new code at run time. Rebuild the image when dependencies change.
  • Assuming the agent's summary is the truth. The Hermes docs warn that after a blocked write "the model may still claim the edit succeeded." Trust the diff and the file mutation verifier, not the closing message.

FAQ

What is a self-extending AI agent?

It is an agent that adds to its own capabilities while it works, by installing packages, writing scripts, saving reusable skills, adding tools such as MCP servers, or scheduling jobs. The model itself does not change. What grows is a set of files and configuration that future sessions load and run.

Is it safe to let an AI agent install packages?

It can be, if the agent can only install from a source you curate, only at pinned versions with hashes, and only inside a sandbox. Without those controls an agent can install an unpinned version, a package with install scripts, or a hallucinated name that someone else has registered.

Does Hermes Agent review the skills it writes?

Not by default. On 23 October 2026, the Hermes docs list skills.write_approval: false and skills.guard_agent_created: false as defaults, so agent skill writes land immediately and unscanned. Setting write_approval: true stages every write under ~/.hermes/pending/skills/ for review with /skills diff and /skills approve.

Can Hermes Agent install software on its own?

It can run package manager commands through its terminal tool, subject to its approval mode, and Hermes itself can install declared optional extras on demand when security.allow_lazy_installs is enabled. Set that key to false and use a sandboxed backend with a curated package source if you want installs to be deliberate.

Why is an agent skill a supply chain risk?

Because it is executable instruction plus optional code that loads automatically into later sessions and can be shared through directories, repositories and hubs. If one is wrong or was influenced by hostile content, every consumer runs it. That is the same shape as a compromised dependency.

What does NIST SP 800-218A say about AI agents writing code?

SP 800-218A is the SSDF profile for generative AI and dual-use foundation model development. It focuses on model and data provenance, integrity and security. It does not specifically address code written by an agent at runtime. For that, apply the base SSDF tasks: PS.1.1, PS.3.2, PW.4.1, PW.4.4 and PW.7.1.

How do I stop an agent from installing hallucinated packages?

Make the agent's only package source a curated mirror or feed, so a name that is not already approved fails to resolve. Add frozen installs and hash pinning for anything a skill installs, and see our slopsquatting control set for the full list.

Is Hermes Agent safe to run on a work laptop?

The Hermes docs describe several default protections (command approvals, a hardline blocklist, file-write denylists, secret redaction) and a guide for tightening them on work machines. Two published CVE records affect earlier versions: CVE-2026-71963, which CVE.org lists as remote code execution in versions 0.18.2 through 0.21.0, and CVE-2026-85105, an authorization bypass reported against version 0.18.0. Run a current release, use a container backend, and turn on the skill and memory write gates.

Should agent-written code be labelled in git?

Yes. Use commit trailers or a consistent message convention for agent-authored changes, sign the commits you approve, and keep the session or task reference in the message. It costs little and makes review and incident response much faster.

Why patching speed still matters for agent-installed code

A self-extending agent turns package installs, scripts and skills into part of your codebase, often without a pull request. The agent's own dependency tree, its plugins and the packages its skill scripts pull in are open source components that receive CVEs like any other, so the gap between a fix and your running environment matters here too.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.

3. Gold Registry: start from components that are already fixed

registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingThe Gold scan GitHub Action in CI, plus Safeguard policies and gates
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch (early access)
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

The first demo shows Claude connected to the Safeguard MCP server with OAuth, where you choose which Safeguard tools Claude may use. You add Safeguard from Claude's connector directory rather than writing a custom configuration by hand. It is the same least-privilege idea this post argues for: an agent gets the specific tools it needs, chosen by a person, and nothing it adds to itself.

Click through it at your own pace, or open it full screen.

The second demo is a real Safeguard CLI session. The assistant is asked to fix a lodash CVE, reads the finding and advisory, asks before each command, edits package.json to lodash 4.17.21, runs npm install and npm test with approval, and pushes nothing. It then shows /permissions, /model and /scan .. That is the shape you want for any agent that changes dependencies: every install visible, every command approved, and a scan at the end.

Click through it at your own pace, or open it full screen.

The third demo sets up the local runner on your own machine, approves it with a device code, and scans from the terminal. For a team running agents in sandboxes, the same flow lets you scan the agent's image and its shared skills repository where they live, without sending the code anywhere first.

Click through it at your own pace, or open it full screen.

To try it on your own repositories, download Safeguard or read the CLI docs.

Quick check

In Hermes Agent, which setting makes the agent's own skill writes wait for human approval, and what is its default?

skills.write_approval. It defaults to false, so writes land immediately. When set to true, every create, edit, patch, delete and supporting-file write is staged under ~/.hermes/pending/skills/ and reviewed with /skills pending, /skills diff, /skills approve and /skills reject.

Why is a curated package source the strongest single control against hallucinated package names?

Because a name that is not already in the curated source cannot resolve, whatever the model writes. Pinning and hashing protect the versions you chose; the curated source stops names you never chose from being installed at all.

Sources

Last reviewed: 23 October 2026. Hermes Agent ships several releases a week; check its docs for current defaults before you copy a setting.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.