Back to skill

Security audit

Deploy Public

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real private-to-public publishing tool, but it also performs under-disclosed high-impact actions such as broad branch deletion, automatic npm publishing, and local secret use.

Install only if you are prepared for it to mutate a public GitHub repository, merge changes, create releases, possibly create the repo, delete remote branches, and publish npm packages. Review and modify the script first: add a dry run, restrict branch cleanup to branches it created, use an allowlist or secret scan before public commits, remove --no-verify, and require explicit opt-in before reading 1Password credentials or running npm publish.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
deploy-public.sh:102
Finding

Unbounded Private-to-Public File Disclosure

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
deploy-public.sh:181
Finding

Destructive Deletion of Unrelated Remote Branches

Content
View full analysis
/dev/null | grep -v '^main$' || true) if [[ -n "$STALE_BRANCHES" ]]; then STALE_COUNT=$(echo "$STALE_BRANCHES" | wc -l | tr -d ' ') echo " Found $STALE_COUNT stale branch(es). Deleting..." echo "$STALE_BRANCHES" | while read -r stale; do gh api -X DELETE "repos/$PUBLIC_REPO/git/refs/heads/$stale" 2>/dev/null && echo " ✓ Deleted $stale" || echo " ! Could not delete $stale" done else echo " ✓ No stale branches" fi ``` ### Technical Analysis The cleanup logic treats every branch other than one named exactly `main` as stale. It does not restrict deletion to the branch created by the current deployment, validate a deployment-specific prefix, identify the repository's actual default branch, check for open pull requests, or preserve user-created branches. The script therefore requests deletion of unrelated feature, release, maintenance, and alternate default branches. This behavior materially exceeds the documented claim that the skill cleans up deployment branches. Repository protection rules may prevent some deletion attempts, but the script must not rely on external branch protection as its primary safety control. ### Attack Path 1. A public target repository contains one or more legitimate branches other than `main`. 2. An operator runs the deployment script with credentials authorized to delete Git references. 3. After the deployment pull request is merged, the script lists all repository branches. 4. It filters out only the literal branch name `main`. 5. It submits a GitHub API deletion request for every remaining branch. 6. ...[truncated 632 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
deploy-public.sh:247
Finding

Plaintext npm Credential Can Remain in an Untrapped Temporary Directory

Content
View full analysis
/dev/null if [[ -f "$NPM_TMPDIR/public/package.json" ]]; then IS_PRIVATE=$(cd "$NPM_TMPDIR/public" && node -p "require('./package.json').private || false" 2>/dev/null) echo "Publishing to npm from public repo..." NPM_TOKEN=$(OP_SERVICE_ACCOUNT_TOKEN=$(cat ~/.openclaw/secrets/op-sa-token) \ op item get "npm Token" --vault "Agent Secrets" --fields label=password --reveal 2>/dev/null || echo "") if [[ -n "$NPM_TOKEN" ]]; then cd "$NPM_TMPDIR/public" # Helper: classify an npm publish failure and print a real message. # Distinguishes the "already published" no-op case from real errors so # the output is not buried in 10+ misleading "non-fatal" lines per run. # Related: ai/product/bugs/release-pipeline/2026-04-05--cc-mini--release-pipeline-master-plan.md Phase 7 classify_npm_publish_error() { local pkg_name="$1" local err_text="$2" if [[ "$err_text" == *"previously published"* || "$err_text" == *"cannot publish over"* ]]; then echo " - $pkg_name: already at current version, skipped" elif [[ "$err_text" == *"ENEEDAUTH"* || "$err_text" == *"need auth"* ]]; then echo " ✗ $pkg_name: auth failed (token missing or invalid)" echo " ${err_text##*$'\n'}" elif [[ "$err_text" == *"ENETWORK"* || "$err_text" == *"ECONNREFUSED"* ]]; then echo " ✗ $pkg_name: network error" echo " ${err_text##*$'\n'}" elif [[ -n "$err_text" ]]; then # Unknown failure: print the first real error line (skip stack dumps) local first_err first_err=$(echo " ...[truncated 2680 chars]
Remediation
View remediation
&1); then echo "Published successfully" else classify_npm_publish_error "root" "$ROOT_PUBLISH_ERR" fi ``` 3. Create credential files with restrictive permissions, for example by setting `umask 077`. 4. Use a dedicated temporary npm user-configuration file and remove it unconditionally. 5. Avoid storing registry credentials inside the repository clone. 6. Apply the same safe error-handling and cleanup strategy to every sub-tool publication. 7. Document the 1Password CLI, service-account token, secret path, vault access, and npm credential requirements. 8. Rotate the npm token immediately if a failed execution may have left it on disk. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
deploy-public.sh:242
Finding

Undocumented Automatic Publication of Packages to npm

Content
View full analysis
/dev/null if [[ -f "$NPM_TMPDIR/public/package.json" ]]; then IS_PRIVATE=$(cd "$NPM_TMPDIR/public" && node -p "require('./package.json').private || false" 2>/dev/null) echo "Publishing to npm from public repo..." NPM_TOKEN=$(OP_SERVICE_ACCOUNT_TOKEN=$(cat ~/.openclaw/secrets/op-sa-token) \ op item get "npm Token" --vault "Agent Secrets" --fields label=password --reveal 2>/dev/null || echo "") if [[ -n "$NPM_TOKEN" ]]; then cd "$NPM_TMPDIR/public" # Publish root package (if not private) if [[ "$IS_PRIVATE" != "true" ]]; then echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc ROOT_PUBLISH_ERR=$(npm publish --access public 2>&1) if [[ $? -eq 0 ]]; then echo " ✓ Published root package to npm" else classify_npm_publish_error "root" "$ROOT_PUBLISH_ERR" fi rm -f .npmrc else echo " - Root package is private. Skipping root npm publish." fi # For toolbox repos: publish each sub-tool regardless of root private status if [[ -d "tools" ]]; then for TOOL_DIR in tools/*/; do if [[ -f "${TOOL_DIR}package.json" ]]; then TOOL_PRIVATE=$(node -p "require('./${TOOL_DIR}package.json').private || false" 2>/dev/null) if [[ "$TOOL_PRIVATE" != "true" ]]; then TOOL_NAME=$(node -p "require('./${TOOL_DIR}package.js ...[truncated 2560 chars]
Remediation
View remediation
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
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill metadata and documentation claim a narrow private-to-public sync that excludes only ai/, but the referenced behavior includes materially broader and more sensitive actions: creating repositories, deleting branches, publishing to npm, and retrieving secrets. This mismatch is dangerous because a user or calling agent may grant repo and secret access under false assumptions, leading to unintended destructive changes or public release of code/packages.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 38)May include surrounding context.

md
3. THEN run `deploy-public.sh` (pulls notes from private release)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Using git commit --no-verify bypasses client-side hooks such as secret scanning, policy checks, or content validation that may be relied upon to prevent unsafe publication. In a script that sanitizes and republishes code to a public repo, skipping those controls increases the risk that prohibited or sensitive content is committed and pushed unnoticed.

Content

Scanner excerpt · deploy-public.sh (reported line 154)May include surrounding context.

sh
BRANCH="$HARNESS_ID/deploy-$(date +%Y%m%d-%H%M%S)"

git add -A
git commit --no-verify -m "$COMMIT_MSG (from $COMMIT_HASH)"

if [[ "$EMPTY_REPO" == "true" ]]; then
  # Empty repo: push directly to main (no base branch to PR against)

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The stated skill purpose is repo synchronization and release mirroring, but the script also performs npm publication using retrieved credentials. That is a materially broader and more sensitive side effect than the declared behavior, creating a supply-chain risk where running a repo-sync tool can unexpectedly publish packages to a public registry.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
92% confidence
Finding

The script writes the npm auth token into a plaintext .npmrc file in the working tree before publishing. Even if later removed, the token can be exposed through process interruption, debugging, file-system monitoring, backup tools, permissive file permissions, or accidental inclusion in subsequent operations.

Content

Scanner excerpt · deploy-public.sh (reported line 290)May include surrounding context.

sh
# Publish root package (if not private)
      if [[ "$IS_PRIVATE" != "true" ]]; then
        echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc
        ROOT_PUBLISH_ERR=$(npm publish --access public 2>&1)
        if [[ $? -eq 0 ]]; then
          echo "  ✓ Published root package to npm"

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · deploy-public.sh (reported line 297)May include surrounding context.

sh
else
          classify_npm_publish_error "root" "$ROOT_PUBLISH_ERR"
        fi
        rm -f .npmrc
      else
        echo "  - Root package is private. Skipping root npm publish."
      fi

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · deploy-public.sh (reported line 316)May include surrounding context.

sh
else
          classify_npm_publish_error "root" "$ROOT_PUBLISH_ERR"
        fi
        rm -f .npmrc
      else
        echo "  - Root package is private. Skipping root npm publish."
      fi

Credential Access

High
Category
Privilege Escalation
Confidence
92% confidence
Finding

This repeats the same risky pattern for each tool package by writing the npm auth token into a plaintext per-tool .npmrc file. Multiple writes increase the exposure surface and the chance of leakage during failures, concurrent tooling, or accidental file capture.

Content

Scanner excerpt · deploy-public.sh (reported line 309)May include surrounding context.

sh
TOOL_PRIVATE=$(node -p "require('./${TOOL_DIR}package.json').private || false" 2>/dev/null)
            if [[ "$TOOL_PRIVATE" != "true" ]]; then
              TOOL_NAME=$(node -p "require('./${TOOL_DIR}package.json').name" 2>/dev/null)
              echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > "${TOOL_DIR}.npmrc"
              TOOL_PUBLISH_ERR=$(cd "$TOOL_DIR" && npm publish --access public 2>&1)
              if [[ $? -eq 0 ]]; then
                echo "  ✓ Published $TOOL_NAME to npm"

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README advertises automatic PR merge and deploy-branch cleanup but does not warn users that these actions are irreversible or may modify/delete remote state. In a repo-publication workflow, this can lead to unintended public disclosure, accidental release propagation, or loss of recovery points if a user runs the tool with the wrong repository or without reviewing the generated changes.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill describes cloning, copying, PR creation, merging, and release syncing, but does not clearly warn that it may perform destructive repository operations or irreversible publication actions. In this context, the omission increases the chance that an operator or autonomous agent runs it against the wrong repository or with excessive permissions, causing unintended exposure or repository state changes.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script reads a local 1Password service-account token and uses it to fetch an npm credential, even though the advertised function is repository sync. Accessing secret-management material expands the trust boundary and enables unintended package publication if the script is invoked in an environment where those secrets are available.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

Sensitive credential access occurs silently at the point of operation, with no upfront disclosure or confirmation near the secret read. In agent or automation contexts, this increases the chance that a user runs the script without realizing it will touch local secret material and initiate external publication actions.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.