Back to skill

Security audit

huawei-cloud-obs-lifecycle-management

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real Huawei OBS lifecycle management skill, but it needs review because it can change bucket lifecycle rules and installs an unverified telemetry helper into the user's environment.

Install only with a Huawei OBS identity scoped to the specific bucket you intend to manage. Before any create, update, or delete, export the current lifecycle configuration, review the exact pending JSON and affected-object preview, and avoid --apply unless you have an external approval process. Consider disabling telemetry with SKILL_QUALITY_REPORT=0 or manually verifying the helper CLI before allowing it to install into ~/.local/bin.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/obs_lifecycle_analyzer.py:380
Finding

Mutating lifecycle operations allow confirmation bypass through --apply

Content
View full analysis

Vulnerability Details

File Location: scripts/obs_lifecycle_analyzer.py:380-383, 425-427, 514-516, 526-532, 582-583
Vulnerability Type: Unenforced authorization and confirmation gate
Risk Level: High

Vulnerable Code

python
def _confirm(message: str, apply: bool) -> None:
    if apply:
        print(f"[confirm-gate] SKIPPED (--apply provided; user confirmation assumed given elsewhere): {message}")
        return
    print(f"\n⚠️  {message}")
    answer = input("Type 'yes' to continue, anything else to abort: ").strip().lower()
    if answer != "yes":
        sys.exit("Aborted by user.")

The mutation paths rely on this function immediately before changing the remote lifecycle configuration:

python
_confirm(
    f"PUT will REPLACE the whole lifecycle configuration of {bucket} "
    f"with {len(new_cfg['Rules'])} rule(s). Preview showed "
    f"{pv['affected_objects']} affected object(s). Proceed?",
    apply,
)
_put_config(bucket, new_cfg)
python
_confirm(
    f"Updating rule '{rule_id}' of {bucket}. Preview: "
    f"{pv['affected_objects']} object(s), {pv['affected_size_gb']} GB "
    f"would be affected by the updated rule. Proceed?",
    apply,
)
_put_config(bucket, cfg)
python
_confirm(
    f"Deleting rule '{rule_id}' from {bucket} is IRREVERSIBLE. "
    f"{len(rules) - len(remaining)} rule(s) will be removed, "
    f"{len(remaining)} kept. Proceed?",
    apply,
)
if remaining:
    _put_config(bucket, {"Rules": remaining})
else:
    _delete_config(bucket)

The bypass is exposed directly through the command-line interface:

python
p.add_argument(
    "--apply",
    action="store_true",
    help="skip the interactive confirmation "
         "(only after user confirmation was given elsewhere)",
)

Technical Analysis

The Skill states that lifecycle creation, update, and deletion require preview and explicit user confirmation. The executable implementation does not enforce evidence of that authorizati ...[truncated 2419 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove --apply from direct mutation commands where interactive approval is required.
  2. For automation, introduce a short-lived approval artifact generated only after showing:
    • The target bucket.
    • The exact operation.
    • The immutable final lifecycle JSON.
    • The affected-object preview.
  3. Bind the approval artifact to a digest of the bucket, operation, rule configuration, and preview result. Reject it if any value changes.
  4. Expire approval artifacts after a short interval and prevent reuse.
  5. Separate planning and application:
    • plan produces the final configuration and digest.
    • The user approves that digest.
    • apply accepts only the approved, unchanged plan.
  6. Require a stronger confirmation for whole-configuration deletion and broad expiration rules.
  7. Add tests proving that mutation cannot reach _put_config() or _delete_config() without a valid approval artifact.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/obs_lifecycle_analyzer.py:331
Finding

Update confirmation preview evaluates the deployed rule instead of the pending rule

Content
View full analysis

Vulnerability Details

File Location: scripts/obs_lifecycle_analyzer.py:331-337, 449-516
Vulnerability Type: Incorrect security preview before a destructive cloud mutation
Risk Level: High

Vulnerable Code

The preview function independently retrieves the currently deployed configuration:

python
def preview(bucket: str, prefix: str = "", rule_id: str = "", days: int = 0,
            action: str = "", limit: int = 1000) -> dict:
    cfg = get_lifecycle_config(bucket)
    rules = cfg.get("Rules") or []
    objects = list_objects(bucket, prefix, limit)
    now = datetime.now(timezone.utc)

When a rule ID is supplied without explicit preview days or action, it selects that rule from the remotely retrieved configuration:

python
if rule_id and days == 0 and not action:
    rule = next((r for r in rules if r.get("ID") == rule_id), None)
    if not rule:
        sys.exit(f"ERROR: rule '{rule_id}' not found in bucket {bucket}")
    effective = _rule_effective_prefix(rule)
    useprefix = effective
    input_objects = [o for o in objects if o["key"].startswith(useprefix)]
    for kind, d, cls, date_iso in _rule_actions(rule):
        affected = [
            o for o in input_objects
            if _action_reached(kind, d, date_iso, o["last_modified"], now)
        ]

update_rule() first modifies its local configuration:

python
cfg = get_lifecycle_config(bucket)
rules = cfg.get("Rules") or []
rule = next((r for r in rules if r.get("ID") == rule_id), None)

if prefix:
    rule["Prefix"] = prefix
    if rule.get("Filter"):
        rule["Filter"]["Prefix"] = prefix

It may also alter expiration or transition behavior:

python
if days > 0:
    if action == "expire":
        exp = rule.get("Expiration")
        if exp:
            exp["Days"] = days
        else:
            rule["Expiration"] = {"Days": days}
    elif action == "transition":
        trans = rule.get("Transitions")
        if trans:
            trans[0]["Days"] =
...[truncated 3040 chars]
Remediation
View remediation

Remediation Suggestions

  1. Refactor preview() to accept an explicit candidate rule or candidate lifecycle configuration.
  2. During update:
    • Fetch the existing configuration once.
    • Construct an immutable pending configuration.
    • Preview that exact pending configuration.
    • Display its exact JSON and impact.
    • Apply the same object without refetching or modifying it.
  3. Compute a digest of the pending configuration before confirmation and verify the digest immediately before PUT.
  4. Do not select the deployed rule by ID when previewing an update; select the modified in-memory rule.
  5. Show both old and new values for prefixes, days, actions, and storage classes.
  6. Abort if the preview cannot completely evaluate the pending rule.
  7. Add regression tests covering:
    • Narrow-to-broad prefix changes.
    • Long-to-short expiration changes.
    • Transition-class changes.
    • Rules containing both expiration and transition actions.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/obs_lifecycle_analyzer.py:518
Finding

Delete-rule mutates lifecycle configuration without the mandatory impact preview

Content
View full analysis

Vulnerability Details

File Location: scripts/obs_lifecycle_analyzer.py:518-533
Vulnerability Type: Missing safety validation before destructive policy modification
Risk Level: Medium

Vulnerable Code

python
def delete_rule(bucket: str, rule_id: str, apply: bool = False) -> dict:
    cfg = get_lifecycle_config(bucket)
    rules = cfg.get("Rules") or []
    rule = next((r for r in rules if r.get("ID") == rule_id), None)
    if not rule:
        sys.exit(f"ERROR: rule '{rule_id}' not found in bucket {bucket}")
    remaining = [r for r in rules if r.get("ID") != rule_id]
    _confirm(
        f"Deleting rule '{rule_id}' from {bucket} is IRREVERSIBLE. "
        f"{len(rules) - len(remaining)} rule(s) will be removed, "
        f"{len(remaining)} kept. Proceed?",
        apply,
    )
    if remaining:
        _put_config(bucket, {"Rules": remaining})
    else:
        # Last rule: OBS rejects {"Rules": []} (400 MalformedXML), so remove
        # the whole lifecycle configuration instead.
        _delete_config(bucket)
    return {
        "action": "delete_rule",
        "rule_id": rule_id,
        "removed": True,
        "remaining_rules": len(remaining),
        "bucket": bucket,
    }

Technical Analysis

The Skill documentation defines preview and explicit confirmation as mandatory for create, update, and delete operations. The delete implementation retrieves the configuration and counts removed and remaining rules, but never calls preview() and does not display the complete rule being removed or the objects governed by it.

The confirmation prompt therefore communicates only the number of rules affected. It does not communicate whether the deleted rule governs a narrow test prefix, the entire bucket, expiration, transition, or a large object population.

If the selected rule is the final rule, the implementation escalates from a put-back operation to _delete_config(), removing the bucket's complete lifecycle configuration. Al ...[truncated 1659 chars]

Remediation
View remediation

Remediation Suggestions

  1. Require delete_rule() to call an impact-preview function before confirmation.
  2. Display:
    • The complete rule being removed.
    • Its effective prefix and actions.
    • The number and size of currently matched objects.
    • Whether it is the final lifecycle rule.
  3. Use a stronger, separate confirmation phrase when deletion will invoke _delete_config() and remove the complete lifecycle configuration.
  4. Fail closed if object listing or rule preview fails.
  5. Bind confirmation to the retrieved configuration version or digest so the remote policy cannot change between preview and application.
  6. Preserve the existing configuration in a user-approved backup or output file before deletion.
  7. Remove or secure the --apply bypass as described in the first finding.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Writing executables into the user's local bin directory and downloading a CLI from external endpoints materially expands the skill's behavior beyond lifecycle policy management. In the context of a cloud administration skill, this is dangerous because it can modify the host environment and establish trust in a secondary binary whose integrity and purpose are not clearly bounded by the skill's stated function.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

Writing executables into the user's local bin directory and downloading a CLI from external endpoints materially expands the skill's behavior beyond lifecycle policy management. In the context of a cloud administration skill, this is dangerous because it can modify the host environment and establish trust in a secondary binary whose integrity and purpose are not clearly bounded by the skill's stated function.

Content

No source excerpt is available for this finding.

Chaining Abuse

High
Category
Tool Misuse
Confidence
75% confidence
Finding

Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Content

Scanner excerpt · references/cli-installation-guide.md (reported line 23)May include surrounding context.

bash
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y hcloud
# openEuler/CentOS
sudo yum install -y hcloud

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
60% 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-installation-guide.md (reported line 35)May include surrounding context.

Linux (x86_64)

bash
curl -O https://obs-community-tool.obs.cn-north-1.myhuaweicloud.com/hcloudcli/latest/hcloudcli-linux-amd64.tar.gz
sha256sum hcloudcli-linux-amd64.tar.gz   # compare against the official published SHA-256
tar -xzf hcloudcli-linux-amd64.tar.gz
chmod +x hcloud

External Script Fetching

High
Category
Supply Chain
Confidence
94% confidence
Finding

The script trusts network-fetched data to determine what binary to download, then installs that binary without cryptographic verification beyond transport security. This is a classic supply-chain risk: compromise of the API, object storage, release pipeline, or trust path could result in arbitrary code being installed into the user's PATH.

Content

Scanner excerpt · scripts/ensure_cli.sh (reported line 16)May include surrounding context.

sh
API_URL="https://skillsapi.developer.myhuaweicloud.com/api/quality/cli/latest"
OBS_BASE="https://obs-skills-repository.obs.cn-north-4.myhuaweicloud.com/skill-quality-cli"

V=$(curl -s "${API_URL}" | python3 -c 'import sys,json;print(json.load(sys.stdin)["version"])' 2>/dev/null)
if [ -z "$V" ]; then
    echo "警告: 无法获取 skill-quality-cli 最新版本,跳过安装" >&2
    exit 0

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

This installer fetches and installs a separate 'skill-quality-cli' tool that is unrelated to the stated OBS lifecycle-management purpose of the skill. A skill that quietly introduces extra executable components expands the trust boundary and creates a supply-chain and execution risk, especially because the installed binaries persist in the user's home directory and may later be invoked by other workflows.

Content

No source excerpt is available for this finding.

External Script Fetching

High
Category
Supply Chain
Confidence
97% confidence
Finding

The script retrieves remote data to determine the latest version and then downloads an archive based on that network-supplied value without any integrity verification such as checksum or signature validation. This is a classic supply-chain risk: if the API, storage location, or delivery path is compromised, a user could install attacker-controlled binaries while believing they are installing a trusted helper.

Content

Scanner excerpt · scripts/install_cli.sh (reported line 12)May include surrounding context.

sh
API_URL="https://skillsapi.developer.myhuaweicloud.com/api/quality/cli/latest"
OBS_BASE="https://obs-skills-repository.obs.cn-north-4.myhuaweicloud.com/skill-quality-cli"

V=$(curl -s "${API_URL}" | python3 -c 'import sys,json;print(json.load(sys.stdin)["version"])' 2>/dev/null)
if [ -z "$V" ]; then
    echo "无法获取 skill-quality-cli 最新版本" >&2
    exit 1

Direct Prompt Extraction

High
Category
System Prompt Leakage
Confidence
85% confidence
Finding

Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.

Content

Scanner excerpt · scripts/obs_lifecycle_analyzer.py (reported line 193)May include surrounding context.

python
filter_prefix = f.get("Prefix")
    if filter_prefix:  # non-empty Filter.Prefix is authoritative
        return filter_prefix
    return rule.get("Prefix") or ""


def _rule_actions(rule: dict) -> list:

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding

The skill invokes shell commands and writes local files, but it does not declare an explicit tool scope such as allowed-tools or permissions. That makes the real execution surface broader than the manifest suggests and weakens policy enforcement and review, especially for a skill that can mutate cloud storage lifecycle configuration and create local artifacts.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The invocation examples include generic terms such as "不生效", "未生效", "dry-run", "expiration", "transition", and "storage class" alongside more specific OBS phrases. These terms are broad enough to overlap with many unrelated troubleshooting or cloud-storage conversations, increasing the risk of unintended activation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Automatic telemetry is enabled by default, but the document does not clearly state what command content, bucket names, object prefixes, environment metadata, or error output may be transmitted. In a cloud-storage administration context, even metadata can be sensitive, so silent default reporting creates avoidable confidentiality and compliance risk.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The authentication section documents different environment variable names than the prerequisites section, which can cause operators to fall back to ad hoc credential handling when the documented method fails. In practice this often leads to secrets being pasted into commands, shells, or chat despite the skill warning against plaintext credential use.

Content

No source excerpt is available for this finding.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/cli-installation-guide.md (reported line 23)May include surrounding context.

bash
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y hcloud
# openEuler/CentOS
sudo yum install -y hcloud

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/cli-installation-guide.md (reported line 25)May include surrounding context.

bash
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y hcloud
# openEuler/CentOS
sudo yum install -y hcloud

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/cli-installation-guide.md (reported line 39)May include surrounding context.

bash
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y hcloud
# openEuler/CentOS
sudo yum install -y hcloud

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/cli-installation-guide.md (reported line 49)May include surrounding context.

bash
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y hcloud
# openEuler/CentOS
sudo yum install -y hcloud

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/cli-installation-guide.md (reported line 59)May include surrounding context.

bash
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y hcloud
# openEuler/CentOS
sudo yum install -y hcloud

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

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

bash
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y hcloud
# openEuler/CentOS
sudo yum install -y hcloud

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/cli-installation-guide.md (reported line 100)May include surrounding context.

bash
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y hcloud
# openEuler/CentOS
sudo yum install -y hcloud

Sudo/Root Execution

Medium
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · references/cli-installation-guide.md (reported line 110)May include surrounding context.

bash
# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y hcloud
# openEuler/CentOS
sudo yum install -y hcloud

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The guide instructs users to set --cli-region=cn-south-1 as the default profile region, which imposes a specific locale/region choice in natural language guidance. While Huawei Cloud is the domain, this line does not present the region as an example or ask the user to choose their actual region, so it reads as a forced regional default.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This markdown file explains rules that delete objects (Expiration, NoncurrentVersionExpiration) and notes that -method=put overwrites the entire lifecycle configuration, but it does not present these behaviors as an explicit warning about data loss or irreversible changes. Although best practices mention previewing changes, the document lacks a direct caution that applying these rules can permanently remove data or replace existing bucket policy state.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The documentation explicitly includes a one-command destructive operation that wipes all lifecycle rules from a bucket. In a skill intended to manage lifecycle policies safely—where other operations emphasize preview and confirmation—surfacing a bulk-delete command materially increases the chance an agent or operator will perform an irreversible, overbroad action outside the advertised delete-one-rule workflow.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file's behavior expands beyond the stated scope of OBS lifecycle management by silently performing software installation. That mismatch undermines user trust and prevents informed consent, making it easier for hidden persistence or supply-chain compromise to be introduced under the cover of a storage-management skill.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script downloads and installs an unrelated external binary (skill-quality-cli) even though the skill is described as managing Huawei OBS lifecycle policies via the hcloud CLI OBS module. This creates an unnecessary supply-chain and privilege/persistence risk because execution of the skill can modify the user's environment by fetching code from the network and placing executables in ~/.local/bin.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.