Back to skill

Security audit

Aliyun Oss Static Deploy

Security checks for vulnerabilities and agentic risk

Overview

The skill is a mostly coherent static-site deployment helper, but it reaches into local GitHub credentials and persists TLS private keys in ways that deserve review before installation.

Review this skill before installing. Use a dedicated Aliyun RAM user and test bucket, confirm every public-access, DNS, certificate, FC, and GitHub repository change, set a narrowly scoped GITHUB_TOKEN explicitly, and do not let the helper read ~/.git-credentials. Store generated certificate keys under a protected account or adjust permissions yourself.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (3)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/set_github_secret.py:31
Finding
Automatic Access to the User's Plaintext GitHub Credential Store## Vulnerability Details **File Location**: `scripts/set_github_secret.py`, lines 31-40 **Vulnerability Type**: Excessive credential access and insecure credential discovery **Risk Level**: Medium ### Vulnerable Code ```python def get_token(): tok = os.environ.get("GITHUB_TOKEN", "") if tok: return tok cred = os.path.join(os.path.expanduser("~"), ".git-credentials") if os.path.exists(cred): m = re.search(r"(gh[oUp]_[A-Za-z0-9]+)", open(cred, encoding="utf-8", errors="replace").read()) if m: return m.group(1) sys.exit("Cannot obtain a GitHub token") ``` Related instructions also explicitly recommend extracting a token from the credential file in `SKILL.md`, lines 77-80: ```bash TOKEN=$(grep -o "gho_[A-Za-z0-9]*" ~/.git-credentials) curl --noproxy '*' -H "Authorization: Bearer $TOKEN" \ https://api.github.com/repos/<owner>/<repo>/actions/{secrets,variables} ``` ### Technical Analysis When `GITHUB_TOKEN` is absent, the helper automatically opens and reads the user's entire `~/.git-credentials` file. That file can contain plaintext credentials for multiple repositories, accounts, and Git hosting services. The regular expression selects the first token matching one of several GitHub token prefixes without verifying the credential's host, account, repository scope, or intended use. Reading a broad credential store is not required to set a GitHub Actions secret. The tool could instead require an explicitly supplied environment variable, standard input, or Git's credential-helper interface. The current behavior crosses a least-privilege boundary by accessing credentials unrelated to the requested operation. The token is subsequently placed in the `Authorization` header for requests to the fixed `https://api.github.com` endpoint. The reviewed implementation does not send the token to an arbitrary host and does not print ...[truncated 1181 chars]
Remediation
## Remediation Suggestions 1. Remove the automatic fallback that opens `~/.git-credentials`. 2. Require an explicitly supplied `GITHUB_TOKEN`, a secure standard-input option, or a recognized OS secret store. 3. If Git credential integration is necessary, use the Git credential-helper protocol and request credentials specifically for `github.com` rather than parsing the complete file. 4. Require fine-grained, repository-scoped tokens with only the Actions secrets or variables permissions needed for the requested operation. 5. Validate `--repo` against a strict `owner/repository` format before constructing an API path. 6. Document token requirements and fail closed when an explicit credential is unavailable.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/cert_manager.py:113
Finding
Unencrypted ACME and TLS Private Keys Created Without Explicit Restrictive Permissions## Vulnerability Details **File Location**: `scripts/cert_manager.py`, lines 113-149 **Vulnerability Type**: Insecure persistence of cryptographic private keys **Risk Level**: High ### Vulnerable Code ```python os.makedirs(CERT_DIR, exist_ok=True) if os.path.exists(ACCOUNT_KEY): acc_key = serialization.load_pem_private_key( open(ACCOUNT_KEY, "rb").read(), password=None) else: acc_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) open(ACCOUNT_KEY, "wb").write(acc_key.private_bytes( serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption())) ``` ```python if os.path.exists(PRIVKEY): cert_key = serialization.load_pem_private_key( open(PRIVKEY, "rb").read(), password=None) else: cert_key = rsa.generate_private_key(public_exponent=65537, key_size=2048) open(PRIVKEY, "wb").write(cert_key.private_bytes( serialization.Encoding.PEM, serialization.PrivateFormat.PKCS8, serialization.NoEncryption())) ``` ### Technical Analysis The certificate manager persistently writes both the ACME account private key and the issued certificate's private key using `serialization.NoEncryption()`. Persisting unencrypted keys may be necessary for unattended renewal, but the script does not explicitly protect the directory with mode `0700` or key files with mode `0600`. `os.makedirs()` and ordinary `open(..., "wb")` calls rely on the process umask. Under a permissive or commonly configured umask, the directory or files may be readable by other local users. Existing files are also loaded without checking ownership, file type, symbolic-link status, or permissions. The `.gitignore` entries for `*.pem` and `*.key` reduce accidental repository commits but do not protect files stored in the user's home directory from local disclosure. ### Attack Path 1. The user runs `cert_manager.py` to issue or renew a c ...[truncated 1528 chars]
Remediation
## Remediation Suggestions 1. Create the certificate base directory and each domain directory with mode `0700`. 2. Create private-key files atomically with exclusive creation and mode `0600`, such as by using `os.open()` with `O_CREAT`, `O_EXCL`, and `O_NOFOLLOW` where supported. 3. Apply `os.chmod(path, 0o600)` to existing private-key files after verifying that they are regular files owned by the current user. 4. Reject symbolic links and unexpected file ownership before reading or overwriting key material. 5. Write new keys to a secure temporary file in the same protected directory, flush and synchronize it, then atomically replace the target. 6. Warn or fail when existing key files have group or world permissions. 7. Where unattended operation permits, support encrypted key storage or integration with an OS key store, hardware-backed key provider, or managed certificate service. 8. Document that renewal jobs must run under a dedicated, minimally privileged account.

T08 · Insecure Dependencies

Note
Location
SKILL.md:23
Finding
Security-Critical Dependencies Installed Without Version or Hash Pinning## Vulnerability Details **File Location**: `SKILL.md`, line 23 **Vulnerability Type**: Uncontrolled third-party dependency resolution **Risk Level**: Low ### Vulnerable Code ```bash pip install oss2 acme josepy cryptography alibabacloud_alidns20150109 alibabacloud_cas20200407 alibabacloud_ram20150501 pynacl ``` Equivalent unpinned installation instructions also appear in `README.md`, lines 61-64: ```bash pip install oss2 acme josepy cryptography \ alibabacloud_alidns20150109 alibabacloud_cas20200407 \ alibabacloud_ram20150501 pynacl ``` ### Technical Analysis The installation instructions resolve the latest available versions of numerous third-party packages without a lock file, exact version constraints, or package hashes. The dependencies include cryptographic libraries and Alibaba Cloud SDKs that execute in a process holding DNS, CAS, OSS, FC, and potentially GitHub credentials. No confirmed malicious or misspelled package was identified in the reviewed instructions. The weakness is that future installations are not reproducible and implicitly trust mutable package-index state and dependency resolution. A compromised package release, transitive dependency, or package-index account could therefore introduce code that was not part of the audited Skill. Python packages may execute code during build or installation and will execute imported module code at runtime. Consequently, compromise can occur before or while the Skill performs its declared deployment tasks. ### Attack Path 1. A user follows the documented unrestricted `pip install` command. 2. The package resolver selects versions available at installation time rather than a reviewed dependency set. 3. A selected direct or transitive package has been compromised or contains a newly introduced vulnerability. 4. Malicious package code executes during installation, import, or API use. 5. If the Skill is then run in the same environment, the packa ...[truncated 742 chars]
Remediation
## Remediation Suggestions 1. Provide a reviewed dependency lock file with exact direct and transitive versions. 2. Include cryptographic hashes and install with: ```bash pip install --require-hashes -r requirements.txt ``` 3. Separate runtime and development dependencies and remove packages not used by the bundled scripts. 4. Define supported version ranges only where necessary, while deploying from a fully locked environment. 5. Use a trusted package index and explicitly document the expected index URL. 6. Add automated dependency vulnerability scanning and controlled update reviews. 7. Build and distribute dependencies through a reproducible, isolated environment rather than installing mutable latest versions directly into a credential-bearing host.
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (19)

Credential Access

High
Category
Privilege Escalation
Content
venv/
.DS_Store
Thumbs.db
.env
*.pem
*.key
state.json
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared purpose is OSS static deployment, but the skill also reads a local GitHub credential file and manages repository Actions secrets and variables through the GitHub API. This is a meaningful expansion of privilege and data access beyond what a user may reasonably expect from the description, creating a risk of secret harvesting or unauthorized CI configuration changes.

Missing User Warnings

High
Confidence
97% confidence
Finding
The instructions direct the operator to disable bucket-level public access protections to make the site anonymously readable, but they do not require an explicit warning or confirmation that this exposes content publicly on the internet. Removing public access blocks can unintentionally expose data if the wrong bucket, path, or account context is used.

Credential Access

High
Category
Privilege Escalation
Content
先查现状再动手,别猜(只能读名字,读不到值):

```bash
TOKEN=$(grep -o "gho_[A-Za-z0-9]*" ~/.git-credentials)
curl --noproxy '*' -H "Authorization: Bearer $TOKEN" \
  https://api.github.com/repos/<owner>/<repo>/actions/{secrets,variables}
```
Confidence
99% confidence
Finding
The instruction to grep ~/.git-credentials for a GitHub token is direct credential access to a local secret store. In an agent context this is dangerous because it can silently harvest reusable credentials, expand access far beyond the current task, and enable unauthorized reads or writes to repositories and CI settings.

Credential Access

High
Category
Privilege Escalation
Content
依赖:pip install pynacl

用法:
    export GITHUB_TOKEN=ghp_xxx          # 或自动从 ~/.git-credentials 读
    python set_github_secret.py --repo owner/repo --list
    python set_github_secret.py --repo owner/repo --name OSS_ACCESS_KEY_ID --value "$AK_ID"
    python set_github_secret.py --repo owner/repo --name OSS_BUCKET --value my-bucket --variable
Confidence
91% confidence
Finding
The documented behavior explicitly advertises automatic token retrieval from ~/.git-credentials, normalizing credential collection beyond the script's core purpose. In a deployment skill that may run on developer machines or CI runners, this increases the risk of unintended credential access and subsequent modification of GitHub Actions secrets across repositories reachable by the token.

Credential Access

High
Category
Privilege Escalation
Content
tok = os.environ.get("GITHUB_TOKEN", "")
    if tok:
        return tok
    cred = os.path.join(os.path.expanduser("~"), ".git-credentials")
    if os.path.exists(cred):
        m = re.search(r"(gh[oUp]_[A-Za-z0-9]+)",
                      open(cred, encoding="utf-8", errors="replace").read())
Confidence
98% confidence
Finding
The code directly opens ~/.git-credentials and extracts a GitHub token via regex, which is credential access behavior. Even if intended for convenience, this is risky because the skill can silently consume stored credentials and use them to write secrets or variables to repositories, potentially altering CI/CD behavior or enabling persistence.

Credential Access

High
Category
Privilege Escalation
Content
open(cred, encoding="utf-8", errors="replace").read())
        if m:
            return m.group(1)
    sys.exit("拿不到 GitHub token:设置 GITHUB_TOKEN 或确认 ~/.git-credentials 里有凭据")


def req(method, path, token, data=None):
Confidence
90% confidence
Finding
The error message instructs users to ensure credentials exist in ~/.git-credentials, reinforcing and encouraging the insecure credential-sourcing behavior. While this line alone does not access credentials, in context it supports a workflow that promotes broad reuse of locally stored tokens by automation.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The activation phrases are broad and overlap with common deployment-related language, which can cause the skill to trigger in situations the user did not specifically intend. In an agent setting, overbroad triggering can lead to unintended cloud, DNS, certificate, or CI/CD actions with real operational consequences.

Skill Enumeration

Medium
Category
Agent Snooping
Content
下载仓库 zip,解压后把整个文件夹放到技能目录下,保证路径是:

```
~/.workbuddy/skills/aliyun-oss-static-deploy/SKILL.md
~/.workbuddy/skills/aliyun-oss-static-deploy/scripts/cert_manager.py
~/.workbuddy/skills/aliyun-oss-static-deploy/scripts/set_github_secret.py
```
Confidence
80% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill instructs the agent to access environment variables, perform shell commands, write files, and make network calls, but it declares no tool scope or permission boundaries. In an agent environment, this increases the chance of unintended credential access, file modification, and outbound requests without explicit user awareness or sandbox constraints.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The trigger phrases are broad and overlap with common deployment requests, making accidental invocation more likely in contexts where the user did not intend OSS deployment, public exposure, certificate operations, or GitHub configuration. In agent systems, over-broad routing can cause sensitive actions to be proposed or performed under an imprecise match.

Missing User Warnings

Medium
Confidence
99% confidence
Finding
The skill instructs reading a GitHub token from ~/.git-credentials without an explicit safety warning or user consent step. Accessing local credential stores is sensitive because it can expose tokens unrelated to the requested deployment target and enable repository modification, secret management, or broader account actions.

External Transmission

Medium
Category
Data Exfiltration
Content
```bash
TOKEN=$(grep -o "gho_[A-Za-z0-9]*" ~/.git-credentials)
curl --noproxy '*' -H "Authorization: Bearer $TOKEN" \
  https://api.github.com/repos/<owner>/<repo>/actions/{secrets,variables}
```

- **Variables**(明文,直接 POST):`OSS_BUCKET`、`OSS_REGION`。
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
Natural-language content in the manifest is predominantly Chinese, including user-facing metadata and activation phrases, but the file does not indicate that the skill is intended only for Chinese-speaking users or provide an opt-in language choice. This can violate language/locale policy when a skill implicitly constrains interaction language without explicit justification.

Vague Triggers

Medium
Confidence
93% confidence
Finding
Several trigger phrases are generic deployment requests such as '部署到 OSS', '静态站上线', and '绑定自定义域名', which can cause the skill to activate for broad, loosely related user intents. In an agent system, over-broad routing can misapply deployment guidance, cause unintended cloud operations, or expose users to risky infrastructure changes when they asked for more general help.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The docstring promises sensitive material is only read from environment variables and never written to disk, but the script stores the ACME account key, certificate private key, certificate chain, and state data under ~/.acme-oss. Persisting private keys locally increases exposure if the host is multi-user, compromised, backed up insecurely, or has permissive file permissions; the misleading claim may also cause operators to underestimate that risk.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
for _ in range(max(1, timeout // 20)):
        try:
            out = subprocess.run(
                ["nslookup", "-type=TXT", fqdn, "223.5.5.5"],
                capture_output=True, text=True, timeout=40,
            ).stdout
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The script automatically reads a GitHub token from ~/.git-credentials when GITHUB_TOKEN is not set, which expands its capability from using explicitly supplied credentials to harvesting locally stored credentials. In an agent skill context, this is dangerous because it can silently use sensitive tokens the user did not intend to expose to the skill, enabling unauthorized repository secret or variable changes.

Description-Behavior Mismatch

Low
Confidence
90% confidence
Finding
The manifest frames the skill as deploying pure static sites to Aliyun OSS with custom domains, HTTPS, and GitHub Actions. However, the README states that `scripts/cert_manager.py` also binds certificates to `FC` custom domains, which extends beyond OSS static-site deployment into Function Compute infrastructure management.

Static analysis

No suspicious patterns detected.