Back to skill

Security audit

App Store Changelog

Security checks for vulnerabilities and agentic risk

Overview

This skill coherently helps generate App Store release notes from local git history, with one limited script-hardening issue to be aware of.

Reasonable to install for generating release notes from a repository. Use normal commit/tag refs when invoking the helper script, and avoid passing untrusted or option-like values as revision arguments until the script is hardened with revision validation and quoted git arguments.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/collect_release_changes.sh:4
Finding

Unvalidated Git Revisions Allow Git Option Injection

Content
View full analysis

Vulnerability Details

File Location: scripts/collect_release_changes.sh, lines 4-31
Vulnerability Type: Git option injection through unvalidated and unquoted revision arguments
Risk Level: Medium

Vulnerable Code

bash
since_ref="${1:-}"
until_ref="${2:-HEAD}"

if [[ -z "${since_ref}" ]]; then
  if git describe --tags --abbrev=0 >/dev/null 2>&1; then
    since_ref="$(git describe --tags --abbrev=0)"
  fi
fi

range=""
if [[ -n "${since_ref}" ]]; then
  range="${since_ref}..${until_ref}"
else
  range="${until_ref}"
fi

repo_root="$(git rev-parse --show-toplevel)"

printf "Repo: %s\n" "${repo_root}"
if [[ -n "${since_ref}" ]]; then
  printf "Range: %s..%s\n" "${since_ref}" "${until_ref}"
else
  printf "Range: start..%s (no tags found)\n" "${until_ref}"
fi

printf "\n== Commits ==\n"
git log --reverse --date=short --pretty=format:'%h|%ad|%s' ${range}

printf "\n\n== Files Touched ==\n"
git log --reverse --name-only --pretty=format:'--- %h %s' ${range} | sed '/^$/d'

Technical Analysis

The script accepts since_ref and until_ref from positional arguments without confirming that they resolve to valid Git revisions. The resulting range variable is then expanded without quotation in two git log commands.

Consequently, shell word splitting and pathname expansion apply to the value. More importantly, when since_ref is empty, an until_ref beginning with - is passed directly to git log and can be interpreted as one or more command-line options rather than as a revision.

This is Git option injection rather than direct shell command injection: shell metacharacters contained in the expanded variable are not reparsed as shell syntax. Nevertheless, supported Git log or diff options can alter command behavior. For example, output-related options may cause Git to write generated log content to a caller-selected writable path.

Attack Path

  1. An attacke ...[truncated 1701 chars]
Remediation
View remediation

Remediation Suggestions

Validate both caller-provided values as Git revisions before using them, reject option-shaped inputs, and never pass an unquoted range to Git.

  1. Reject empty, whitespace-containing, or --prefixed user-supplied revision names.
  2. Resolve each revision to an immutable commit ID with git rev-parse --verify.
  3. Build the range from validated commit hashes, which cannot be interpreted as options.
  4. Quote the final range in every invocation.
  5. Return a clear error if either supplied revision does not resolve to a commit.
  6. Consider accepting only a restricted revision syntax if arbitrary Git revision expressions are unnecessary.

Example hardened implementation:

bash
resolve_commit() {
  local ref="$1"

  if [[ -z "$ref" || "$ref" == -* || "$ref" =~ [[:space:]] ]]; then
    printf 'Invalid Git revision: %q\n' "$ref" >&2
    return 1
  fi

  git rev-parse --verify "${ref}^{commit}"
}

if [[ -n "$since_ref" ]]; then
  since_commit="$(resolve_commit "$since_ref")"
fi
until_commit="$(resolve_commit "$until_ref")"

if [[ -n "${since_commit:-}" ]]; then
  range="${since_commit}..${until_commit}"
else
  range="${until_commit}"
fi

git log --reverse --date=short \
  --pretty=format:'%h|%ad|%s' "$range"

git log --reverse --name-only \
  --pretty=format:'--- %h %s' "$range" | sed '/^$/d'

Where supported by the deployed Git version, git rev-parse --verify --end-of-options "${ref}^{commit}" should also be used to strengthen option separation during validation.

Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep

Static analysis

No suspicious patterns detected.