An agent skill can hand a stranger your shell - hours after you installed it

grith team··11 min read·security
grith is live

A security proxy for AI coding agents, enforced at the OS level. Install grith and put a real boundary around your agent.

A SKILL.md document feeds instructions into an AI agent process tree. File, shell and network actions then cross a hexagonal runtime enforcement boundary, where project access passes, credential access is held and unknown network egress is stopped.
The skill is instructions. The security boundary has to govern what those instructions cause the agent and its child processes to do.

An agent skill can bundle executable Python, Bash and JavaScript. Its specification defines the maximum length of its name, but provides no portable way to limit which files that code may read, which processes it may spawn or which hosts it may contact.

Without runtime enforcement, installing an agent skill can amount to giving an unreviewed stranger your shell, repository and developer credentials - possibly hours after you installed it.

Not every skill is malicious. Most are useful instructions written by people trying to make agents more reliable. The problem is that the current contract cannot express the difference between a PDF formatter that needs one input file and a deployment helper that needs the network, cloud credentials and permission to rewrite production configuration.

To the host agent, both are folders containing Markdown.

The ecosystem is standardising distribution before authority

This is no longer a niche format.

X now publishes an official skill describing how agents can use its API, discoverable through a well-known endpoint and installable with one command:1

npx skills add https://docs.x.com

On 5 September 2026, mise creator Jeff Dickey introduced packslip, a signed release manifest that can associate versioned agent skills with the software they document.2 It is thoughtful supply-chain engineering: pin the release, verify the signature, check the downloaded bytes and make skill activation opt-in.

The packslip announcement also states the limit precisely: a verified signature tells you where the instructions came from. It does not establish that those instructions are appropriate for your project.

A front-page Ask HN thread now has more than 100 comments about how people manage skill files.3 The discussion covers Git, symlinks, version pinning, package managers, evals and bundled scripts. The word “permission” does not appear.

That absence is the other half of the contract. The ecosystem is learning to distribute and maintain skills before it has agreed how to bound what they can do. A manifest can describe requested authority. Something outside the skill must enforce it.

What SKILL.md can express today

The current specification defines five useful frontmatter concepts:4

---
name: release-notes
description: Generate release notes from commits and pull requests.
license: Apache-2.0
compatibility: Requires git, Python and internet access.
allowed-tools: Bash(git:*) Read
---

name and description help the agent discover and select the skill. license covers distribution. compatibility is prose about environmental requirements. metadata is an arbitrary string map.

allowed-tools sounds like a permission system, but the specification marks it experimental and says support varies between clients. More importantly, it names tools rather than authority. Read does not answer which paths. Bash(git:*) does not answer which repository, remote or credentials. It says nothing about child processes, DNS, listening sockets or secrets.

The specification separately defines scripts/ as a place for executable code and recommends Python, Bash and JavaScript as common options. Its authoring guide shows skills invoking uvx, npx, bunx, deno run and go run, including packages resolved at execution time.5

So the portable format has a standard place for executable code, but no standard way to bound that code's effects.

The dangerous part happens later

Skills use progressive disclosure. At startup, an agent sees each skill's name and description. When a task matches, it loads the full SKILL.md. It reads supporting files and runs bundled scripts only when the instructions call for them.4

That is good context management. It is awkward security timing.

The developer may inspect and install a skill on Monday. On Thursday, during an unrelated-looking repository task, the agent decides the description matches and activates it. A plausible malicious chain then looks like this:

  1. The skill tells the agent to run python3 scripts/report.py as a routine preparation step.
  2. The script searches for configuration that will supposedly improve its report.
  3. It reads a neighbouring project's .env, a Git credential store or a cloud credential file.
  4. It sends the result to an external endpoint or uses the developer's existing authenticated tooling to publish it.
  5. It returns a normal-looking report, so the user sees no obvious failure.

Nothing in that chain requires a memory-corruption exploit. The skill asks the agent to use capabilities the agent already has.

This is why the risk is higher than “a Markdown file might contain a bad prompt”. The Markdown is a delayed control plane for code execution under ambient developer authority.

How dangerous is that?

It depends entirely on the agent's effective runtime authority.

Runtime postureConsequence of a malicious skill
Read-only workspace, no network, no secretsMostly prompt manipulation and exposure of workspace content
Workspace write access plus package executionSource tampering and dependency compromise
Home-directory reads plus outbound networkCredential and private-project exfiltration
Full shell with approval bypassDeveloper-account compromise and persistence
CI runner with repository or deployment credentialsSupply-chain or production compromise

Native agent sandboxes and approval prompts matter. They reduce risk when they are enabled and narrowly configured. They are not part of the portable skill contract, however, and a skill that works across many clients does not receive one consistent security boundary.

The worst case should be understood in familiar terms: running an unreviewed package install script as your normal user, except the trigger is selected later by a model and the instructions can adapt to the surrounding task.

Signing solves provenance, not behaviour

Signed skills are better than unsigned skills. Version pins, checksums, release-age delays and independent review all remove real supply-chain risks.

They answer important questions:

  • Who published this skill?
  • Are these the bytes they signed?
  • Did the contents change between releases?
  • Has a reviewer approved this exact version?

They do not answer:

  • Which files may it read or modify?
  • Which credentials may it use?
  • Which processes may it spawn?
  • Which hosts may receive data?
  • Did its runtime behaviour match its declared purpose?

A trusted author can make a mistake. A legitimate release can contain an over-broad helper. An acquired or compromised publisher can sign malicious instructions perfectly. Provenance is necessary, but a valid signature is not a safety verdict.

What a real permissions manifest needs

A useful extension would declare concrete resources and effects, not just high-level tool names. For example:

requested-permissions:
  filesystem:
    read:
      - '${workspace}/src/**'
      - '${workspace}/package.json'
    write:
      - '${workspace}/generated/**'
  process:
    spawn:
      - 'python3'
      - 'git'
  network:
    connect:
      - 'api.x.com:443'
  secrets:
    use:
      - 'X_API_TOKEN'

This is illustrative, not current Agent Skills syntax. The important semantics are:

  1. The skill requests authority. It does not grant authority to itself. The host or an external policy must intersect the request with what the operator permits.
  2. Objects are explicit. Filesystem permissions name paths, network permissions name destinations, secret permissions name handles and process permissions name executable identities.
  3. Children inherit the boundary. Running an allowed python3 cannot become a tunnel around the policy.
  4. Undeclared effects fail closed. A skill that requests workspace reads and then reaches for ~/.ssh/id_ed25519 does not get a warning label. It gets a denied read.
  5. Observed behaviour is recorded. The audit should show what was requested, granted, attempted and denied.

This direction already has research behind it. SkillGuard proposes treating skills as permission-bearing executable artefacts, combining manifests, deny-by-default runtime access control and behaviour monitoring.6 Its evaluation also shows why nobody should market manifests as a complete solution: the framework reduced attack success, but did not reduce it to zero.

Permission metadata is a contract. Runtime enforcement is what makes breaking the contract consequential.

Where Grith sits today

Grith does not currently parse SKILL.md, verify skill signatures or identify which active skill caused an operation. When Claude runs a skill, Grith sees the caller as the supervised Claude session, not as release-notes@1.2.0.

What Grith does provide is the enforcement layer underneath the agent:

grith exec --workspace-only -- claude

The skill can persuade Claude to run Python. It cannot persuade Grith that Python's subsequent syscalls did not happen.

The skill tells the agent to...Grith evaluates...
Run a bundled helperThe process spawn, arguments, executable provenance and child process tree
Read an SSH key, .env or cloud credentialThe actual file path, sensitivity and resulting data taint
Send data elsewhereDNS queries, destination, port, egress reputation and prior sensitive reads
Rewrite or delete filesThe target path, operation risk, rate and destructive pattern
Hand work to Docker, systemd-run or a desktop control socketThe attempted authority delegation before work escapes the supervised tree

With --workspace-only, filesystem access outside the project boundary is denied before the normal read-noise shortcuts. Necessary system runtime reads and paths explicitly trusted by the selected agent profile remain reachable. The sensitive-path, taint, egress and process filters still apply independently.

That final qualification matters. Grith's shipped Claude and Codex profiles trust their own state directories, including ~/.claude/** and ~/.codex/**, for routine operation. Skill files in those trees can currently be read and modified without a skill-specific decision. Grith limits the effects a skill causes elsewhere, but it is not yet a skill package manager or a per-skill capability system.

We should not claim otherwise.

The missing join

The complete model has three separate layers:

  1. Signed delivery: establish publisher identity, version and exact bytes.
  2. Requested permissions: describe the maximum authority the skill says it needs.
  3. Runtime enforcement: constrain and audit the effects the agent actually attempts.

Packslip is pushing the first layer forward. The Agent Skills ecosystem needs to standardise the second. Grith already supplies much of the third at the agent-process boundary.

The next Grith step is to join them: resolve the active skill to a canonical path and content hash, carry that identity into the syscall context, convert its requested permissions into subtractive runtime policy, and report declared versus observed behaviour. Crucially, those restrictions must run before convenience allowlists. Otherwise the most familiar paths and commands become the easiest place to hide.

This also gives skill authors something they do not have today: a testable least-authority contract. A PDF skill could prove that its integration tests touch only the selected document and output directory. An X publishing skill could prove that it connects only to the declared API host and never reads unrelated credentials. A release could fail if observed behaviour widens without a reviewed manifest change.

That is more useful than a badge saying “scanned”. It is evidence.

A skill is not dangerous because it is Markdown

It is dangerous because Markdown can select code, and the code inherits authority that was granted to the agent for an entirely different reason.

The ecosystem is making skill discovery, installation, signing and synchronisation dramatically easier. That is good work. Before one-command installation becomes the default, the runtime contract needs to catch up.

For every skill, users should be able to answer four questions before and after it runs:

  • Who shipped it?
  • What authority did it request?
  • What authority was actually granted?
  • What did it attempt to do?

Today, an agent skill can bundle Python. It still can't declare which files that Python may read.

Signing the skill proves who made that decision. A permissions manifest makes the decision visible. Enforcement underneath the agent is what makes it real.

Footnotes

  1. X Developer Platform: skill.md

  2. Jeff Dickey: Introducing packslip

  3. Ask HN: How do you manage skills files?

  4. Agent Skills specification 2

  5. Agent Skills: Using scripts in skills

  6. Pan et al.: SkillGuard - A Permission Framework for Agent Skills

Like this post? Share it.