Back to skill

Security audit

Polling Best Practices

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent for background polling, but its reusable shell template should be reviewed because it evaluates configurable strings as shell code and retains polling logs under temporary directories.

Install only if you are comfortable with agents creating temporary polling folders and starting bounded background shell scripts. Before using the template, replace eval-based command parsing with fixed commands or argument arrays, avoid placing untrusted IDs in shell snippets, and keep logs in private directories because command output may contain sensitive data.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/poll-template.sh:90
Finding

Arbitrary Shell Command Execution Through Configurable eval Expressions

Content
View full analysis
&1) || { log "Command failed: $OUTPUT" save_progress "$POLL_COUNT" "command_failed" sleep "$POLL_INTERVAL" continue } log "Output: ${OUTPUT:0:200}" PARSED=$(eval "$PARSE_OUTPUT" <<< "$OUTPUT" 2>/dev/null) || PARSED="parse_error" ``` The evaluated variables are configured earlier in the same file: ```bash POLL_COMMAND='echo "Replace this with the actual status check command"' PARSE_OUTPUT='jq -r ".status" <<< "$OUTPUT"' ``` ### Technical Analysis The script uses `eval` to interpret both `POLL_COMMAND` and `PARSE_OUTPUT` as shell source code. Unlike executing a fixed command with a separately quoted argument array, `eval` performs another complete round of shell parsing. Shell metacharacters, command substitutions, redirections, pipelines, and additional commands contained in either variable are therefore executed. The template instructs users or agents to customize these strings for each polling task. If a job identifier, artifact name, path, status expression, or other untrusted value is concatenated into either configuration string, quoting at the original assignment site may not remain effective during the second parsing pass. The polling script is intended to run unattended with the permissions of the invoking agent or user. Consequently, injected commands execute under that same account and are not restricted to the polling task directory. ### Attack Path 1. An attacker controls or influences a value used to construct `POLL_COMMAND` or `PARSE_OUTPUT`, such as a job ID, artifact ID, filename, API-provided handle, or user-supplied parsing expression. 2. The generated configuration embeds that value into one of the shell command strings. 3. The ...[truncated 1096 chars]
Remediation
View remediation
&1); then save_progress "$POLL_COUNT" "command_failed" error_exit "Polling command failed" fi ``` 3. Validate identifiers before using them. For example, require job IDs to match a narrowly defined format: ```bash [[ "$JOB_ID" =~ ^[A-Za-z0-9._-]+$ ]] || error_exit "Invalid job identifier" ``` 4. Replace configurable parsing source code with fixed parser functions. Select a parser using a strict enumerated value rather than an executable expression: ```bash case "$PARSER_TYPE" in json-status) PARSED=$(jq -r '.status // empty' <<< "$OUTPUT") ;; plain-status) PARSED=$(awk -F ': ' '$1 == "status" {print $2; exit}' <<< "$OUTPUT") ;; *) error_exit "Unsupported parser type" ;; esac ``` 5. Keep user-controlled values exclusively in data variables and pass them as quoted arguments. Do not interpolate them into shell programs. 6. If arbitrary commands are an unavoidable feature, require explicit trusted configuration, reject shell metacharacters where possible, run the command with reduced privileges, and document that configuration values must never contain untrusted data. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/poll-template.sh:43
Finding

Sensitive Polling Data May Be Exposed Through Retained Temporary Logs

Content
View full analysis
"$PROGRESS_FILE" <> "$ERROR_LOG" log "ERROR: $*" exit 1 } ``` The command and portions of its output are persisted: ```bash log "[Poll $POLL_COUNT/$MAX_POLLS] Running: $POLL_COMMAND" OUTPUT=$(eval "$POLL_COMMAND" 2>&1) || { log "Command failed: $OUTPUT" save_progress "$POLL_COUNT" "command_failed" sleep "$POLL_INTERVAL" continue } log "Output: ${OUTPUT:0:200}" ``` The associated guidance places these files under `/tmp`, requires poll results to be logged, and states that the temporary folder should not be automatically deleted. It does not require a restrictive `umask`, private directory permissions, file permissions, or secret redaction. ### Technical Analysis The script records the complete polling command, complete command output on failure, and the first 200 characters of successful output. Status commands and API clients can include or return sensitive material such as access tokens, signed URLs, account identifiers, private artifact names, error diagnostics, or portions of generated content. The script relies on inherited process defaults when creating `poll.log`, `error.log`, and `progress.json`. On systems with a typical permissive umask, newly created files may be readable by other local users unless the containing task directory was independently created wit ...[truncated 1915 chars]
Remediation
View remediation
&2 exit 1 } chmod 700 "$TASK_DIR" ``` 3. Explicitly initialize sensitive files with mode `0600`: ```bash install -m 600 /dev/null "$POLL_LOG" install -m 600 /dev/null "$ERROR_LOG" install -m 600 /dev/null "$PROGRESS_FILE" ``` 4. Do not log the complete command string, because arguments may contain credentials. Log only a fixed command name or a sanitized operation label. 5. Redact known secret formats, authorization headers, query-string signatures, bearer tokens, and credentials before recording output. 6. Prefer structured logging that records only required fields, such as poll number and normalized status, instead of raw command output. 7. Truncate failure output as well as successful output, but do not treat truncation alone as sufficient secret protection. 8. Define a retention period and provide secure cleanup after explicit user approval. Document the exact task directory and warn users when logs may contain sensitive data. 9. Update `SKILL.md` to require mode `0700` for task directories, mode `0600` for state and log files, and redaction before any command output is persisted. ]]>
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • 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
Findings (1)

Session Persistence

Medium
Category
Rogue Agent
Confidence
65% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

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

bash
# In the task's temp dir:
nohup bash poll.sh > /dev/null 2>&1 &
echo "Polling started in background (PID: $!)"

Static analysis

No suspicious patterns detected.