Back to skill

Security audit

ceph-aiops

Security checks for vulnerabilities and agentic risk

Overview

This Ceph operations skill is transparent about its purpose, but it exposes destructive storage actions through MCP without an enforced approval gate.

Install only if you intend an agent to inspect or operate a Ceph cluster. Start with a dedicated read-only Ceph Dashboard account, grant write privileges only for a controlled maintenance session, and require an external human approval workflow before any MCP write that can delete pools, images, snapshots, or change replica size.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Error
Location
references/agent-guardrails.md:47
Finding

Destructive MCP operations lack an enforced operator-confirmation gate

Content
View full analysis

Vulnerability Details

File Location: references/agent-guardrails.md, lines 47 and 79–81
Vulnerability Type: Missing authorization enforcement for destructive operations
Risk Level: High

Vulnerable Snippet

markdown
| "Confirm before anything destructive" | Every destructive tool (`osd_purge`, `osd_mark_out`, `pool_delete`, `rbd_image_delete`, `rbd_snapshot_delete`, `set_pool_size`) takes `dry_run=True` for a preview and is `risk=high`, tagged `review` on its audit row. ⚠️ **The double confirmation is a CLI feature, and only `osd_purge` and `osd_mark_out` have CLI commands** — the other four are reachable only over MCP, where nothing prompts. Keep your own confirmation for those. |
text
- `pool_delete`, `rbd_image_delete`, `rbd_snapshot_delete` and `set_pool_size` have no CLI
  command, so nothing will ask you to confirm them. Call them with `dry_run=True` first,
  show the operator what would change, and wait for an explicit go-ahead.

Technical Analysis

The Skill exposes pool_delete, rbd_image_delete, rbd_snapshot_delete, and set_pool_size through MCP. The documentation expressly states that these operations do not produce a confirmation prompt. The dry-run and operator-approval procedure is only a prompt-level instruction to the agent, rather than a control enforced by the MCP operation.

Consequently, an agent can submit the real destructive operation without demonstrating that:

  1. A dry run was completed for the same operation, target, and parameters.
  2. The dry-run result was presented to the operator.
  3. The operator explicitly approved that exact change.
  4. The approval remains current and has not been reused for different parameters.

An audit label such as risk=high or review records an operation but does not authorize or prevent it. Likewise, account-level Ceph permissions limit which accounts can perform writes, but a write-enabled account still leaves the model-to-cluster authorization boundary ...[truncated 1410 chars]

Remediation
View remediation

Remediation Suggestions

Enforce destructive-operation approval in the MCP implementation rather than relying on model instructions:

  1. Require a successful dry run before every destructive operation.
  2. Bind the dry-run record to the exact operation, target resource, parameters, authenticated account, and cluster.
  3. Return a cryptographically random, short-lived, single-use confirmation token after the dry run.
  4. Require the token for the real operation and reject calls with missing, expired, reused, or parameter-mismatched tokens.
  5. Require the client to obtain explicit operator approval before submitting the token.
  6. Default destructive calls to dry-run mode and require an explicit execution flag.
  7. Apply the gate consistently to pool_delete, rbd_image_delete, rbd_snapshot_delete, and set_pool_size.
  8. Preserve least-privilege Ceph roles as defense in depth, using read-only accounts unless write access is explicitly required.
  9. Continue audit logging, but treat it as detection and accountability rather than authorization.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (16)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

This capability exposes a destructive DELETE operation for purging an OSD by ID, and the only described safeguards are dry-run and double-confirm at the CLI/policy layer rather than a hard technical constraint in the API surface. If an agent is induced to supply the wrong OSD ID, or if identifier validation and authorization are weak elsewhere, this can irreversibly remove storage components and trigger cluster degradation or data loss.

Content

Scanner excerpt · references/capabilities.md (reported line 38)May include surrounding context.

md
| `osd_reweight` | medium | `POST /api/osd/{id}/reweight` | 0.0 = drain; captures prior weight (undo) |
| `osd_mark_in` | medium | `POST /api/osd/{id}/mark` | captures prior up/in state (undo) |
| `osd_mark_out` | **high** | `POST /api/osd/{id}/mark` | drains data; CLI double-confirm + dry-run; captures prior state |
| `osd_purge` | **high** | `DELETE /api/osd/{id}` | destroy + crush rm + auth del; **irreversible**; dry-run + double-confirm |
| `trigger_scrub` | medium | `POST /api/pg/{pgid}/scrub` | schedule a shallow scrub; no prior state |
| `trigger_deep_scrub` | medium | `POST /api/pg/{pgid}/deep_scrub` | schedule a deep (data-integrity) scrub |
| `set_pool_quota` | medium | `PUT /api/pool/{name}` | captures prior max_bytes/max_objects (undo) |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% confidence
Finding

This skill advertises a high-risk pool deletion endpoint that destroys all data in the named pool, making parameter abuse especially dangerous because a mistaken or manipulated pool name results in immediate irreversible loss. In an agent context, natural-language ambiguity, prompt injection, or stale inventory can all cause the wrong target to be selected.

Content

Scanner excerpt · references/capabilities.md (reported line 46)May include surrounding context.

md
| `set_pool_autoscale` | medium | `PUT /api/pool/{name}` | captures prior autoscale mode (undo) |
| `pool_create` | medium | `POST /api/pool` | create a new pool |
| `set_pool_size` | **high** | `PUT /api/pool/{name}` | replica change **forces data movement**; dry-run + double-confirm; captures prior size |
| `pool_delete` | **high** | `DELETE /api/pool/{name}` | **destroys all data**; dry-run + double-confirm |
| `rbd_image_create` | medium | `POST /api/block/image` | create an RBD image |
| `rbd_snapshot_create` | medium | `POST /api/block/image/{spec}/snap` | reversible → delete the snapshot |
| `rbd_image_delete` | **high** | `DELETE /api/block/image/{spec}` | **irreversible**; dry-run + double-confirm |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
94% confidence
Finding

The documented DELETE operation for RBD images is inherently dangerous because image specifiers are user-controllable parameters and deletion is irreversible. In a storage-operations skill, an incorrect pool/image spec or prompt-manipulated target could destroy live block devices backing workloads.

Content

Scanner excerpt · references/capabilities.md (reported line 49)May include surrounding context.

md
| `pool_delete` | **high** | `DELETE /api/pool/{name}` | **destroys all data**; dry-run + double-confirm |
| `rbd_image_create` | medium | `POST /api/block/image` | create an RBD image |
| `rbd_snapshot_create` | medium | `POST /api/block/image/{spec}/snap` | reversible → delete the snapshot |
| `rbd_image_delete` | **high** | `DELETE /api/block/image/{spec}` | **irreversible**; dry-run + double-confirm |
| `rbd_snapshot_delete` | **high** | `DELETE /api/block/image/{spec}/snap/{snap}` | **irreversible**; dry-run + double-confirm |
| `throttle_recovery` | medium | `GET`+`POST /api/cluster_conf` | tunes `osd_max_backfills` / `osd_recovery_max_active`; captures prior values (undo) |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
93% confidence
Finding

Snapshot deletion is also a destructive parameterized action, and although narrower than deleting the whole image, abusing the image/snapshot identifiers can remove recovery points that may be critical for rollback or incident response. In this skill's context, the danger is elevated because the tool is designed for direct production Ceph administration over live APIs.

Content

Scanner excerpt · references/capabilities.md (reported line 50)May include surrounding context.

md
| `rbd_image_create` | medium | `POST /api/block/image` | create an RBD image |
| `rbd_snapshot_create` | medium | `POST /api/block/image/{spec}/snap` | reversible → delete the snapshot |
| `rbd_image_delete` | **high** | `DELETE /api/block/image/{spec}` | **irreversible**; dry-run + double-confirm |
| `rbd_snapshot_delete` | **high** | `DELETE /api/block/image/{spec}/snap/{snap}` | **irreversible**; dry-run + double-confirm |
| `throttle_recovery` | medium | `GET`+`POST /api/cluster_conf` | tunes `osd_max_backfills` / `osd_recovery_max_active`; captures prior values (undo) |

## Out of scope (by design)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/cli-reference.md (reported line 11)May include surrounding context.

bash
ceph-aiops init                      # interactive onboarding wizard
ceph-aiops doctor [--skip-auth]      # config + secret store + JWT login + mgr-dashboard reachability
ceph-aiops mcp                       # start the MCP server (stdio transport)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/cli-reference.md (reported line 52)May include surrounding context.

bash
ceph-aiops init                      # interactive onboarding wizard
ceph-aiops doctor [--skip-auth]      # config + secret store + JWT login + mgr-dashboard reachability
ceph-aiops mcp                       # start the MCP server (stdio transport)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
70% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/setup-guide.md (reported line 136)May include surrounding context.

bash
ceph-aiops init                      # interactive onboarding wizard
ceph-aiops doctor [--skip-auth]      # config + secret store + JWT login + mgr-dashboard reachability
ceph-aiops mcp                       # start the MCP server (stdio transport)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/cli-reference.md (reported line 21)May include surrounding context.

ceph-aiops secret set [--value ] # store Dashboard password (hidden prompt if no --value) ceph-aiops secret list # names only — values never shown ceph-aiops secret rm ceph-aiops secret migrate # import legacy plaintext .env (CEPH__PASSWORD) ceph-aiops secret rotate-password # re-encrypt under a new master password

text

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · SKILL.md (reported line 23)May include surrounding context.

md
metadata: {"openclaw":{"requires":{"anyBins":["ceph-aiops","uvx"]},"optional":{"env":["CEPH_AIOPS_CONFIG","CEPH_AIOPS_MASTER_PASSWORD"]},"homepage":"https://github.com/AIops-tools/Ceph-AIops","emoji":"🐙","os":["macos","linux"]}}
compatibility: >
  Standalone, self-governed Ceph operations. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency. Works against vanilla ceph-mgr (cephadm / hypervisor-bundled Ceph / MicroCeph); no croit and no Kubernetes dependency.
  All write operations are audited to a local SQLite DB under ~/.ceph-aiops/ (relocatable via CEPH_AIOPS_HOME).
  Connection: the ceph-mgr Dashboard REST API over HTTPS (default port 8443). Authentication is username + password exchanged for a short-lived JWT at POST /api/auth; the mgr 'dashboard' module must be enabled. The username lives in config.yaml; the password is stored ENCRYPTED in ~/.ceph-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'ceph-aiops init' to onboard, or 'ceph-aiops secret set <target>' to add one. The store is unlocked by a master password from CEPH_AIOPS_MASTER_PASSWORD (non-interactive/MCP/CI) or an interactive prompt (CLI on a TTY). A legacy plaintext env var CEPH_<TARGET_NAME_UPPER>_PASSWORD is still honoured as a fallback with a deprecation warning (migrate with 'ceph-aiops secret migrate'). The password is held only in memory and exchanged for a JWT at request time; secrets are never logged or echoed.
  State-changing operations require double confirmation at the CLI layer and support --dry-run. All write tools pass through the @governed_tool decorator (pre-check + budget guard + audit + risk-tier label). High-risk destructive ops (osd_mark_out, osd_purge, pool_delete, set_pool_size, rbd_image_delete, rbd_snapshot_delete) require dry-run + double confirmation; reversible writes (osd_reweight, cluster_flag_set, set_pool_quota/pg_num/autoscale, throttle_r
...[truncated 25 chars]

Session Persistence

Medium
Category
Rogue Agent
Confidence
95% confidence
Finding

The skill explicitly exposes state-changing Ceph operations but states there is no read-only switch, policy file, or approval gate, and that authorization is left to the agent's judgment or the connected account. In an agentic environment, this creates a real risk of unintended destructive actions against storage infrastructure if the model is prompted into executing writes using an overprivileged account.

Content

Scanner excerpt · SKILL.md (reported line 135)May include surrounding context.

md
## Governance & Safety

The skill delivers reads and writes and records them; it does **not** decide
whether a write is permitted. That is your agent's judgement, or the permission
of the account you connect it with (a ceph-mgr Dashboard account with a
read-only role — writes then fail at the mgr). There is no read-only switch,
policy file, or approval gate.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
95% confidence
Finding

The guardrail explicitly states that the tool does not enforce read-only mode or approval for writes, and that write control must come from external account permissions or prompting. In a Ceph operations skill, this means a model with access to write-capable credentials can perform destructive cluster actions without an in-tool authorization checkpoint, which materially increases the risk of unintended or induced autonomous changes.

Content

Scanner excerpt · references/agent-guardrails.md (reported line 15)May include surrounding context.

md
## Authorization is not this tool's job — decide it where it belongs

Whether a write should happen is your decision, or the account's. The tool does
not gate it — there is no read-only switch and no approval prompt to configure.
The two right places to control read vs write:

- **The account you connect with.** Give it a ceph-mgr Dashboard account with a

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · references/cli-reference.md (reported line 11)May include surrounding context.

bash
ceph-aiops init                      # interactive onboarding wizard
ceph-aiops doctor [--skip-auth]      # config + secret store + JWT login + mgr-dashboard reachability
ceph-aiops mcp                       # start the MCP server (stdio transport)

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · references/cli-reference.md (reported line 52)May include surrounding context.

bash
ceph-aiops init                      # interactive onboarding wizard
ceph-aiops doctor [--skip-auth]      # config + secret store + JWT login + mgr-dashboard reachability
ceph-aiops mcp                       # start the MCP server (stdio transport)

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool defaults are unsafe or overly permissive (e.g. disabled TLS verification, no authentication, world-writable permissions). Unsafe defaults widen the attack surface.

Content

Scanner excerpt · references/setup-guide.md (reported line 136)May include surrounding context.

bash
ceph-aiops init                      # interactive onboarding wizard
ceph-aiops doctor [--skip-auth]      # config + secret store + JWT login + mgr-dashboard reachability
ceph-aiops mcp                       # start the MCP server (stdio transport)

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/setup-guide.md (reported line 20)May include surrounding context.

bash
ceph mgr module enable dashboard
# Start read-only. This tool does not decide whether a write is allowed — the
# Dashboard role does — so the role you pick here IS the authorization boundary.
ceph dashboard ac-user-create <username> -i <password-file> read-only
# find the URL/port: ceph mgr services   → e.g. https://<host>:8443/

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
80% confidence
Finding

Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Content

Scanner excerpt · references/setup-guide.md (reported line 76)May include surrounding context.

md
- The Dashboard password is **never** written to disk in plaintext. It lives only
  in `~/.ceph-aiops/secrets.enc`, encrypted with Fernet (AES-128-CBC + HMAC), the
  key derived from your master password via scrypt. Only a per-store random salt
  and the ciphertext are on disk (chmod 600); the master password itself is never
  stored.
- A legacy plaintext env var `CEPH_<TARGET_NAME_UPPER>_PASSWORD` is still honoured
  as a fallback with a deprecation warning — migrate with

Static analysis

No suspicious patterns detected.