Back to skill

Security audit

veeam-aiops

Security checks for vulnerabilities and agentic risk

Overview

This Veeam operations skill is transparent about its purpose, but it can perform irreversible infrastructure actions without an enforced approval or read-only gate.

Review before installing in production. Start with a read-only or tightly restricted Veeam account, enable write privileges only for intended workflows, and do not let an agent use restore or stop-session tools without your own approval process. Protect ~/.veeam-aiops, avoid committing MCP configs containing VEEAM_AIOPS_MASTER_PASSWORD, migrate any legacy plaintext .env secrets, and use dry-run previews before any restore.

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
SKILL.md:201
Finding

Irreversible MCP restore operation lacks an enforced approval gate

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:201-218
Vulnerability Type: Unenforced authorization for an irreversible infrastructure operation
Risk Level: High

Evidence

markdown
## 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 Veeam account you connect it with (a read-only or restricted role on the
VBR server — writes then fail at the server). There is no read-only switch,
policy file, or approval gate.

- Credentials stored **encrypted** in `~/.veeam-aiops/secrets.enc` (Fernet/AES-128 + scrypt key derivation; chmod 600) — never plaintext on disk; the master password is never stored, only a per-store salt + ciphertext
- **Audit is the guarantee, and it is not bypassable.** Every operation — MCP and CLI alike — is logged to `~/.veeam-aiops/audit.db` (relocatable via `VEEAM_AIOPS_HOME`): params (secrets redacted), result, status, duration, and the risk tier. The CLI writes the same row the MCP path does.
- `VEEAM_AUDIT_APPROVED_BY` / `VEEAM_AUDIT_RATIONALE` are optional annotations recorded on the audit row (who/why); they are never required and never block.
- **Runaway guard** — a safety backstop, not authorization: cumulative tool calls and wall-time are capped, and the same call looped in a tight session-poll/retry window trips a circuit breaker.
- Writes support `--dry-run` / `dry_run=True` and double confirmation at the CLI; CLI writes execute through the same governed tools, so they are audited + undo-recorded.
- Reversible writes (job start/stop/retry, enable/disable) record an inverse undo descriptor; the irreversible `start_vm_restore` and `session_stop` record none.

Supporting behavior is documented in references/capabilities.md:43-79: start_vm_restore is a high-risk, restore-to-original operation with no undo, while dry_run=True is an optional parameter. Double confirmation is d ...[truncated 3177 chars]

Remediation
View remediation

Remediation Suggestions

  1. Implement a mandatory two-phase MCP restore protocol:

    • Phase one resolves the restore-point identifier and returns the exact VM identity, creation time, target location, operation type, and expected overwrite behavior.
    • Phase two requires a short-lived, single-use approval token bound to those exact parameters.
  2. Reject direct restore execution unless:

    • A successful preview has occurred.
    • The preview resolved the target unambiguously.
    • The caller supplies the matching approval token.
    • Explicit confirmation is present and has not expired.
  3. Remove acknowledge_unresolved or equivalent bypasses from agent-callable interfaces. Require unresolved restores to be performed manually through the Veeam console.

  4. Add an enforceable read-only mode and default to it. Write tools should not be registered or should fail closed unless write access is explicitly enabled for the current session.

  5. Make approval metadata mandatory for irreversible operations and validate it before issuing the Veeam API request rather than recording it only as an optional audit annotation.

  6. Bind authorization to the resolved object, configured target, selected restore point, and operation type so approval cannot be reused for another VM or Veeam server.

  7. Retain the existing audit, dry-run, and target-protection mechanisms as defense-in-depth, but do not treat them as substitutes for pre-execution authorization.

  8. Continue recommending a restricted Veeam service account. Server-side least privilege should constrain the maximum impact if an agent or workflow invokes the wrong tool.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (13)

Credential Access

High
Category
Privilege Escalation
Confidence
91% confidence
Finding

The skill explicitly supports importing secrets from a legacy plaintext .env, which normalizes a weaker credential-handling path alongside the encrypted store. Even with deprecation messaging, permitting plaintext secret sources increases the chance of credential disclosure through filesystem access, backups, shell history, or accidental commits.

Content

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

md
veeam-aiops infra proxies
veeam-aiops secret set <target>                        # store password encrypted
veeam-aiops secret list                               # names only
veeam-aiops secret migrate                            # import legacy plaintext .env
veeam-aiops secret rotate-password
veeam-aiops doctor
veeam-aiops mcp                                        # start MCP server (stdio)

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 13)May include surrounding context.

veeam-aiops secret set # store/replace a password (prompts hidden) veeam-aiops secret list # names only; values never shown veeam-aiops secret rm # delete a stored password veeam-aiops secret migrate # import a legacy plaintext .env into the encrypted store veeam-aiops secret rotate-password # re-encrypt the store under a new master password

text

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
86% confidence
Finding

The documented --skip-auth option indicates the tool can perform a doctor/connectivity workflow without authentication checks. In an agent-operated environment, such a flag can weaken security assumptions, enable unauthenticated probing of configuration or service reachability, and normalize bypass behavior that could be abused if exposed through automation.

Content

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

Doctor & MCP

bash
veeam-aiops doctor [--skip-auth]           # config + encrypted store + connectivity check
veeam-aiops mcp                            # start the MCP server (stdio transport)

Session Persistence

Medium
Category
Rogue Agent
Confidence
90% confidence
Finding

The skill stores durable sensitive operational artifacts locally: audit records in SQLite and encrypted credentials in a persistent secrets file under ~/.veeam-aiops/. In the context of backup administration, these stores can reveal target identities, operational history, and possibly metadata useful to an attacker, so persistence meaningfully increases post-compromise value.

Content

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

md
metadata: {"openclaw":{"requires":{"anyBins":["veeam-aiops","uvx"]},"optional":{"env":["VEEAM_AIOPS_CONFIG","VEEAM_AIOPS_MASTER_PASSWORD"]},"homepage":"https://github.com/AIops-tools/Veeam-AIops","emoji":"💾","os":["macos","linux"]}}
compatibility: >
  Standalone, self-governed Veeam Backup & Replication operations. The governance harness (audit, policy, token/runaway budget, undo, risk-tiers) is bundled in the package — no external skill-family dependency.
  All write operations are audited to a local SQLite DB under ~/.veeam-aiops/ (relocatable via VEEAM_AIOPS_HOME).
  Credentials: Each Veeam target's login password is stored ENCRYPTED in ~/.veeam-aiops/secrets.enc (Fernet/AES-128 + scrypt-derived key) — never plaintext on disk. Run 'veeam-aiops init' to onboard, or 'veeam-aiops secret set <target>' to add one. The store is unlocked by a master password from VEEAM_AIOPS_MASTER_PASSWORD (non-interactive/MCP/CI) or an interactive prompt (CLI on a TTY). A legacy plaintext env var VEEAM_<TARGET_NAME_UPPER>_PASSWORD is still honoured as a fallback with a deprecation warning (migrate with 'veeam-aiops secret migrate'). The password is exchanged for a short-lived OAuth2 bearer token at connect time and held only in memory; passwords/tokens are never logged or echoed.
  Destructive operations (job stop, session stop, restore start) require double confirmation at the CLI layer and support --dry-run. A dry_run MAY read (that is how it can tell you the call would be refused) but never writes, records no undo, and is audited like any other governed call; the CLI --dry-run routes through the same governed function as the MCP tool. All write tools pass through the @governed_tool decorator (budget guard + audit + risk-tier labelling). Reversible writes (job start/stop/retry, enable/disable) record an inverse undo descriptor; session stop and the VM restore are irreversible and record none.
  Webhooks: none — no outbound network calls beyond the configured Veeam REST API endpoint
...[truncated 23 chars]

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 116)May include surrounding context.

md
1. `veeam-aiops restore list-points` → identify the correct restore point id
2. `veeam-aiops restore start --restore-point-id <id> --dry-run` → preview the exact API call **and the VM name + creation time** the id resolves to — never approve a restore from a GUID
3. `veeam-aiops restore start --restore-point-id <id>` → double confirmation required; this is IRREVERSIBLE (overwrites/creates a VM) and records no undo token. Refused outright if the VM name matches the configured VBR host (an in-place overwrite of the backup server itself) — a name-based safety net, not a proof, so confirm the target yourself
4. **Failure branch**: if `doctor` shows the VBR server unreachable or the password env var is missing, fix `~/.veeam-aiops/.env` (chmod 600) before retrying — the restore is never issued against an unauthenticated session.

## Usage Mode

Session Persistence

Medium
Category
Rogue Agent
Confidence
89% confidence
Finding

The undo system records inverse descriptors for write operations, creating persistent state about prior privileged actions that could be replayed through undo_apply. In an ops skill that can start/stop jobs and modify backup behavior, stored undo metadata expands the attack surface if the local store is tampered with or accessed by an unauthorized user.

Content

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

md
| Undo | `undo_list` | Read |
| | `undo_apply` | Write |

**Harness features that light up**: write tools with a clean inverse (`job_start`↔`job_stop`, `job_retry`→`job_stop`, `job_enable`↔`job_disable`) pass an `undo=` lambda so the harness records an inverse descriptor (with `_undo_id`) to the undo store. The irreversible `start_vm_restore` and `session_stop` declare no undo; `start_vm_restore` is tagged `risk_level=high`. All 27 tools are audit-logged under `~/.veeam-aiops/` and pass through the budget/runaway guard, each row carrying a descriptive risk tier. Veeam jobs/restores run as async sessions — poll with `session_get` / `session_log` instead of re-issuing (the runaway breaker backs this up). Start any triage with `overview` (jobs by last result, repos near full, running sessions), then drill in with `job_failure_rca` (categorizes failing sessions with cited error substrings) and `repository_capacity_rca` (cited free%).

## CLI Quick Reference

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
93% confidence
Finding

The document explicitly states that the tool does not enforce read-only mode or approval for write operations, relying instead on external account permissions or prompt instructions. In an agentic environment, prompt-level controls are not strong security boundaries, so a misconfigured account or prompt failure could allow the model to invoke destructive actions such as stopping jobs, disabling jobs, or starting restores without human approval.

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 the Veeam account you connect with a

Unsafe Defaults

Medium
Category
Tool Misuse
Confidence
82% confidence
Finding

An authentication-bypass-style option presented as a normal doctor flag is an unsafe default pattern because it makes reduced-assurance execution a first-class documented path. In the context of a Veeam operations skill that handles backups, restores, repositories, and secrets, any normalized auth bypass increases the chance of misuse or accidental insecure automation.

Content

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

Doctor & MCP

bash
veeam-aiops doctor [--skip-auth]           # config + encrypted store + connectivity check
veeam-aiops mcp                            # start the MCP server (stdio transport)

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 18)May include surrounding context.

text

`init` writes `~/.veeam-aiops/config.yaml` (no secrets) and stores the login
password **encrypted** in `~/.veeam-aiops/secrets.enc` (Fernet + scrypt; chmod
600). It prompts for a *master password* that unlocks the store; set it via
`VEEAM_AIOPS_MASTER_PASSWORD` for non-interactive (MCP/CI) use.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The guide shows VEEAM_AIOPS_MASTER_PASSWORD embedded directly in an MCP config env block, which encourages storing the decryption password in plaintext configuration. That secret may be exposed through checked-in config files, local file disclosure, backups, screenshots, or other users/processes that can read the config, weakening the protection of the encrypted credential store.

Content

No source excerpt is available for this finding.

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 · SKILL.md (reported line 117)May include surrounding context.

md
> by, or sponsored by Veeam Software**. MIT licensed. See `SECURITY.md`.

- **Credentials**: stored **encrypted** in `~/.veeam-aiops/secrets.enc`
  (Fernet/AES-128 + scrypt-derived key, chmod 600) — never plaintext on disk.
  The master password is never stored (only a per-store salt + ciphertext) and
  comes from `VEEAM_AIOPS_MASTER_PASSWORD` or an interactive prompt. The login
  password is exchanged for a short-lived OAuth2 bearer token at connect time

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 · SKILL.md (reported line 212)May include surrounding context.

md
> by, or sponsored by Veeam Software**. MIT licensed. See `SECURITY.md`.

- **Credentials**: stored **encrypted** in `~/.veeam-aiops/secrets.enc`
  (Fernet/AES-128 + scrypt-derived key, chmod 600) — never plaintext on disk.
  The master password is never stored (only a per-store salt + ciphertext) and
  comes from `VEEAM_AIOPS_MASTER_PASSWORD` or an interactive prompt. The login
  password is exchanged for a short-lived OAuth2 bearer token at connect time

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 72)May include surrounding context.

md
> by, or sponsored by Veeam Software**. MIT licensed. See `SECURITY.md`.

- **Credentials**: stored **encrypted** in `~/.veeam-aiops/secrets.enc`
  (Fernet/AES-128 + scrypt-derived key, chmod 600) — never plaintext on disk.
  The master password is never stored (only a per-store salt + ciphertext) and
  comes from `VEEAM_AIOPS_MASTER_PASSWORD` or an interactive prompt. The login
  password is exchanged for a short-lived OAuth2 bearer token at connect time

Static analysis

No suspicious patterns detected.