Back to skill

Security audit

cert lifecycle harness

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent and mostly transparent, but its install/update path and some production certificate runbook templates need careful review before use.

Install only from a pinned, reviewed release or commit, not the mutable npx/GitHub examples. Before using generated production scripts, require a human security review of secret handling, rollback, deletion steps, sudo commands, and Kubernetes/JKS templates; prefer fixing the unsafe templates before allowing agent-assisted execution.

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)

T08 · Insecure Dependencies

Error
Location
README.md:21
Finding
Unpinned npx Installer and Mutable Skill Update Chain<![CDATA[ ## Vulnerability Details **File Location**: `README.md:21-28` **Additional Locations**: `README.zh-CN.md:22-29`, `scripts/version-check.sh:43-45`, `SKILL.md:510-519` **Vulnerability Type**: Unpinned third-party dependency execution **Risk Level**: High ### Vulnerable Code ```bash # global install (all projects) npx skills add dimayip/cert-lifecycle-harness -g -a claude-code # project-only install (current repo) npx skills add dimayip/cert-lifecycle-harness -a codebuddy ``` The version-check script also constructs a mutable update command: ```bash REPO_API="https://api.github.com/repos/dimayip/cert-lifecycle-harness/releases/latest" UPDATE_CMD="npx skills add https://github.com/dimayip/cert-lifecycle-harness" ``` The skill permits the agent to execute the returned command after a user asks it to update: ```markdown - ✅ If the user explicitly says "help me update" → the Agent executes `<UPDATE_CMD>` and verifies it. ``` ### Technical Analysis The installation instructions invoke `npx` without pinning the `skills` command-line package to an exact audited version. Depending on the local npm configuration and cache state, `npx` may retrieve and execute the current package version and its transitive dependencies. The skill source is also identified using a mutable repository reference instead of a release tag, commit SHA, signed artifact, or verified checksum. Consequently, the code executed during installation or update can differ from the code reviewed in this audit. Although explicit user approval is required before the agent performs an update, approval does not address supply-chain integrity. The user authorizes an operation whose effective code remains remotely mutable. ### Attack Path 1. An attacker compromises the npm package used by `npx`, one of its transitive dependencies, the associated publisher account, or the referenced source repository. 2. The attacker publishes or inserts malicious installer or skill content. 3. A user fo ...[truncated 1080 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin the installer to an exact audited version: ```bash npx --yes skills@<audited-version> add ... ``` 2. Pin the skill source to a reviewed commit SHA or signed release tag rather than the repository's mutable default branch. 3. Publish checksums or signatures for release artifacts and verify them before installation. 4. Prefer a review-first installation flow: - Download the release archive without executing it. - Verify its signature and checksum. - Inspect its contents. - Copy it into the skill directory only after verification. 5. Make automatic version checks and update recommendations opt-in. 6. Never execute an update command obtained from remotely returned or locally cached text without reconstructing it from trusted constants and presenting the exact pinned target to the user. 7. Document the package registry, expected publisher identity, package version, repository commit, and verification procedure. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
phases/runbook-templates/k8s-secret-rollover.sh.tpl.md:28
Finding
Kubernetes TLS Private Key Exported to Predictable Insecure Temporary File<![CDATA[ ## Vulnerability Details **File Location**: `phases/runbook-templates/k8s-secret-rollover.sh.tpl.md:28-30` **Related Rollback Location**: `phases/runbook-templates/k8s-secret-rollover.sh.tpl.md:53-57` **Vulnerability Type**: Plaintext sensitive-data exposure and unsafe temporary-file handling **Risk Level**: High ### Vulnerable Code ```bash # ---- 1. Backup ---- kubectl -n "$NAMESPACE" get secret "$SECRET_NAME" -o yaml \ > "/tmp/secret-backup-$SECRET_NAME-$(date +%Y%m%d-%H%M).yaml" # ---- 2. Replace Secret in place ---- kubectl -n "$NAMESPACE" create secret tls "$SECRET_NAME" \ --cert="$NEW_CERT" --key="$NEW_KEY" \ --dry-run=client -o yaml | kubectl apply -f - ``` The rollback procedure uses a wildcard rather than the exact backup created by the run: ```bash kubectl -n "$NAMESPACE" apply -f /tmp/secret-backup-$SECRET_NAME-*.yaml kubectl -n ingress-nginx rollout restart deployment/ingress-nginx-controller ``` ### Technical Analysis A Kubernetes TLS Secret contains `tls.crt` and `tls.key` values encoded with base64. Base64 is not encryption; anyone who reads the YAML backup can recover the private key. The template writes this material into `/tmp` using a predictable filename. It does not: - Set `umask 077`. - Create a private directory with mode `0700`. - Create the file atomically with `mktemp`. - Explicitly enforce mode `0600`. - Encrypt the backup. - Validate the backup before rollback. - Delete the backup after the retention window. - Store and reuse the exact backup filename. The rollback wildcard can match multiple stale files. It may therefore restore an obsolete Secret, produce ambiguous command behavior, or select a file placed by another local process. The exact consequences depend on shell expansion and the number of matching files. ### Attack Path 1. An authorized operator executes the generated rollover script on a shared or insufficiently isolated workstation or administration host. 2. `kubectl get secret -o yaml` exp ...[truncated 1291 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Avoid exporting the Secret to local plaintext storage where possible. Use an encrypted, access-controlled, versioned secret store or the platform's approved backup mechanism. 2. If a local backup is unavoidable, create it securely: ```bash umask 077 BACKUP_DIR="$(mktemp -d "${TMPDIR:-/tmp}/tls-secret-backup.XXXXXX")" chmod 700 "$BACKUP_DIR" BACKUP_FILE="$BACKUP_DIR/secret.yaml" kubectl -n "$NAMESPACE" get secret "$SECRET_NAME" -o yaml > "$BACKUP_FILE" chmod 600 "$BACKUP_FILE" ``` 3. Save the exact backup filename and use only that path for rollback. Do not use wildcards. 4. Validate file ownership, mode, checksum, namespace, Secret name, and Secret type before applying the backup. 5. Add a cleanup trap and an explicit retention policy. If secure deletion cannot be guaranteed, use encrypted temporary storage. 6. Remove unnecessary metadata from the backup and never log its contents. 7. Verify that the certificate and private key match before applying them. 8. Use a dedicated kubeconfig and narrowly scoped RBAC permissions limited to the named Secret and required namespace. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
phases/runbook-templates/jks-rollover.sh.tpl.md:38
Finding
JKS and PKCS12 Passwords Exposed Through Process Arguments<![CDATA[ ## Vulnerability Details **File Location**: `phases/runbook-templates/jks-rollover.sh.tpl.md:38-55` **Additional Location**: `phases/runbook-templates/jks-rollover.sh.tpl.md:71-73` **Vulnerability Type**: Secret exposure through command-line arguments **Risk Level**: High ### Vulnerable Code ```bash # ---- 1. Baseline snapshot ---- BACKUP_DIR="/var/backups/jks/$(date +%Y%m%d-%H%M)" sudo mkdir -p "$BACKUP_DIR" sudo cp "$KEYSTORE_PATH" "$BACKUP_DIR/keystore.jks.bak" sudo keytool -list -v -keystore "$BACKUP_DIR/keystore.jks.bak" -storepass "$JKS_PASS" \ > "$BACKUP_DIR/before.txt" # ---- 2. Delete old alias ---- sudo keytool -delete -alias "$ALIAS" \ -keystore "$KEYSTORE_PATH" \ -storepass "$JKS_PASS" # ---- 3. Import new certificate ---- sudo keytool -importkeystore \ -srckeystore "$NEW_P12" -srcstoretype PKCS12 -srcstorepass "$P12_PASS" \ -destkeystore "$KEYSTORE_PATH" -deststoretype JKS -deststorepass "$JKS_PASS" \ -alias "$ALIAS" ``` The self-verification step repeats the exposure: ```bash sudo keytool -list -v -keystore "$KEYSTORE_PATH" -storepass "$JKS_PASS" \ | grep -A5 "$ALIAS" ``` ### Technical Analysis The template correctly avoids hardcoding passwords, but it passes `JKS_PASS` and `P12_PASS` directly as command-line arguments. Secrets placed in process arguments can be exposed to: - Local process inspection facilities. - Privileged monitoring or endpoint agents. - Audit frameworks that record executed command lines. - Diagnostic collection tools. - Shell tracing if later enabled around the script. - Process accounting or incident-response snapshots. Using environment variables as the initial source does not protect a secret after it is expanded into `keytool` arguments. The repeated `sudo keytool` invocations increase the number of exposure windows. The precise visibility of another user's process arguments varies by operating-system configuration. Nevertheless, privileged monitoring and audit systems can commonly ca ...[truncated 1393 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Use `keytool` password-file mechanisms instead of literal command-line passwords where supported, such as protected files referenced through the applicable `:file` option syntax. 2. Create password files in a private runtime directory with: - `umask 077` - Directory mode `0700` - File mode `0600` - Exact ownership validation - Cleanup through an `EXIT`, `INT`, and `TERM` trap 3. If the installed Java version supports an appropriate non-argv protected mechanism, use it and document the minimum supported version. 4. Avoid `set -x` and ensure wrappers, CI systems, and monitoring tools do not log secret-bearing commands or environments. 5. Use short-lived, operation-specific passwords where feasible and rotate affected passwords after the change. 6. Avoid password reuse across hosts, environments, JKS files, and PKCS12 bundles. 7. Update the self-review checklist to explicitly reject secrets in process arguments, not merely hardcoded or on-disk credentials. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
phases/runbook-templates/jks-rollover.sh.tpl.md:34
Finding
Unvalidated Signal and PID Used in Privileged Process Control<![CDATA[ ## Vulnerability Details **File Location**: `phases/runbook-templates/jks-rollover.sh.tpl.md:34-35,57-66` **Additional Location**: `phases/runbook-templates/jks-rollover.sh.tpl.md:76-80` **Vulnerability Type**: Insufficient input validation for privileged process signaling **Risk Level**: Medium ### Vulnerable Code ```bash : "${APP_PID_FILE:?e.g. /var/run/legacy-app.pid}" : "${RELOAD_SIGNAL:=HUP}" # Expected: HUP / USR1 / USR2 # ---- 4. Hot reload ---- APP_PID=$(cat "$APP_PID_FILE") sudo kill -"$RELOAD_SIGNAL" "$APP_PID" sleep 5 # ---- 5. Verification ---- if ! curl -sk --resolve "${HEALTH_URL#*//}:443:127.0.0.1" "$HEALTH_URL" | grep -q "ok"; then echo "🔴 Verification failed, starting rollback" sudo cp -a "$BACKUP_DIR/keystore.jks.bak" "$KEYSTORE_PATH" sudo kill -"$RELOAD_SIGNAL" "$APP_PID" exit 1 fi ``` The standalone rollback command repeats the same behavior: ```bash sudo cp -a "$BACKUP_DIR/keystore.jks.bak" "$KEYSTORE_PATH" sudo kill -"$RELOAD_SIGNAL" "$(cat $APP_PID_FILE)" ``` ### Technical Analysis The comments describe `HUP`, `USR1`, and `USR2` as the intended signals, but the script does not enforce that allowlist. A caller can supply another valid signal such as `TERM` or `KILL`, changing a reload operation into process termination. The PID is read from a caller-selected file without validating that: - It contains exactly one positive numeric PID. - The PID belongs to the expected application. - The process executable or command line matches the intended service. - The PID file is securely owned and not writable by an untrusted user. - The PID has not been reused since the file was written. Quoting prevents ordinary shell-metacharacter command injection in these variables, but it does not prevent misuse of valid `kill` options or signaling the wrong process. Because `sudo` is used, the signal may be delivered with elevated privileges. ### Attack Path 1. An attacker or misconfiguration controls `RELOAD_SIGNAL`, `APP ...[truncated 1114 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce a strict signal allowlist before any privileged operation: ```bash case "$RELOAD_SIGNAL" in HUP|USR1|USR2) ;; *) echo "Unsupported reload signal" >&2; exit 2 ;; esac ``` 2. Require the PID file to be an absolute path under an approved directory. 3. Validate ownership, permissions, and non-symlink status of the PID file. 4. Require its content to match a single positive integer: ```bash [[ "$APP_PID" =~ ^[1-9][0-9]*$ ]] || exit 2 ``` 5. Confirm the process identity using `/proc/$APP_PID/exe`, the service manager, or another platform-appropriate mechanism before signaling it. 6. Prefer `systemctl reload <fixed-service-name>` or an application-specific reload command over arbitrary PID signaling. 7. Configure sudoers for the narrowest fixed command possible rather than granting general `kill` capability. 8. Repeat all validation in the standalone rollback path; do not assume values validated by a previous shell remain trustworthy. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (91)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill’s declared purpose is certificate lifecycle guidance, but it also introduces update-check logic, GitHub API access, and local metadata/cache handling that are unrelated to the stated operational goal. Undeclared maintenance/network behavior increases attack surface and can leak environment or network metadata in contexts where users expect a bounded PKI workflow assistant.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill’s declared purpose is certificate lifecycle guidance, but it also introduces update-check logic, GitHub API access, and local metadata/cache handling that are unrelated to the stated operational goal. Undeclared maintenance/network behavior increases attack surface and can leak environment or network metadata in contexts where users expect a bounded PKI workflow assistant.

Ae1

High
Category
analysis-evasion
Content
| `skipped` | 本地 `SKILL.md` 未找到 `version` 字段 | ✅ 沉默,直接进入 Phase 0 |
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
| 每次进入 Phase 0 前 | `scripts/version-check.sh`(静默执行,失败不阻塞,见 §11.4)|
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The intake document authorizes the Agent to send approval-test requests and test alerts, which are operational actions rather than passive information gathering. In a certificate-management context, unsolicited coordination or alerting can trigger real workflows, create audit noise, confuse responders, and condition the Agent to act on external systems before formal planning and approvals are complete.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The template contains an explicit destructive delete operation (`keytool -delete`) even though the skill metadata says it should never execute Delete before writes. In this context, the delete happens before the replacement import is proven successful, creating a dangerous outage window where the keystore may be left without the required alias if the import fails.

Chaining Abuse

High
Category
Tool Misuse
Content
```bash
sudo cp -a "$BACKUP_DIR/$CERT_NAME".* "$NGINX_SSL_DIR/"
sudo nginx -t && sudo systemctl reload nginx
```
Confidence
75% confidence
Finding
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The guide explicitly includes and operationalizes a `cleanup-old.sh` step that deletes old certificate files and labels it as executable after a waiting period, which conflicts with the skill metadata claim that it should 'never execute Delete'. In a certificate lifecycle context, deletion of prior cert material is safety-critical because old cert/key artifacts are often the last rollback path during outage recovery, partial rollout failure, or shadow dependency discovery.

External Script Fetching

High
Category
Supply Chain
Content
3. **每个 🔴 脚本必须有配套 rollback 脚本**(cleanup 类除外,但必须标"不可回滚")。
4. **执行顺序必须给 mermaid 图**,让运维一眼看清依赖。
5. **所有生产值必须用变量**,模板里的 `{{}}` 占位符不允许被 Agent 填成具体值(除非用户明确提供)。
6. **禁止出现**:`curl | bash`、`rm -rf` 无过滤、`kubectl apply` 无 dry-run、硬编码密码。

---
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
3. **每个 🔴 脚本必须有配套 rollback 脚本**(cleanup 类除外,但必须标"不可回滚")。
4. **执行顺序必须给 mermaid 图**,让运维一眼看清依赖。
5. **所有生产值必须用变量**,模板里的 `{{}}` 占位符不允许被 Agent 填成具体值(除非用户明确提供)。
6. **禁止出现**:`curl | bash`、`rm -rf` 无过滤、`kubectl apply` 无 dry-run、硬编码密码。

---
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

External Script Fetching

High
Category
Supply Chain
Content
- 检查项:`grep -E "example\.com|/etc/nginx|AKID|xxx\.com"` 不应命中实值

- [ ] **B5** 脚本中是否有危险模式?
  - `curl ... | bash` ❌
  - 未过滤的 `rm -rf` ❌
  - `kubectl apply` 没有 `--dry-run` 前置 ❌
  - `set -e` / `set -u` / `set -o pipefail` 缺失 ❌
Confidence
90% confidence
Finding
Remote code is downloaded and executed. This bypasses code review and could introduce malicious code.

Session Persistence

Medium
Category
Rogue Agent
Content
<a href="./LICENSE"><img src="https://img.shields.io/github/license/dimayip/cert-lifecycle-harness?style=flat-square" alt="License"></a>
</p>

> **A Harness-style collaboration skill for the full lifecycle of an X.509/TLS certificate.** The Agent is positioned as **"safety officer + document engineer + trusted executor"** — it generates layered review documents and human-executed scripts, may carry out Import/Modify-class write APIs on the user's behalf once six gates are satisfied, and **never executes Delete**.

---
Confidence
87% confidence
Finding
The README explicitly positions the agent as a "trusted executor" that may perform Import/Modify-class write APIs on the user's behalf once procedural gates are satisfied. In a high-risk production certificate-management context, delegating write actions to an agent materially increases the chance of unauthorized or mistaken changes, especially because README claims are not an enforceable technical control and could normalize dangerous overtrust.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Skill Enumeration

Medium
Category
Agent Snooping
Content
npx skills add dimayip/cert-lifecycle-harness -a codebuddy
```

Or drop the repo into your agent's skills directory manually (e.g. `~/.claude/skills/cert-lifecycle-harness/` or `.codebuddy/skills/cert-lifecycle-harness/`).

Compatible with the [Agent Skills Specification](https://agentskills.io).
Confidence
85% 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.

External Transmission

Medium
Category
Data Exfiltration
Content
## ⭐ Star history

[![Star History Chart](https://api.star-history.com/svg?repos=dimayip/cert-lifecycle-harness&type=Date)](https://star-history.com/#dimayip/cert-lifecycle-harness&Date)

---
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
## ⭐ Star history

[![Star History Chart](https://api.star-history.com/svg?repos=dimayip/cert-lifecycle-harness&type=Date)](https://star-history.com/#dimayip/cert-lifecycle-harness&Date)

---
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Skill Enumeration

Medium
Category
Agent Snooping
Content
npx skills add dimayip/cert-lifecycle-harness -a codebuddy
```

或者手动把仓库放到对应 Agent 的 skills 目录下(例如 `~/.claude/skills/cert-lifecycle-harness/` 或 `.codebuddy/skills/cert-lifecycle-harness/`)。

兼容 [Agent Skills Specification](https://agentskills.io)。
Confidence
85% 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.

Skill Enumeration

Medium
Category
Agent Snooping
Content
npx skills add dimayip/cert-lifecycle-harness -a codebuddy
```

或者手动把仓库放到对应 Agent 的 skills 目录下(例如 `~/.claude/skills/cert-lifecycle-harness/` 或 `.codebuddy/skills/cert-lifecycle-harness/`)。

兼容 [Agent Skills Specification](https://agentskills.io)。
Confidence
85% 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.

Vague Triggers

Medium
Confidence
92% confidence
Finding
L055-L063 将“证书到期”“SSL 证书”“TLS 证书”等常见运维表述直接作为自动触发条件,但没有说明仅在证书生命周期管理、变更规划或特定代理环境中触发,也未给出负例。这些短语在普通排障、学习交流或泛泛咨询中都很常见,容易造成技能被过宽激活。

Static analysis

No suspicious patterns detected.