Back to skill

Security audit

Alibabacloud Sas Multiaccount Manage

Security checks for vulnerabilities and agentic risk

Overview

The skill matches its Alibaba Cloud report-export purpose, but it handles downloaded ZIP reports too unsafely for automatic trust.

Install only if you trust the publisher and will run it in a dedicated working directory with least-privilege Alibaba Cloud RAM credentials. Avoid system-wide pip installs, expect sensitive security reports to be written locally, and review or harden the ZIP download/extraction logic before using it in shared or important workspaces.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/baseline.py:138
Finding

Unrestricted Download and Extraction of Remotely Supplied Archives

Content
View full analysis

Vulnerability Details

File Location: scripts/baseline.py:138-165; scripts/vuln.py:176-200
Vulnerability Type: Unsafe remote archive handling
Risk Level: High

Vulnerable Code

scripts/baseline.py:

python
async def download_and_extract_async(link, account_id, prefix):
    """Asynchronously download a ZIP, extract it, and rename it."""
    zip_path = Path(f"{prefix}-{account_id}-{TODAY}.zip")
    print(f"  [download] account {account_id}...")

    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, _download_with_timeout, link, zip_path)

    with zipfile.ZipFile(zip_path) as zf:
        names = zf.namelist()
        zf.extractall(path=zip_path.parent)
        extracted = zip_path.parent / names[0]

    output_path = Path(f"{prefix}-{account_id}-{TODAY}.xlsx")
    if extracted != output_path:
        extracted.rename(output_path)
    if zip_path.exists():
        zip_path.unlink()

    return str(output_path)


def _download_with_timeout(link, output_path):
    """Download a file with a timeout."""
    with urllib.request.urlopen(link, timeout=DOWNLOAD_TIMEOUT_SECONDS) as response:
        with Path(output_path).open("wb") as fp:
            shutil.copyfileobj(response, fp)

scripts/vuln.py:

python
async def download_and_extract_async(link, account_id, prefix):
    """Download a ZIP, extract it, and rename it."""
    zip_path = Path(f"{prefix}-{account_id}-{TODAY}.zip")
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, _download_with_timeout, link, zip_path)

    with zipfile.ZipFile(zip_path) as zf:
        names = zf.namelist()
        zf.extractall(path=zip_path.parent)
        extracted = zip_path.parent / names[0]

    output_path = Path(f"{prefix}-{account_id}-{TODAY}.xlsx")
    if extracted != output_path:
        extracted.rename(output_path)
    if zip_path.exists():
        zip_path.unlink(
...[truncated 2838 chars]
Remediation
View remediation

Remediation Suggestions

  1. Parse the returned URL and require https.
  2. Allowlist the documented Alibaba Cloud export domains and reject redirects to unapproved hosts.
  3. Stream the response while enforcing a strict maximum compressed size.
  4. Open the archive before extraction and require exactly one expected regular .xlsx member.
  5. Reject absolute paths, parent-directory components, nested paths, symbolic links, duplicate names, and non-workbook extensions.
  6. Calculate the declared total expanded size and reject archives exceeding a conservative limit.
  7. Extract only the validated member rather than calling extractall.
  8. Use tempfile.TemporaryDirectory with restrictive permissions and move the validated workbook to the final location only after successful inspection.
  9. Refuse to overwrite existing output files unless the user explicitly requests replacement.
  10. Delete partial downloads and extracted files in a finally block.
  11. Apply the same hardened helper to both baseline.py and vuln.py.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/baseline.py:140
Finding

Unvalidated Account IDs Are Incorporated into Filesystem Paths

Content
View full analysis

Vulnerability Details

File Location: scripts/baseline.py:140-154, 286-288, 312-314; scripts/vuln.py:178-190, 277-280
Vulnerability Type: Path manipulation through unvalidated input
Risk Level: Medium

Vulnerable Code

scripts/baseline.py:

python
async def download_and_extract_async(link, account_id, prefix):
    """Asynchronously download a ZIP, extract it, and rename it."""
    zip_path = Path(f"{prefix}-{account_id}-{TODAY}.zip")
    print(f"  [download] account {account_id}...")

    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, _download_with_timeout, link, zip_path)

    with zipfile.ZipFile(zip_path) as zf:
        names = zf.namelist()
        zf.extractall(path=zip_path.parent)
        extracted = zip_path.parent / names[0]

    output_path = Path(f"{prefix}-{account_id}-{TODAY}.xlsx")
    if extracted != output_path:
        extracted.rename(output_path)
    if zip_path.exists():
        zip_path.unlink()

    return str(output_path)
python
def cmd_export_cspm(args):
    if args.account_id:
        account_ids = [args.account_id]
    else:
        accounts = get_enabled_accounts()
        account_ids = [a["AccountId"] for a in accounts]

scripts/vuln.py:

python
async def download_and_extract_async(link, account_id, prefix):
    """Download a ZIP, extract it, and rename it."""
    zip_path = Path(f"{prefix}-{account_id}-{TODAY}.zip")
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, _download_with_timeout, link, zip_path)

    with zipfile.ZipFile(zip_path) as zf:
        names = zf.namelist()
        zf.extractall(path=zip_path.parent)
        extracted = zip_path.parent / names[0]

    output_path = Path(f"{prefix}-{account_id}-{TODAY}.xlsx")
    if extracted != output_path:
        extracted.rename(output_path)
    if zip_path.exists():
        zip_path.unlink()
   
...[truncated 2242 chars]
Remediation
View remediation

Remediation Suggestions

  1. Validate every account ID at the input boundary using the documented numeric format, for example ^[0-9]{6,32}$.
  2. Apply validation to command-line values and entries loaded from accounts.json.
  3. Store all generated artifacts under a dedicated output directory.
  4. Resolve both the output directory and candidate path before use.
  5. Verify that each candidate path remains beneath the output directory using Path.is_relative_to() or an equivalent check.
  6. Generate temporary filenames independently of user input, such as with tempfile.NamedTemporaryFile.
  7. Avoid deleting or replacing an existing file unless it was created by the current execution.
  8. Centralize path construction and validation in one helper shared by both export scripts.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/baseline.py:120
Finding

Export Status Polling Has No Overall Deadline

Content
View full analysis

Vulnerability Details

File Location: scripts/baseline.py:120-136; scripts/vuln.py:159-174
Vulnerability Type: Unbounded authenticated polling
Risk Level: Low

Vulnerable Code

scripts/baseline.py:

python
async def wait_for_export_async(export_id, account_id, poll_interval=5):
    """Poll export status and return the download link after success."""
    while True:
        cli_args = [
            "describe-export-info",
            "--export-id", export_id,
        ]
        if account_id != _caller_account_id:
            cli_args += ["--resource-directory-account-id", str(account_id)]
        data = await _run_aliyun_async(cli_args, account_id)
        status = data.get("ExportStatus", "")

        if status == "success":
            return data["Link"]
        if status in ("failed", "error"):
            raise RuntimeError(
                f"Account {account_id} export failed, status={status}"
            )
        await asyncio.sleep(poll_interval)

scripts/vuln.py:

python
async def wait_for_export_async(export_id, account_id, poll_interval=5):
    """Poll vulnerability export status and return its link."""
    while True:
        cli_args = [
            "describe-vul-export-info",
            "--force",
            "--export-id", export_id,
        ]
        if account_id != _caller_account_id:
            cli_args += ["--resource-directory-account-id", str(account_id)]
        data = await _run_aliyun_async(cli_args, account_id)
        status = data.get("ExportStatus", "")
        if status == "success":
            return data["Link"]
        if status in ("failed", "error"):
            raise RuntimeError(
                f"Account {account_id} export failed, status={status}"
            )
        await asyncio.sleep(poll_interval)

Technical Analysis

Each individual CLI request has connection and read timeou ...[truncated 1233 chars]

Remediation
View remediation

Remediation Suggestions

  1. Add a configurable overall export deadline.
  2. Enforce a maximum number of polling attempts.
  3. Recognize only explicitly documented pending and terminal states; fail closed on unknown states.
  4. Use exponential backoff with bounded jitter rather than a constant polling interval.
  5. Handle task cancellation and keyboard interruption cleanly.
  6. Return a nonzero process status when no requested export completes.
  7. Clean up partial downloads and temporary files after timeout or cancellation.

T08 · Insecure Dependencies

Warning
Location
scripts/pyproject.toml:5
Finding

Dependency Installation Is Not Cryptographically Reproducible

Content
View full analysis

Vulnerability Details

File Location: scripts/pyproject.toml:5-11; scripts/requirements.txt:1-5; SKILL.md:60-71
Vulnerability Type: Unbounded and unhashed dependency installation
Risk Level: Medium

Vulnerable Code

scripts/pyproject.toml:

toml
requires-python = ">=3.6"
dependencies = [
    "openpyxl>=3.1.5",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

scripts/requirements.txt:

text
et_xmlfile==2.0.0
numpy==2.4.4
openpyxl==3.1.5
python-dateutil==2.9.0.post0
six==1.17.0

SKILL.md:

bash
cd scripts/

# Option A: use venv
python3 -m venv .venv
.venv/bin/pip install -e .

# Option B: use uv (optional)
uv sync

# Option C: if current Python version is unsupported, install as system dependencies
pip install -r requirements.txt

Technical Analysis

The primary editable-install path permits any future openpyxl version equal to or newer than 3.1.5. The build backend dependency, hatchling, is also unbounded. Although requirements.txt uses exact versions, it does not provide artifact hashes.

Python package installation can execute build-backend and package installation code. Without a reviewed lock file, exact build-backend versions, trusted-index controls, and cryptographic hashes, the effective code installed at runtime may differ from what was audited.

This is a supply-chain hardening deficiency rather than evidence that the currently named packages are malicious. No typosquatted package name or known malicious dependency was identified in the reviewed manifests.

Attack Path

  1. A package index account, release artifact, dependency source, or configured package index is compromised.
  2. A malicious future release satisfies openpyxl>=3.1.5, or a malicious build-backend release satisfies the unbounded hatchling requirement.
  3. The user follows the documented pip install -e . workflow. ...[truncated 935 chars]
Remediation
View remediation

Remediation Suggestions

  1. Generate and commit a reviewed lock file containing exact versions and hashes.
  2. Pin openpyxl, hatchling, and all transitive dependencies to audited versions.
  3. Use pip install --require-hashes -r requirements.txt for the pip workflow.
  4. Configure a trusted package index explicitly and disable unexpected extra indexes.
  5. Keep dependency updates automated but require review and security scanning before lock-file changes are accepted.
  6. Avoid recommending system-wide installation; require an isolated virtual environment.
  7. Ensure the dependency manifests are consistent so every documented installation method resolves to the same audited package set.
Vulnerability Patterns
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (14)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code clearly supports part of the declared description: it uses aliyun CLI plus Python to batch-export SAS baseline-related reports for multiple enabled accounts and merges the resulting Excel files. However, the declared purpose is broader than the supplied code. This chunk does not implement account management operations such as refreshing account lists or enabling/disabling accounts, and it does not export vulnerability report categories mentioned in the description. Its actual scope is limited to two baseline/system-warning export commands. Because significant declared capabilities are absent from the provided code chunk, the description does not accurately represent what this specific code actually does.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a broad operational tool for managing multiple Alibaba Cloud accounts and exporting SAS baseline/vulnerability reports. In contrast, the supplied code only merges existing Excel files from disk and adds a 'resource management account' column. While report merging is mentioned in the description, this chunk lacks the core advertised behaviors and resources: no cloud authentication, no account administration, no export logic, and no SAS-specific processing. Therefore the code chunk does not accurately represent the declared primary purpose and is materially narrower and different.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The code is narrowly focused on vulnerability export workflows via aliyun sas commands: export-vul and describe-vul-export-info, for four vulnerability types. It supports multi-account operation by reading enabled accounts and optionally targeting a single account, then merges exported Excel files. However, the declared description says the skill also manages multi-account settings (refresh, enable/disable) and exports baseline/configuration reports such as baselineCspm and exportHcWarning. None of those baseline-export or account-management behaviors are present in this supplied code chunk. While importing account helpers suggests integration with broader tooling, this specific chunk does not implement those declared capabilities, so the description overstates what the provided code actually does.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill documents shell, network, file-read, and file-write behavior but does not declare any explicit tool scope such as permissions or allowed-tools. In an agent setting, this weakens least-privilege controls and can let the skill be invoked with broader capabilities than a user or platform reviewer would expect, including writing files and making cloud/API calls.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill writes downloaded multi-account security reports into the current working directory and deletes temporary extracted files, but this side effect is not highlighted as an explicit warning near the skill description. Because the data includes security posture and vulnerability results across accounts, unexpected local writes or cleanup can expose sensitive data, overwrite user expectations about where files appear, or cause accidental handling in shared workspaces.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/accounts.py (reported line 56)May include surrounding context.

python
region_id = getattr(args, "region_id", "cn-shanghai")

    # 获取当前凭证的主账号(自身也应包含在可操作范围内)
    identity_result = subprocess.run(
        _aliyun_cmd("sts", "get-caller-identity"),
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/accounts.py (reported line 67)May include surrounding context.

python
sys.exit(1)
    caller_account_id = str(json.loads(identity_result.stdout)["AccountId"])

    result = subprocess.run(
        _aliyun_cmd("sas", "--region", region_id, "list-accounts-in-resource-directory"),
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/accounts.py (reported line 81)May include surrounding context.

python
accounts = data.get("Accounts", [])

    # 调用 describe-monitor-accounts,只保留已纳入监控的账号(并将自身主账号也包含进来)
    monitor_result = subprocess.run(
        _aliyun_cmd("sas", "--region", region_id, "describe-monitor-accounts"),
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/accounts.py (reported line 164)May include surrounding context.

python
def get_caller_account_id():
    """获取当前凭证的主账号 ID(通过 aliyun sts get-caller-identity)。"""
    result = subprocess.run(
        _aliyun_cmd("sts", "get-caller-identity"),
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The command arguments hard-code --lang zh, which imposes a specific language on all users. Under the policy, locale constraints should either be optional/opt-in or clearly justified as region-specific; this code does neither.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This code file contains natural-language instructions and runtime messages that consistently force Chinese for usage, errors, warnings, and success output. Under the policy, language restrictions should be optional or clearly justified as region-specific; no such opt-in or justification is present here.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The export configuration hard-codes --lang zh for all export types, which enforces a specific language/locale choice. The CLI exposes region selection but provides no user option to choose export language or consent to the locale constraint.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

This code file contains natural-language strings and help text entirely in Chinese, including the module docstring and CLI usage/help output. Under the policy, forcing a specific language without user opt-in can be a locale-policy violation when no alternative language option or justification is provided.

Content

No source excerpt is available for this finding.

Unverifiable Dependency: openpyxl has 2 known advisory(ies) (CVE-2017-5992 (Improper Restriction of XML External Entity Reference in Openpyxl); CVE-2017-5992 (Openpyxl 2.4.1 resolves external entities by default, which allows remote attack)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.