Back to skill

Security audit

Digital Clawatar

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a legitimate UNITH avatar-management skill, but it needs Review because credential-bearing API calls can be redirected by an undocumented environment override and token handling is too broad for the sensitivity involved.

Install only if you are comfortable giving the skill authority over your UNITH account and uploaded knowledge documents. Before use, unset or lock down API_BASE, consider disabling UNITH_TOKEN_CACHE or moving it to a private user-owned directory, avoid putting secrets in logged payloads or command-line fields, and require an explicit user confirmation that names the exact digital human before any delete operation.

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)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/_utils.sh:5
Finding
Environment-Controlled API Base Can Redirect Credentials, Tokens, and Documents<![CDATA[ ## Vulnerability Details **File Location**: `scripts/_utils.sh:5`, `scripts/auth.sh:68-71`, `scripts/list-resources.sh:30-31`, `scripts/delete-head.sh:37-38 and 71-72`, `scripts/upload-document.sh:61-64` **Vulnerability Type**: Unvalidated security-sensitive endpoint override **Risk Level**: High ### Vulnerable Code ```bash # scripts/_utils.sh:5 API_BASE="${API_BASE:-https://platform-api.unith.ai}" ``` ```bash # scripts/auth.sh:68-71 unith_curl -X POST "$API_BASE/auth/token" \ -H 'Content-Type: application/json' \ -H 'accept: application/json' \ -d "$(jq -n --arg e "$UNITH_EMAIL" --arg k "$UNITH_SECRET_KEY" '{email:$e, secretkey:$k}')" ``` ```bash # scripts/list-resources.sh:30-32 if ! unith_curl -X GET "$API_BASE/headvisual/list" \ -H "$AUTH_HEADER" \ -H 'accept: application/json'; then ``` ```bash # scripts/delete-head.sh:37-39 if ! unith_curl -X GET "$API_BASE/head/$HEAD_ID" \ -H "Authorization: Bearer $UNITH_TOKEN" \ -H 'accept: application/json'; then ``` ```bash # scripts/delete-head.sh:71-73 if ! unith_curl -X DELETE "$API_BASE/head/$HEAD_ID" \ -H "Authorization: Bearer $UNITH_TOKEN" \ -H 'accept: application/json'; then ``` ```bash # scripts/upload-document.sh:61-64 if ! unith_curl -X POST "$API_BASE/document/upload" \ -H "Authorization: Bearer $UNITH_TOKEN" \ -F "file=@$FILE_PATH" \ -F "headId=$HEAD_ID"; then ``` ### Technical Analysis The declared service endpoint is `https://platform-api.unith.ai`, but `_utils.sh` allows any inherited `API_BASE` value to replace it. No validation requires HTTPS, verifies the destination hostname, or restricts overrides to an allowlist. All scripts subsequently trust this variable when sending sensitive data. Authentication transmits the user's account email and non-expiring UNITH secret key. Resource management calls transmit a bearer token valid for up to seven days, while document upload also transmits the selected local document. The network behavior in `delete-head.sh` ...[truncated 1319 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Hard-code `https://platform-api.unith.ai` for all credential-bearing production requests. - If endpoint overrides are required for development, require a separate explicit opt-in such as `UNITH_ALLOW_CUSTOM_API_BASE=1`. - Parse and validate the override before use: - Require the `https` scheme. - Require an exact approved hostname. - Reject embedded user information, fragments, unexpected ports, and lookalike subdomains. - Verify the effective destination immediately before adding an `Authorization` header or sensitive request body. - Never send the non-expiring secret key, bearer token, or document to an endpoint that has not passed validation. - Document any supported development endpoint and its security implications. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/auth.sh:45
Finding
Predictable Shared Token Cache Allows Cache Poisoning and Unsafe File Replacement<![CDATA[ ## Vulnerability Details **File Location**: `scripts/auth.sh:45-61 and 99-103` **Vulnerability Type**: Unsafe predictable temporary credential file **Risk Level**: Medium ### Vulnerable Code ```bash # Cache file stores: email \t token \t timestamp (epoch seconds) # Token is valid for 7 days; we reuse if less than 6 days old to give margin. TOKEN_CACHE="${UNITH_TOKEN_CACHE-/tmp/.unith_token_cache}" CACHE_MAX_AGE=$((6 * 24 * 60 * 60)) # 6 days in seconds if [ -n "$TOKEN_CACHE" ] && [ -f "$TOKEN_CACHE" ]; then CACHED_EMAIL=$(cut -f1 "$TOKEN_CACHE" 2>/dev/null || echo "") CACHED_TOKEN=$(cut -f2 "$TOKEN_CACHE" 2>/dev/null || echo "") CACHED_TIME=$(cut -f3 "$TOKEN_CACHE" 2>/dev/null || echo "0") NOW=$(date +%s) AGE=$((NOW - CACHED_TIME)) if [ "$CACHED_EMAIL" = "$UNITH_EMAIL" ] && [ -n "$CACHED_TOKEN" ] && [ "$AGE" -lt "$CACHE_MAX_AGE" ]; then export UNITH_TOKEN="$CACHED_TOKEN" REMAINING_DAYS=$(( (CACHE_MAX_AGE - AGE) / 86400 + 1 )) log_ok "Reusing cached token (valid ~${REMAINING_DAYS} more days). To force refresh: rm $TOKEN_CACHE" return 0 2>/dev/null || exit 0 fi fi ``` ```bash # Write to cache if [ -n "$TOKEN_CACHE" ]; then printf '%s\t%s\t%s\n' "$UNITH_EMAIL" "$TOKEN" "$(date +%s)" > "$TOKEN_CACHE" chmod 600 "$TOKEN_CACHE" fi ``` ### Technical Analysis The default token cache is a fixed, predictable path in the globally shared `/tmp` directory. Before trusting the cached token, the script does not verify that the path is a regular file, that it is owned by the current user, that its permissions are sufficiently restrictive, or that it is not a symbolic link. When writing, shell redirection opens or truncates the destination before `chmod 600` runs. Consequently, applying restrictive permissions afterward does not make path resolution or file creation safe. The write is also not atomic. The cached bearer token remains usable for up to six days and represents remote account authority, making integrity and confide ...[truncated 1476 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Store the cache under `$XDG_RUNTIME_DIR` or a private user directory rather than a shared `/tmp` pathname. - Set `umask 077` before creating any credential file. - Create files atomically with `mktemp` in a trusted, user-owned directory, write the content, and rename the file into place. - Before reading a cache, verify that: - It is a regular file. - It is not a symbolic link. - It is owned by the current effective user. - Its mode does not permit group or other access. - Reject malformed timestamps, negative ages, and unexpected cache fields. - Consider disabling persistent token caching by default or using an operating-system credential store. - Remove expired or invalid caches securely and avoid retaining tokens longer than operationally necessary. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/update-head.sh:98
Finding
Update Script Prints Credential-Bearing Payloads to Logs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/update-head.sh:98-100` **Vulnerability Type**: Sensitive information exposure through console output **Risk Level**: Medium ### Vulnerable Code ```bash log_info "Updating digital human '$HEAD_ID'..." log_info "Payload:" echo "$PAYLOAD" | jq . ``` ### Technical Analysis The update script accepts arbitrary JSON fields and prints the complete resulting payload before sending it. The documented configuration includes the sensitive `voiceflowApiKey` field, and future or undocumented API fields may contain additional keys, tokens, private prompts, or webhook credentials. Console output is frequently retained in CI logs, terminal recording systems, Agent transcripts, support bundles, and centralized logging platforms. Although the payload is intentionally supplied by the user, reproducing it in full is not necessary to perform the update. ### Attack Path 1. A user prepares an update containing a sensitive field, such as `voiceflowApiKey`. 2. The user invokes `scripts/update-head.sh` with the JSON file or a `--field` argument. 3. The script renders the entire payload with `jq`. 4. An automation platform, terminal recorder, Agent transcript, or CI system retains the output. 5. A person or service with log access retrieves and reuses the exposed credential. ### Impact Assessment The exposed data can include Voiceflow API credentials, private system prompts, webhook configuration, or other arbitrary update fields. Compromise scope depends on the authority of the logged credential. For example, a disclosed Voiceflow key may permit access to the associated project under the permissions granted to that key. The flaw does not expose `UNITH_TOKEN` directly unless a user places it in the payload. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Do not print complete update payloads by default. - Report only non-sensitive metadata, such as the head ID and names of fields being updated. - If verbose output is needed, require an explicit debug flag and clearly warn that it may expose secrets. - Recursively redact field names containing terms such as `key`, `token`, `secret`, `password`, `authorization`, and `credential`. - Ensure redaction covers nested objects and uses case-insensitive matching. - Advise users not to pass credentials through command-line arguments because process listings and shell history may retain them; prefer protected JSON files or standard input. ]]>

T08 · Insecure Dependencies

Warning
Location
references/embedding.md:38
Finding
Embedding Guidance Executes an Unpinned Mutable Third-Party Script<![CDATA[ ## Vulnerability Details **File Location**: `references/embedding.md:38 and 78-83` **Vulnerability Type**: Unpinned remote JavaScript dependency without integrity verification **Risk Level**: Medium ### Vulnerable Code ```html <script src="https://cdn.unith.ai/widget/latest/unith-widget.js"></script> ``` ```jsx useEffect(() => { const script = document.createElement('script'); script.src = 'https://cdn.unith.ai/widget/latest/unith-widget.js'; script.onload = () => { window.UnithWidget.init({ ``` ### Technical Analysis The recommended integration loads a JavaScript resource from a mutable `latest` path. No fixed version or Subresource Integrity hash is supplied. Every website following this guidance therefore executes whatever code the CDN serves at request time, even if that code differs from what was reviewed when the integration was deployed. Remote JavaScript executes with the privileges of the embedding page's origin. An upstream compromise, CDN compromise, DNS or account takeover, or malicious future release could therefore affect all consumers automatically. This is dependency guidance rather than malicious code shipped in the Skill itself. No evidence was found that the current remote widget is malicious. ### Attack Path 1. A website adopts the documented widget integration. 2. The remote `latest` asset is modified through an upstream release or supply-chain compromise. 3. A visitor opens the integrating website. 4. The browser downloads the modified script without verifying a pinned version or integrity hash. 5. The modified code executes in the page context and accesses data and browser APIs available to that script. ### Impact Assessment Compromised widget code can manipulate page content, monitor avatar conversations, make authenticated same-origin requests where browser controls permit them, read non-HttpOnly browser storage, and exfiltrate data accessible to JavaScript. The exact scope depends on the integrating site's ...[truncated 73 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace the mutable `latest` URL with a specific, audited version. - Publish and document a Subresource Integrity hash for the pinned asset. - Add the appropriate `integrity` and `crossorigin` attributes to static script examples. - Use a restrictive Content Security Policy that permits only the required hosts and capabilities. - Document a controlled dependency-upgrade process that reviews changes before updating the pinned version. - Where practical, self-host the reviewed widget artifact and monitor it for unauthorized changes. - Keep iframe-based integration isolated with the narrowest feasible `allow` and `sandbox` permissions. ]]>
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 Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (15)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
---

## Delete a Digital Human — `DELETE /head/<headId>`

Permanently removes a digital human.
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
Permanently removes a digital human.

```
DELETE /head/<headId>
Authorization: Bearer <token>
```
Confidence
80% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill instructs the agent to invoke multiple shell scripts and use tools like curl and jq, but it does not declare any explicit tool scope such as permissions or allowed-tools. That creates an authorization gap where an agent runtime may permit broader shell execution than intended, increasing the chance of command misuse, unintended external network access, or destructive operations like deletion through available scripts.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The document-upload instructions tell users to upload local files to the service via script or multipart API, but do not warn that uploaded documents may contain sensitive or regulated data. In an agent setting, this can lead to inadvertent exfiltration of private files to a third-party platform because the docs normalize file transmission without any privacy or data-handling caveats.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation exposes a destructive delete endpoint and explicitly states it 'Permanently removes' a digital human, but provides no guidance about confirmation prompts, irreversible effects, or safeguards before invoking it. In an agent skill context, this omission increases the chance an LLM-driven workflow could delete resources from ambiguous or malicious user prompts without adequate human confirmation.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The embedding guidance explicitly requests camera and microphone permissions but does not instruct integrators to provide a user-facing privacy notice, consent flow, or justification for why those permissions are needed. In the context of a conversational avatar product, this can lead downstream adopters to deploy a widget that surprises users with access requests for sensitive sensors, increasing privacy, compliance, and trust risks.

External Transmission

Medium
Category
Data Exfiltration
Content
log_info "Authenticating with UNITH API as $UNITH_EMAIL..."

unith_curl -X POST "$API_BASE/auth/token" \
  -H 'Content-Type: application/json' \
  -H 'accept: application/json' \
  -d "$(jq -n --arg e "$UNITH_EMAIL" --arg k "$UNITH_SECRET_KEY" '{email:$e, secretkey:$k}')"
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
# Write to cache
if [ -n "$TOKEN_CACHE" ]; then
  printf '%s\t%s\t%s\n' "$UNITH_EMAIL" "$TOKEN" "$(date +%s)" > "$TOKEN_CACHE"
  chmod 600 "$TOKEN_CACHE"
fi

log_ok "Authenticated successfully. Token stored in UNITH_TOKEN (valid 7 days)."
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The script reads an arbitrary JSON payload and sends it directly to the UNITH API, and for voiceflow mode it explicitly requires a `voiceflowApiKey` inside that payload. This creates a real risk of transmitting third-party credentials or other sensitive fields without any explicit warning, redaction, or safer secret-handling path, which can lead to accidental disclosure to the remote service, shell history, or logs if users are not careful.

External Transmission

Medium
Category
Data Exfiltration
Content
PAYLOAD=$(cat "$PAYLOAD_FILE")

if ! unith_curl -X POST "$API_BASE/head/create" \
  -H "Authorization: Bearer $UNITH_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'accept: application/json' \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
#
# Usage:
#   bash scripts/delete-head.sh <headId>
#   bash scripts/delete-head.sh <headId> --confirm    # skip confirmation prompt

set -euo pipefail
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
echo "Usage: $0 <headId> [--confirm]"
  echo ""
  echo "  headId      - The digital human ID (from list-resources.sh heads)"
  echo "  --confirm   - Skip confirmation prompt"
  echo ""
  echo "WARNING: This permanently deletes the digital human and cannot be undone."
  exit 1
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

External Transmission

Medium
Category
Data Exfiltration
Content
log_info "Payload:"
echo "$PAYLOAD" | jq .

if ! unith_curl -X PUT "$API_BASE/head/update" \
  -H "Authorization: Bearer $UNITH_TOKEN" \
  -H 'Content-Type: application/json' \
  -H 'accept: application/json' \
Confidence
70% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The React example sets autoStart to true without warning that the avatar may begin speaking or initiating conversation automatically. This can cause unexpected audio playback, accessibility issues, and poor user experience, especially when embedded in consumer-facing pages or environments where autoplay is disruptive.

Natural-Language Policy Violations

Low
Confidence
81% confidence
Finding
The usage example sets both `languageSpeechRecognition` and `language` to `en-US`, which can implicitly steer users toward a fixed locale. There is no accompanying note that these are merely examples or that other locales are supported, so the natural-language guidance may conflict with a language-choice policy.

Static analysis

No suspicious patterns detected.