Back to skill

Security audit

lgd-badge-issuer

Security checks for vulnerabilities and agentic risk

Overview

The skill is a small badge-certificate issuer, but its core validation can issue authoritative-looking certificates from unverified or nonexistent evidence.

Review this carefully before relying on it for governance or compliance. It can be useful as a lightweight ledger/certificate generator, but do not treat its badges as proof that checks passed unless you add real evidence validation, trusted evaluator signatures, and pinned installation from a reviewed release.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/badge_issuer.py:30
Finding
Evidence Validation Can Be Bypassed to Issue Unsubstantiated Certificates## Vulnerability Details **File Location**: `scripts/badge_issuer.py`, lines 30-35 and 50-89 **Vulnerability Type**: Insufficient evidence validation and authorization gate bypass **Risk Level**: High ### Vulnerable Code ```python def load_evidence_ref(p: str) -> str: """证据引用:@文件/纯路径 → 内容哈希;否则按内联值哈希。""" q = p[1:] if p.startswith("@") else p if pathlib.Path(q).is_file(): return sha256_of(pathlib.Path(q).read_text(encoding="utf-8")) return sha256_of(p) ``` ```python # 三律门禁:每律至少 1 条证据 ev = {} laws_hit = set() for item in a.evidence: if "=" not in item: print(f"证据格式错误(应为 key=value):{item}", file=sys.stderr) sys.exit(2) k, v = item.split("=", 1) if not k.startswith(LAW_PREFIX): print(f"证据键须以 l1-/l2-/l3- 开头:{k}", file=sys.stderr) sys.exit(2) ev[k] = load_evidence_ref(v) laws_hit.add(k[:3]) missing = [l for l in ("l1-", "l2-", "l3-") if l not in laws_hit] reg_path = pathlib.Path(a.registry) reg = json.loads(reg_path.read_text(encoding="utf-8")) if reg_path.exists() else {"issued": [], "refused": []} def save_reg(): reg_path.parent.mkdir(parents=True, exist_ok=True) reg_path.write_text(json.dumps(reg, ensure_ascii=False, indent=2), encoding="utf-8") now = datetime.datetime.now().isoformat(timespec="seconds") if missing: rec = {"time": now, "holder": a.holder, "reason": "三律证据缺失: " + ",".join(missing)} reg["refused"].append(rec) save_reg() msg = f"⛔ 拒绝签发:三律证据缺失({'、'.join(missing)})— 已留痕台账" print(json.dumps({"issued": False, "holder": a.holder, "missing": missing, "note": msg}, ensure_ascii=False, indent=2) if a.json else msg) sys.exit(1) serial = len(reg["issued"]) + 1 cert = { "badge": BADGE, "serial": serial, "holder": a.holder, "issuer": ISSUER, "issued_at": now, "evidence_sha256": ev, } ``` ### Technical An ...[truncated 2426 chars]
Remediation
## Remediation Suggestions 1. Define a strict schema for each evidence type and reject unknown or malformed structures. 2. Reject empty evidence values and require minimum semantic content. 3. Treat values beginning with `@` as mandatory file references. If the referenced file does not exist, is not a regular file, cannot be decoded, or exceeds an appropriate size limit, terminate with an error. 4. Require each evidence record to contain an explicit successful outcome rather than inferring success from a key prefix. 5. Authenticate trusted gate reports using digital signatures or keyed message authentication, with signer identity and trust policy validation. 6. Bind evidence to the holder, policy version, evaluation timestamp, and relevant artifact digest to prevent evidence reuse. 7. Validate that the three records represent distinct required laws and originate from approved evaluators. 8. Add negative tests covering empty strings, nonexistent files, `false` values, malformed JSON, duplicate keys, untrusted signers, and evidence belonging to another holder. 9. Document that a digest provides integrity identification only and is not proof of authenticity or successful evaluation.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:76
Finding
Installation Instructions Use Mutable and Unpinned Supply-Chain Sources## Vulnerability Details **File Location**: `SKILL.md`, lines 76-81 **Vulnerability Type**: Unpinned package tooling and mutable repository installation **Risk Level**: Medium ### Vulnerable Code ```bash # 一键获取(skills CLI) npx skills add zhaoxinghua09-cell/agent-skills -g # 或手动:克隆后拷贝本技能到你的 Agent 技能目录 git clone https://github.com/zhaoxinghua09-cell/agent-skills.git cp -r agent-skills/skills/lgd-badge-issuer ~/.workbuddy/skills/ ``` ### Technical Analysis The documented installation paths do not pin immutable versions of the downloaded components: - `npx skills` does not specify a package version or verified package digest. - The repository clone does not specify a reviewed commit or signed release. - No checksum, signature, or expected tree digest is provided. - The first command installs content globally through the Skill CLI. - The repository is copied into an Agent Skill directory, where changed instructions or scripts may later be trusted and executed. Consequently, the content installed by users can differ from the artifact that was audited. A compromise of the package publication channel, source repository, maintainer account, or mutable default branch could introduce malicious instructions or executable files without changing these documented commands. This finding concerns the installation procedure. The reviewed Python implementation itself contains no third-party runtime dependency and was not found to retrieve or execute a remote payload. ### Attack Path 1. An attacker compromises the package publication account, the upstream repository, or a maintainer account, or otherwise causes a malicious version to be served through the mutable source. 2. The attacker adds altered Skill instructions or malicious scripts to the distributed package or default repository branch. 3. A user follows the documented `npx` or `git clone` installation command. 4. The installation resolves the current mutable versi ...[truncated 860 chars]
Remediation
## Remediation Suggestions 1. Pin the Skill CLI to a reviewed exact version, such as `npx package-name@X.Y.Z`, and verify the package integrity value. 2. Pin repository installations to an immutable commit hash or signed release tag. 3. Publish SHA-256 checksums or cryptographic signatures for released Skill artifacts and require verification before installation. 4. Retrieve only the specific Skill artifact rather than cloning and trusting an entire mutable repository. 5. Avoid global installation unless it is operationally required; prefer a least-privilege, project-local Skill directory. 6. Protect release accounts with multi-factor authentication, signed commits or tags, restricted publication rights, and auditable release automation. 7. Ensure documentation identifies the exact version and commit covered by a security audit. 8. Resolve the metadata inconsistency between `manifest.json`, which reports version `1.0.0`, and `SKILL.md`, which reports version `1.1.0`, so users can reliably identify the reviewed release.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Lp3

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding
The skill describes installation and operation patterns that imply filesystem interaction, but it does not declare any explicit tool or permission scope. In agent environments, missing scope declarations can cause the agent to run with broader default file read/write access than intended, increasing the risk of unintended modification or exfiltration of local files.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The file’s display names, description, operating guidance, and warnings are written in Chinese, and there is no indication that users may choose another language. This can violate a language/locale policy when a skill imposes a specific language without user opt-in.

Rp1

Medium
Category
MCP Rug Pull
Confidence
90% confidence
Finding
The installation instruction uses `npx skills` without pinning a specific package version or integrity mechanism. This creates a supply-chain risk: users may execute whatever version is current at install time, including a compromised or malicious upstream release.

Tainted flow: 'reg' from pathlib.Path.read_text (line 59, file read) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Content
def save_reg():
        reg_path.parent.mkdir(parents=True, exist_ok=True)
        reg_path.write_text(json.dumps(reg, ensure_ascii=False, indent=2), encoding="utf-8")

    now = datetime.datetime.now().isoformat(timespec="seconds")
    if missing:
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Tainted flow: 'cert' from pathlib.Path.read_text (line 76, file read) → pathlib.Path.write_text (file write)

Medium
Category
Data Flow
Content
if a.out:
        outp = pathlib.Path(a.out)
        outp.parent.mkdir(parents=True, exist_ok=True)
        outp.write_text(json.dumps(cert, ensure_ascii=False, indent=2), encoding="utf-8")

    if a.json:
        print(json.dumps({"issued": True, "cert": cert, "out": a.out}, ensure_ascii=False, indent=2))
Confidence
65% confidence
Finding
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Natural-Language Policy Violations

Low
Confidence
77% confidence
Finding
The manifest sets the category to "AI 治理", which forces a non-English label in the skill metadata. Because the file does not indicate that the skill is intentionally region-specific or provide a language/locale alternative, this can conflict with a language/locale policy requiring user choice or explicit justification.

Static analysis

No suspicious patterns detected.