Skip to content
Back to skills

Docker Volume Guardrails

ASecurity

Set up a Claude Code hook to unconditionally block Docker commands that permanently delete a volume (docker volume rm/prune, docker rm -v, docker system prune --volumes, docker compose down -v). Use when setting up guardrails against destructive volume deletion, or after "never delete volumes without confirmation" has been violated or nearly violated.

  • 2 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 20, 2026
ai-agentsrustshellbashrailsdockergitdatabase

Works with

  • claude code

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 20, 2026

npx -y skills add wakqasahmed/ai-engineering-workflow-skills --skill docker-volume-guardrails --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Docker Volume Guardrails?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Docker Volume Guardrails
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/wakqasahmed-docker-volume-guardrails/badge)](https://www.skillsdirectory.com/skills/wakqasahmed-docker-volume-guardrails)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: docker-volume-guardrails
description: Set up a Claude Code hook to unconditionally block Docker commands that permanently delete a volume (docker volume rm/prune, docker rm -v, docker system prune --volumes, docker compose down -v). Use when setting up guardrails against destructive volume deletion, or after "never delete volumes without confirmation" has been violated or nearly violated.
---

# Docker Volume Guardrails

Sets up a PreToolUse hook that unconditionally blocks any Docker command
that permanently deletes one or more volumes.

## Why unconditional, with no override

This repo's own global instructions already say: "never delete volumes
without explicit human confirmation." A hook only ever sees the raw command
string handed to it - it has no way to observe whether a human actually
confirmed *this specific* deletion earlier in the conversation. The only
mechanical enforcement that is actually faithful to that rule is to never
let the agent run this class of command at all - exactly matching
`git-guardrails-claude-code`'s own precedent for force-push and
`reset --hard`. If a human has genuinely decided to delete a volume, they
run that command themselves, outside the agent.

Companion to `docker-db-guardrails`, which handles a different class of
mistake (a schema/data-wipe command run against the wrong database because
its real target was never resolved and verified). This skill's class of
mistake needs no such resolution step - volume deletion is destructive
regardless of which volume it targets, so the rule is simply "never," full
stop.

## What Gets Blocked

- `docker volume rm` / `docker volume remove`
- `docker volume prune`
- `docker rm -v` / `docker rm --volumes` (removes anonymous volumes attached
  to a container)
- `docker system prune --volumes` (with or without `-a`)
- `docker compose ... down -v` / `--volumes`, and the legacy `docker-compose
  down -v`/`--volumes` binary

Ordinary volume **mounting** (`docker run -v /host:/container ...`,
`docker compose up`) is untouched - the hook only matches `-v`/`--volumes`
on the specific subcommands where that flag means "delete" (`rm`, `down`),
never on `run`/`create`/`up`, where the identical flag means "mount."

As with `docker-db-guardrails`, prose that merely *mentions* these commands
(a commit message or issue body discussing this very hook, for example) is
not blocked - the hook tokenizes with `shlex` and excludes the values of
text-carrying flags (`-m`/`--message`/`--body`/`--title`/`--comment`) from
the scan.

## Steps

### 1. Ask scope

Ask the user: install for **this project only** (`.claude/settings.json`) or
**all projects** (`~/.claude/settings.json`)?

### 2. Copy the hook script

The bundled script is at:
[scripts/block-volume-deletion.py](scripts/block-volume-deletion.py)

Copy it to the target location based on scope:

- **Project**: `.claude/hooks/block-volume-deletion.py`
- **Global**: `~/.claude/hooks/block-volume-deletion.py`

Make it executable with `chmod +x`.

### 3. Add hook to settings

Add to the appropriate settings file, merging into any existing
`hooks.PreToolUse` array's `"Bash"` matcher entry — don't overwrite other
hooks already registered there (`git-guardrails-claude-code`,
`docker-db-guardrails`, etc.):

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "~/.claude/hooks/block-volume-deletion.py"
          }
        ]
      }
    ]
  }
}
```

(Project scope: use
`"\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-volume-deletion.py"` instead.)

### 4. Verify

Test both directions before trusting the hook in a new environment:

```bash
SCRIPT=~/.claude/hooks/block-volume-deletion.py

# Should exit 2 (BLOCKED):
echo '{"tool_input":{"command":"docker volume rm my-app-data"}}' | "$SCRIPT"
echo '{"tool_input":{"command":"docker compose down -v"}}' | "$SCRIPT"

# Should exit 0 (allowed) — mounting a volume, and prose that merely mentions these words:
echo '{"tool_input":{"command":"docker run -v my-app-data:/data --rm image"}}' | "$SCRIPT"
echo '{"tool_input":{"command":"gh issue create --body \"should we ever allow docker volume prune?\""}}' | "$SCRIPT"
```

Then prove it fires live in-session: run an actual `docker volume rm
<some-real-volume-name>` in the Bash tool and confirm the hook intercepts it
with a `PreToolUse:Bash hook error` before it executes.

## Known limitations

- No override mechanism exists by design (see above) - if this blocks a
  deletion the user has genuinely authorized, the answer is the user runs
  it themselves, not a flag or environment variable that lets the agent
  bypass it. Adding a bypass would let an agent self-authorize the exact
  thing this hook exists to prevent.
- Does not resolve command substitution or shell variables in volume names
  or subcommands - the threat model is an honest agent's mistake, not
  adversarial evasion (same scoping rationale as `docker-db-guardrails`).

Files in this skill

  • SKILL.md4.9 KB
  • scripts/block-volume-deletion.py5.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.