Back to skill

Security audit

元情 yotta-intel

Security checks for vulnerabilities and agentic risk

Overview

The skill's IOC extraction is coherent and local, but its installers can broadly modify agent skill directories and have unsafe overwrite/symlink handling that users should review before installing.

Review the installer behavior before using it. Prefer installing to one explicit skill directory with --agent or --dir, avoid --global unless you really want this skill in every supported agent, and do not run the installer from untrusted project directories. Treat CSV output from hostile reports as data for tools, not as a spreadsheet-safe file, unless formula cells are neutralized first.

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

Warning
Location
scripts/yotta_intel.py:435
Finding
CSV Formula Injection Through Attacker-Controlled IOC Context## Vulnerability Details **File Location**: `scripts/yotta_intel.py:333-344`, `scripts/yotta_intel.py:435-439` **Vulnerability Type**: CSV formula injection **Risk Level**: Medium ### Vulnerable Code ```python if entry is None: snippet = "" if 0 < idx <= len(orig_lines): snippet = orig_lines[idx - 1].strip() entry = { "type": ioc_type, "value": canonical, "defanged": defang_value(canonical, ioc_type), "count": 0, "first_line": idx, "snippet": snippet, } ``` ```python def build_csv(records): out = io.StringIO() w = csv.writer(out) w.writerow(["type", "value", "defanged", "count", "first_line", "snippet"]) for r in records: w.writerow([r["type"], r["value"], r["defanged"], r["count"], r["first_line"], r["snippet"]]) return out.getvalue() ``` ### Technical Analysis The tool processes potentially hostile threat reports, phishing messages, and logs. When an IOC is found, the complete original source line is copied into the `snippet` field. This attacker-controlled value is then written to CSV without neutralizing spreadsheet formula prefixes. The `csv.writer` function provides syntactically correct CSV quoting, but quoting does not prevent spreadsheet applications from interpreting cells beginning with characters such as `=`, `+`, `-`, or `@` as formulas. Leading whitespace and control characters can also be used to bypass simplistic prefix checks. Consequently, a CSV file generated from untrusted input may contain active formulas even though the output appears to be ordinary structured IOC data. ### Attack Path 1. An attacker creates a phishing message, threat report, or log line that begins with a spreadsheet formula and also contains a syntactically valid IOC. 2. A user runs: ```bash python3 scripts/yotta_intel.py extract --path hostile-report.txt --format csv --output iocs. ...[truncated 1205 chars]
Remediation
## Remediation Suggestions - Sanitize every attacker-controlled CSV cell before passing it to `csv.writer`, especially `snippet`. - After accounting for leading spaces, tabs, and control characters, prefix cells beginning with `=`, `+`, `-`, or `@` with an apostrophe. - Consider applying neutralization to every string field rather than only `snippet`, preventing future regressions if other fields become attacker-controlled. - Provide a separate raw machine-import format, such as JSON, if preserving the exact source line is required. - Clearly document whether CSV output is safe for direct use in spreadsheet applications. - Add automated tests covering dangerous prefixes, leading whitespace, tabs, carriage returns, and quoted formulas. - Example hardening helper: ```python def safe_csv_cell(value): if not isinstance(value, str): return value probe = value.lstrip(" \t\r\n") if probe.startswith(("=", "+", "-", "@")): return "'" + value return value ```

T09 · Insecure Skill Coding Practices

Warning
Location
install.sh:63
Finding
Shell Installer Follows Pre-Existing Destination Symlinks## Vulnerability Details **File Location**: `install.sh:63-67` **Vulnerability Type**: Symlink-based arbitrary file overwrite and destructive deletion **Risk Level**: Medium ### Vulnerable Code ```bash install_to() { mkdir -p "$1/$SKILL_NAME" cp -r "$SOURCE_DIR/." "$1/$SKILL_NAME/" rm -rf "$1/$SKILL_NAME/.git" echo "installed -> $1/$SKILL_NAME" } ``` ### Technical Analysis The shell installer creates or reuses a destination named `yotta-intel` and recursively copies the package into it. It does not use `lstat`, canonical path validation, or any equivalent check to determine whether the destination or one of its parent components is a symbolic link. If the destination already exists as a symlink to another directory, the copy operation can follow that link and overwrite matching files in the linked directory. The subsequent recursive deletion of `"$1/$SKILL_NAME/.git"` can likewise operate on the `.git` directory beneath the symlink target. The default installation mode also scans the current project for known agent directories. A malicious project can therefore prepare a hostile Skill destination before asking a user to run `install.sh`. ### Attack Path 1. An attacker controls or contributes files to a project that the victim opens locally. 2. The project contains an auto-detected directory such as `.codex/skills`. 3. The attacker places `.codex/skills/yotta-intel` as a symlink to another directory writable by the victim. 4. The victim runs: ```bash bash install.sh ``` Alternatively, the victim supplies an attacker-influenced path through `--dir`. 5. `install_to` reuses the symlink instead of rejecting it. 6. `cp -r` writes package files into the symlink target, overwriting files with matching names. 7. The `rm -rf` command may delete the `.git` directory under the linked target. ### Impact Assessment Exploitation can modify or delete files anywhere writable by the invok ...[truncated 629 chars]
Remediation
## Remediation Suggestions - Reject a destination if `yotta-intel` already exists as a symbolic link. - Canonicalize the destination parent with `realpath` and verify that the final target remains under the explicitly selected Skill directory. - Check every existing path component for symlinks before copying. - Do not recursively delete `.git` through an unresolved destination path. - Prefer creating a new temporary directory beside the destination, copying verified files into it, and atomically renaming it into place. - Refuse to overwrite an existing installation by default, or require an explicit `--force` option after displaying the canonical destination. - Limit copied files to an explicit allowlist rather than recursively copying the entire source tree. - Add tests for destination symlinks, parent-directory symlinks, pre-existing files, and interrupted installations.

T09 · Insecure Skill Coding Practices

Warning
Location
bin/install.js:132
Finding
Node.js Installer Does Not Reject Symlinked or Pre-Existing Installation Targets## Vulnerability Details **File Location**: `bin/install.js:132-158` **Vulnerability Type**: Symlink-based arbitrary file overwrite **Risk Level**: Medium ### Vulnerable Code ```javascript function copyDir(src, dst, skip) { for (const entry of fs.readdirSync(src, { withFileTypes: true })) { if (skip.has(entry.name)) continue; const from = path.join(src, entry.name); const to = path.join(dst, entry.name); try { if (entry.isDirectory()) { fs.mkdirSync(to, { recursive: true }); copyDir(from, to, skip); } else if (entry.isFile()) { fs.copyFileSync(from, to); } } catch (err) { throw new InstallError('Failed to copy ' + from + ' -> ' + to + ': ' + err.message); } } } function installTo(dest) { if (!dest || typeof dest !== 'string') throw new UsageError('Destination directory is required'); const target = path.resolve(dest, SKILL_NAME); assertSafeTarget(target); try { fs.mkdirSync(target, { recursive: true }); copyDir(PKG_ROOT, target, COPY_SKIP); if (!fs.existsSync(path.join(target, 'SKILL.md'))) { throw new InstallError('Installed directory is missing SKILL.md'); } } catch (err) { if (err instanceof UsageError || err instanceof InstallError) throw err; throw new InstallError('Cannot install to ' + target + ': ' + err.message); } console.log('installed -> ' + target); return target; } ``` ### Technical Analysis `installTo` performs a lexical safety check through `assertSafeTarget`, but it does not resolve the real destination or inspect it with `lstat`. Lexical checks cannot detect that a path component or the final `yotta-intel` directory is a symbolic link. The recursive copy operation also overwrites existing files without confirmation. If the destination directory or individual destination files are symlinks, filesystem operations may follow them a ...[truncated 1579 chars]
Remediation
## Remediation Suggestions - Call `fs.lstatSync` on the destination and every existing parent component, rejecting symbolic links. - Resolve the canonical parent using `fs.realpathSync` and ensure the canonical target remains beneath the intended canonical Skill directory. - Open destination files with no-follow and exclusive-creation semantics where supported. - Refuse to overwrite an existing installation unless the user supplies an explicit `--force` option. - Install into a newly created temporary directory and atomically rename it after validation. - Verify that the resulting target is a real directory owned or controlled by the current user. - Add installer tests covering final-target symlinks, parent symlinks, symlinked child files, existing installations, and `--global` mode.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

Context-Inappropriate Capability

Medium
Confidence
83% confidence
Finding
The global installation path writes the skill into many agent-specific directories under the user's home directory in one invocation, effectively propagating the package across multiple tools. While not overtly malicious, this broad self-install capability increases blast radius if the package is tampered with or the user did not intend to modify every supported agent environment.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
Global mode performs writes to multiple user-level directories without any interactive confirmation, warning banner, or per-target consent. This creates a significant trust and safety issue because a single command can silently alter many agent environments, making accidental installation or unwanted persistence across tools more likely.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The installer performs recursive copy and deletion into a caller-controlled destination without any confirmation, backup, or overwrite warning. Running it against an existing skill directory can silently replace files and remove the destination .git directory, causing unintended data loss or corruption of an existing installation.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
install_to() {
  mkdir -p "$1/$SKILL_NAME"
  cp -r "$SOURCE_DIR/." "$1/$SKILL_NAME/"
  rm -rf "$1/$SKILL_NAME/.git"
  echo "installed -> $1/$SKILL_NAME"
}
Confidence
94% confidence
Finding
The script uses rm -rf on a path derived from the install destination, and that destination can come from --dir or environment-dependent path resolution. Although variables are quoted and the deleted path is limited to the .git subdirectory under the skill folder, a mistaken or maliciously influenced target path can still cause destructive filesystem changes in an unintended location.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
test/install.test.js:12