T09 · Insecure Skill Coding Practices
- Location
scripts/gen-news.mjs:119- Finding
Unrestricted Background Image Retrieval Enables Server-Side Request Forgery
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill’s Thai social-image purpose is coherent, but it uses broad system setup, privileged font installation, arbitrary URL image loading, and unrestricted file paths that users should review before installing.
Review this skill before installing. Prefer running it in a container or disposable workspace, avoid running setup with elevated privileges unless you accept system package and font changes, pin and verify dependencies and fonts, and do not pass untrusted background image URLs or output paths.
scripts/gen-news.mjs:119Unrestricted Background Image Retrieval Enables Server-Side Request Forgery
scripts/package.json:5Mutable npm Dependency Installation Creates a Supply-Chain Risk
scripts/setup.sh:65Downloaded Font Assets Are Not Integrity-Verified
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.
# === 5. Install fonts system-wide (Linux) ===
if [[ "$OS" == "debian" || "$OS" == "linux" ]]; then
SYSFONT_DIR="/usr/local/share/fonts/thai"
mkdir -p "$SYSFONT_DIR" 2>/dev/null || sudo mkdir -p "$SYSFONT_DIR"
cp "$FONTS_DIR"/*.ttf "$SYSFONT_DIR/" 2>/dev/null || sudo cp "$FONTS_DIR"/*.ttf "$SYSFONT_DIR/"
fc-cache -f 2>/dev/null || true
echo " Fonts installed to $SYSFONT_DIR"
Tool calls are chained to bypass individual safety checks or escalate capabilities beyond what any single tool call would allow.
# === 5. Install fonts system-wide (Linux) ===
if [[ "$OS" == "debian" || "$OS" == "linux" ]]; then
SYSFONT_DIR="/usr/local/share/fonts/thai"
mkdir -p "$SYSFONT_DIR" 2>/dev/null || sudo mkdir -p "$SYSFONT_DIR"
cp "$FONTS_DIR"/*.ttf "$SYSFONT_DIR/" 2>/dev/null || sudo cp "$FONTS_DIR"/*.ttf "$SYSFONT_DIR/"
fc-cache -f 2>/dev/null || true
echo " Fonts installed to $SYSFONT_DIR"
The skill instructs the agent to run shell commands for setup and image generation, but it does not declare any explicit tool scope or allowed-tools boundary. This is dangerous because an agent may invoke shell more broadly than intended, increasing the chance of unintended command execution or abuse if later content or parameters become attacker-controlled.
The trigger phrases are broad and overlap with common user requests like 'make content' or 'news image', which can cause the skill to activate outside a narrowly intended context. Over-broad activation is risky because it may route unrelated requests into a shell-capable skill, unnecessarily exposing execution paths and increasing the attack surface.
The file repeatedly frames the skill around generating images with Thai text overlay and Thai-friendly output, but does not state that Thai is optional or user-selected. This can violate language/locale policy when the user has not explicitly opted into Thai output.
The script reads any local path supplied in bgImage and writes output to any path supplied in output, with no restriction to a safe workspace directory. In an agent context this can be abused to probe file existence/read sensitive local files as image inputs or overwrite arbitrary writable files, which is broader than the advertised content-generation function and violates least privilege.
The script accepts a user-controlled bgImage value and, when it starts with "http", fetches and decodes a remote image. This expands the skill from local image rendering into outbound network access, creating SSRF/privacy and trust-boundary risks if an attacker can supply URLs to internal services or tracking endpoints; image decoders also increase exposure to malformed-image denial-of-service issues.
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
apt-get update -qq
apt-get install -y -qq build-essential libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev librsvg2-dev pkg-config 2>/dev/null || {
echo "⚠️ apt-get failed — trying without sudo"
sudo apt-get update -qq
sudo apt-get install -y -qq build-essential libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev librsvg2-dev pkg-config
}
elif [[ "$OS" == "macos" ]]; then
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.
apt-get update -qq
apt-get install -y -qq build-essential libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev librsvg2-dev pkg-config 2>/dev/null || {
echo "⚠️ apt-get failed — trying without sudo"
sudo apt-get update -qq
sudo apt-get install -y -qq build-essential libcairo2-dev libjpeg-dev libpango1.0-dev libgif-dev librsvg2-dev pkg-config
}
elif [[ "$OS" == "macos" ]]; then
The setup script copies downloaded font files into a system-wide directory under /usr/local/share/fonts and may invoke sudo implicitly. That causes privileged modification of the host outside the skill directory, which is risky because externally fetched files are being installed globally and can affect other processes or users on the machine.
The script may create a system font directory with sudo as part of an automatic setup path. Because this modifies privileged filesystem locations for a nonessential convenience feature, it broadens the blast radius of running the skill and can normalize elevation without clear consent.
# === 5. Install fonts system-wide (Linux) ===
if [[ "$OS" == "debian" || "$OS" == "linux" ]]; then
SYSFONT_DIR="/usr/local/share/fonts/thai"
mkdir -p "$SYSFONT_DIR" 2>/dev/null || sudo mkdir -p "$SYSFONT_DIR"
cp "$FONTS_DIR"/*.ttf "$SYSFONT_DIR/" 2>/dev/null || sudo cp "$FONTS_DIR"/*.ttf "$SYSFONT_DIR/"
fc-cache -f 2>/dev/null || true
echo " Fonts installed to $SYSFONT_DIR"
The script may copy downloaded TTF files into a privileged system directory using sudo. Installing externally retrieved files system-wide increases supply-chain risk and persists changes beyond the skill itself, making compromise or mistakes more impactful than local-only asset use.
if [[ "$OS" == "debian" || "$OS" == "linux" ]]; then
SYSFONT_DIR="/usr/local/share/fonts/thai"
mkdir -p "$SYSFONT_DIR" 2>/dev/null || sudo mkdir -p "$SYSFONT_DIR"
cp "$FONTS_DIR"/*.ttf "$SYSFONT_DIR/" 2>/dev/null || sudo cp "$FONTS_DIR"/*.ttf "$SYSFONT_DIR/"
fc-cache -f 2>/dev/null || true
echo " Fonts installed to $SYSFONT_DIR"
fi
The dependency uses a caret range (^3.1.0) rather than an exact pinned version, which makes builds non-reproducible and can silently pull newer releases. In a security-sensitive supply chain context, this increases exposure to unexpected regressions or malicious/compromised upstream updates, even though package.json by itself does not prove active exploitation.
"version": "1.0.0",
"type": "module",
"dependencies": {
"canvas": "^3.1.0"
}
}
The manifest references canvas without pinning an exact version, while the package has known historical advisories including memory corruption and denial of service. Because the resolved installed version is not verifiable from this manifest alone, there is a supply-chain risk that a vulnerable release could be installed, which matters more here because the skill processes image/text content and depends on native rendering code.
The setup script uses curl to fetch font files from GitHub, which is a network operation transmitting system request metadata to an external service. Although the script prints that it is downloading fonts, it does not clearly warn the user that it will contact external hosts as part of setup.
No suspicious patterns detected.