Back to skill

Security audit

n0ir DeFi Yield Scout

Security checks for vulnerabilities and agentic risk

Overview

This skill coherently fetches public DeFi yield data and shows comparisons, but its local cache should be treated as a low-level integrity risk.

Install only if you are comfortable with a tool that fetches public DeFiLlama yield data and writes a short-lived local cache. Treat results as advisory, verify pools and APYs on-chain before moving funds, and prefer a future version that stores cache data in a private per-user cache directory.

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

Warning
Location
scripts/yield_scout.py:24
Finding

Predictable Shared Temporary Cache Enables Data Poisoning and Symlink-Based File Overwrite

Content
View full analysis

Vulnerability Details

File Location: scripts/yield_scout.py, lines 24 and 73–85
Vulnerability Type: Unsafe temporary-file handling
Risk Level: Medium

Vulnerable code:

python
CACHE_PATH = os.path.join(tempfile.gettempdir(), "yield_scout_pools.json")
python
def load_pools(force=False):
    if not force and os.path.exists(CACHE_PATH):
        age = time.time() - os.path.getmtime(CACHE_PATH)
        if age < CACHE_TTL:
            with open(CACHE_PATH, "r") as f:
                return json.load(f)

    print("Fetching pool data from DeFiLlama (this may take a moment)...", file=sys.stderr)
    data = fetch_json(POOLS_URL, timeout=120)
    pools = data.get("data", data) if isinstance(data, dict) else data

    with open(CACHE_PATH, "w") as f:
        json.dump(pools, f)

    return pools

Technical Analysis

The pool cache is stored under a fixed, predictable name in the system-wide temporary directory. The implementation does not verify that the cache is a regular file, is owned by the current user, has restrictive permissions, or is not a symbolic link.

When the file's modification time is less than 15 minutes old, its JSON content is trusted as pool data without checking its origin or integrity. A local attacker who can write to the shared temporary directory can therefore provide fabricated pool records. Those records can influence APY rankings, TVL values, risk labels, and breakeven recommendations.

The refresh path opens the same predictable location using normal write mode. This follows symbolic links and truncates the resolved target before writing JSON. A local attacker may pre-create the cache path as a symbolic link to another file. Exploitation is limited to targets writable by the account running the Skill; the code does not independently grant elevated privileges.

Attack Path

Cache-poisoning path:

  1. A local attacker creates `/tmp/yield_sco ...[truncated 1868 chars]
Remediation
View remediation

Remediation Suggestions

  • Store cached data in a private, per-user cache directory rather than a shared temporary directory. Create the directory with mode 0700.
  • Create cache files with mode 0600 and verify that existing files are owned by the current user.
  • Reject symbolic links and non-regular files before reading. Where supported, open files using os.open() with O_NOFOLLOW.
  • Avoid check-then-open sequences based on exists() and getmtime(), which are vulnerable to time-of-check/time-of-use races.
  • Write refreshed data to a securely created temporary file in the private cache directory, flush and optionally fsync() it, then atomically replace the cache using os.replace().
  • Validate the cached JSON structure and expected field types before using it.
  • Consider recording and verifying an integrity digest or trusted metadata if cache authenticity must be protected from same-user processes.
  • On validation, ownership, permission, or file-type failure, discard the cache and securely retrieve a fresh copy.
Vulnerability Patterns
  • 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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (1)

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
79% confidence
Finding

This code writes API-derived data to a temp-file cache at a fixed path, which is a file write operation. Although the script prints when fetching data, it does not disclose that it persists results locally, and the module docstring/CLI help also do not mention local caching behavior.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.