Back to skill

Security audit

Dev Serve

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but its helper script can persistently modify development and Caddy configuration and contains input-handling flaws that could let crafted project names, domains, or ports change files or execute commands.

Review this before installing. Use it only on trusted repositories with simple DNS-safe folder names, a trusted DEV_SERVE_DOMAIN, and numeric ports. Expect it to edit your Caddyfile and Vite config files, and check diffs/backups before committing or reusing those changes. Avoid pointing CADDY_ADMIN anywhere except your intended local Caddy admin endpoint.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/dev-serve.sh:265
Finding

Shell Command Injection Through the Unvalidated Port Argument

Content
View full analysis
/dev/null) if [[ -z "$dev_script" ]]; then echo >&2 "Error: No 'dev' script in package.json. Set DEV_CMD env var." exit 1 fi # Check if it's a vite-based server (needs --host and --port flags) if echo "$dev_script" | grep -qiE '(vite|next|nuxt|svelte)'; then echo "$pm run dev -- --host 0.0.0.0 --port $port" else echo "PORT=$port $pm run dev" fi } ``` ```bash cmd_up() { local repo="${1:?missing repo path}" local repo_abs repo_abs=$(cd "$repo" 2>/dev/null && pwd) || { echo "Error: '$repo' not found" >&2; exit 1; } local name name=$(basename "$repo_abs") local port="${2:-$(next_port)}" # Check if already running if jq -e ".\"$name\"" "$STATE_FILE" >/dev/null 2>&1; then echo "Error: '$name' is already running. Use 'dev-serve down $name' first or 'dev-serve restart $name'." >&2 exit 1 fi local dev_cmd dev_cmd=$(detect_dev_cmd "$repo_abs" "$port") local subdomain="${name}.${DOMAIN}" echo "🚀 Starting ${name}" echo " Repo: ${repo_abs}" echo " Port: ${port}" echo " Command: ${dev_cmd}" echo " URL: https://${subdomain}" echo "" # Patch Vite allowedHosts if needed patch_vite_allowed_hosts "$repo_abs" "$subdomain" # Create tmux session with dev server local sessi ...[truncated 2335 chars]
Remediation
View remediation
65535 )); then echo "Error: port must be an integer from 1 to 65535" >&2 exit 1 fi ``` 2. Do not submit assembled command strings to an interactive shell. Start tmux with an executable and separately quoted arguments where possible. 3. If shell interpretation is unavoidable, construct the command from trusted fixed tokens and escape every variable using `printf '%q'`. 4. Apply equivalent validation to auto-assigned and state-loaded ports. 5. Check that the selected port is not already listening, rather than checking only the state file and Caddyfile. 6. Add regression tests covering semicolons, command substitutions, whitespace, newlines, negative numbers, oversized values, and nonnumeric port arguments. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/dev-serve.sh:164
Finding

JavaScript and TypeScript Source Injection During Vite Configuration Patching

Content
View full analysis
/dev/null; then echo " allowedHosts already includes ${subdomain}" return 0 fi # Check if allowedHosts array exists if grep -q "allowedHosts" "$vite_config" 2>/dev/null; then if [[ "$(uname)" == "Darwin" ]]; then sed -i '' "s/allowedHosts: \[/allowedHosts: ['${subdomain}', /" "$vite_config" else sed -i "s/allowedHosts: \[/allowedHosts: ['${subdomain}', /" "$vite_config" fi echo " ✅ Added ${subdomain} to allowedHosts in $(basename "$vite_config")" elif grep -q "server:" "$vite_config" 2>/dev/null; then if [[ "$(uname)" == "Darwin" ]]; then sed -i '' "/server:.*{/a\\ \\ allowedHosts: ['${subdomain}'], " "$vite_config" else sed -i "/server:.*{/a\\ allowedHosts: ['${subdomain}']," "$vite_config" fi echo " ✅ Added allowedHosts with ${subdomain} to $(basename "$vite_config")" else echo " ⚠️ Could not auto-patch allowedHosts. Add manually to $(basename "$vite_config"):" echo " server: { allowedHosts: ['${subdomain}'] }" fi } ``` The value passed as `subdomain` is constructed from unvalidated inputs: ```bash name=$(basename "$repo_abs") local subdomain="${name}.${DOMAIN}" ``` ### Technical Analysis The repository directory basename and `DEV_SERVE_DOMAIN` are used to construct `s ...[truncated 2343 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/dev-serve.sh:107
Finding

Caddy Configuration Injection Through Unvalidated Repository and Domain Names

Content
View full analysis
> "$CADDYFILE" < tag if grep -q '' "$CADDYFILE"; then local dashboard_entry="
  • ${name}
    Dev Server
  • " if [[ "$(uname)" == "Darwin" ]]; then sed -i '' "s||${dashboard_entry}\n\t|" "$CADDYFILE" else sed -i "s||${dashboard_entry}\n\t|" "$CADDYFILE" fi fi fi } ``` The generated configuration is then submitted to Caddy: ```bash reload_caddy() { echo " Reloading Caddy..." if curl -sf -X POST "${CADDY_ADMIN}/load" \ -H "Content-Type: text/caddyfile" \ --data-binary "@${CADDYFILE}" >/dev/null 2>&1; then echo " ✅ Caddy reloaded" else echo " ⚠️ Caddy API reload failed. Try: caddy reload --config ${CADDYFILE} --address localhost:2019" fi } ``` ### Technical Analysis The generated Caddyfile embeds `name`, `DOMAIN`, and `port` without validating or escaping them for Caddyfile syntax. The repository name is derived from an arbitrary directory basename, while the domain ...[truncated 2183 chars]
    Remediation
    View remediation
    Vulnerability Patterns
    • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
    • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
    • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
    • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
    • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
    Findings (5)

    Ae1

    High
    Category
    analysis-evasion
    Confidence
    100% confidence
    Finding

    Referenced artifact was not completely inspected

    Content

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

    md
    cp scripts/dev-serve.sh ~/.local/bin/dev-serve
    

    Undeclared Tool Scope

    Medium
    Category
    MCP Least Privilege
    Confidence
    95% confidence
    Finding

    The skill clearly directs the agent/user to perform shell-capable actions such as copying executables, changing permissions, starting tmux sessions, editing config files, and reloading Caddy, yet it declares no explicit tool scope or permissions metadata. This increases the risk of overbroad agent execution because consumers cannot easily tell that the skill may modify files, launch network services, and interact with the local reverse proxy/admin API.

    Content

    No source excerpt is available for this finding.

    Missing User Warnings

    Medium
    Category
    Not specified by scanner
    Confidence
    91% confidence
    Finding

    The skill notes later that it auto-patches Vite allowedHosts, but the primary description and command behavior do not prominently warn that running dev-serve up will modify repository source/config files. Silent or easy-to-miss file modification is security-relevant because it can alter application behavior, create unexpected diffs, and normalize agent-driven code changes in a repo the user may not intend to edit.

    Content

    No source excerpt is available for this finding.

    External Transmission

    Medium
    Category
    Data Exfiltration
    Confidence
    70% confidence
    Finding

    Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

    Content

    Scanner excerpt · scripts/dev-serve.sh (reported line 158)May include surrounding context.

    sh
    # Reload Caddy via admin API
    reload_caddy() {
      echo "  Reloading Caddy..."
      if curl -sf -X POST "${CADDY_ADMIN}/load" \
        -H "Content-Type: text/caddyfile" \
        --data-binary "@${CADDYFILE}" >/dev/null 2>&1; then
        echo "  ✅ Caddy reloaded"
    

    Context-Inappropriate Capability

    Medium
    Category
    Not specified by scanner
    Confidence
    94% confidence
    Finding

    The script edits files inside the target repository by automatically patching Vite configuration, which exceeds the expected boundary of a tool described as starting dev servers and configuring Caddy. This can silently alter application source/configuration, break builds, create persistent changes that may later be committed, and weakens host validation by expanding allowedHosts without explicit user approval.

    Content

    No source excerpt is available for this finding.