Back to skill

Security audit

Aiclient2api Usage

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its usage-checking purpose, but it automatically uses a local password and includes an unsafe temporary-script pattern that should be reviewed before installation.

Install only if you are comfortable with the skill reading AIClient2API cache data, account details, and configs/pwd, and with it authenticating to a local service. Prefer a revised version that discloses credential use, asks before authenticated refresh, verifies the local service, and removes the predictable /tmp executable helper.

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

Error
Location
scripts/refresh_usage.sh:35
Finding

Predictable Temporary Script Enables File Overwrite and Local Code Execution

Content
View full analysis

Vulnerability Details

File Location: scripts/refresh_usage.sh, lines 35–62
Vulnerability Type: Predictable and insecure temporary executable file
Risk Level: High

Vulnerable Code

bash
cat > /tmp/refresh_usage.js << 'EOF'
import { readFileSync } from 'fs';
import { join } from 'path';
import { homedir } from 'os';

const configPath = join(homedir(), 'web/AIClient-2-API/configs/usage-cache.json');

console.log('Reading current usage cache...');
try {
    const data = JSON.parse(readFileSync(configPath, 'utf8'));
    console.log('✅ Cache file is accessible');
    console.log('📊 Last update:', data.timestamp);
    
    // The actual refresh happens automatically in the background
    // We just need to wait for the next cycle
    console.log('');
    console.log('💡 Usage data refreshes automatically every few minutes.');
    console.log('   Check again in a moment with: bash scripts/check_usage.sh');
} catch (error) {
    console.error('❌ Error reading cache:', error.message);
}
EOF

node /tmp/refresh_usage.js
rm /tmp/refresh_usage.js

Technical Analysis

The script creates executable JavaScript at the fixed, globally predictable path /tmp/refresh_usage.js. It does not securely reserve the filename, verify that the path is a regular file owned by the current user, prevent symbolic-link traversal, or place the file in a private directory.

This produces two related local attack opportunities:

  1. Symbolic-link file overwrite: A local attacker can create /tmp/refresh_usage.js as a symbolic link to another file writable by the victim. The shell redirection then follows that link and truncates or overwrites its target.
  2. Time-of-check/time-of-use replacement: There is a window between writing the file and invoking node during which another local user may replace the temporary script. Node would then execute attacker-controlled JavaScript under the victim's account.

Removing the predictable path afterward does not prev ...[truncated 1353 chars]

Remediation
View remediation

Remediation Suggestions

Avoid creating a temporary JavaScript file. The cache-reading operation can be implemented directly in shell with jq, or JavaScript can be supplied to Node through standard input so that no executable file is exposed in /tmp.

If a temporary file is unavoidable:

  1. Create a private temporary directory using mktemp -d.
  2. Restrict permissions with umask 077.
  3. write the script only inside that private directory.
  4. Install a cleanup trap immediately after directory creation.
  5. Quote every generated path.
  6. Do not run this script with elevated privileges.

Example hardening pattern:

bash
umask 077
TMP_DIR=$(mktemp -d) || exit 1
trap 'rm -rf -- "$TMP_DIR"' EXIT HUP INT TERM

SCRIPT_FILE="$TMP_DIR/refresh_usage.js"
cat > "$SCRIPT_FILE" <<'EOF'
// JavaScript content
EOF

node -- "$SCRIPT_FILE"

A file-free approach is preferable because it eliminates the temporary-path race entirely.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (6)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
95% 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).

Content

Scanner excerpt · scripts/refresh_usage.sh (reported line 64)May include surrounding context.

sh
EOF

node /tmp/refresh_usage.js
rm /tmp/refresh_usage.js

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill instructs users to execute shell commands and read local files, but it does not declare any explicit tool scope such as permissions or allowed-tools. This creates an authorization gap where an agent may invoke shell access more broadly than intended, increasing the risk of unauthorized local file access or command execution beyond the narrow usage-checking purpose.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script silently reads a stored password from a local config file and uses it to authenticate to a local API as part of a routine status check. Even though the destination is localhost, this is still credential use and transmission without explicit user consent or clear disclosure; if the local service is spoofed, compromised, or bound unexpectedly, the password could be exposed or misused.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
90% confidence
Finding

The script transmits a password in an HTTP POST request to a service on 127.0.0.1. Localhost reduces network exposure, but plain HTTP and lack of service verification still create risk from local interception, malicious local listeners, port hijacking, or accidental exposure if the service binds beyond loopback.

Content

Scanner excerpt · scripts/check_usage.sh (reported line 16)May include surrounding context.

sh
PASSWORD=$(cat "$PWD_FILE" | tr -d '\n')
    
    # Try to login and get token
    LOGIN_RESPONSE=$(curl -s -X POST "http://127.0.0.1:16825/api/login" \
        -H "Content-Type: application/json" \
        -d "{\"password\":\"$PASSWORD\"}" 2>/dev/null)

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The header comments say this script 'Manually triggers usage data refresh by calling the provider's usage check,' and later output says 'Triggering refresh via Web UI API.' However, the generated Node.js script only reads the existing usage-cache.json and prints status; it does not call any API or perform a refresh. This is an active contradiction between the script's stated intent and its actual behavior.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script prints 'Refresh request completed' after merely creating and running a temporary script that reads the cache file. Since no API call, IPC action, or other refresh-triggering mechanism occurs, the success messaging misrepresents what happened and contradicts the code's real effect.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.