T09 · Insecure Skill Coding Practices
Warning
- Location
- auto_tweet.py:98
- Finding
- Unrestricted Research Scan Content Is Transmitted to OpenAI and Can Influence Automated X Posts<![CDATA[ ## Vulnerability Details **File Location**: `auto_tweet.py:39, 98-106, 124-170` **Vulnerability Type**: `T09: Insecure Skill Coding Practices` **Risk Level**: Medium ### Vulnerable Code ```python # Optional: research scan directory for context-aware tweets SCAN_DIR = os.environ.get("SCAN_DIR", "") ``` ```python def get_latest_scan(): """Read the most recent research scan report (optional).""" if not SCAN_DIR or not os.path.isdir(SCAN_DIR): return "" files = sorted(os.listdir(SCAN_DIR), reverse=True) for f in files: if f.endswith(".md"): with open(os.path.join(SCAN_DIR, f)) as fh: return fh.read()[:3000] return "" ``` ```python def generate_tweet(): """Use OpenAI to generate a tweet.""" scan = get_latest_scan() recent = get_recent_tweets() topic = random.choice(TOPICS) banned = ", ".join(f'"{p}"' for p in BANNED_PHRASES) prompt = f"""{PERSONA} Write ONE tweet (max 220 chars) about: {topic} Context — today's research scan (use as inspiration, don't copy verbatim): {scan[:1500] if scan else "(no scan available today)"} Recent tweets (DO NOT repeat similar topics or phrasing): {recent[:800] if recent else "(none yet)"} CRITICAL RULES: - MUST be under 220 characters (count carefully — spaces, emoji, @mentions all count) - MUST include at least one @mention - NEVER FABRICATE DATA. Do NOT invent numbers, stats, percentages, or metrics. - NO generic filler. BANNED phrases: {banned} - NEVER end with a generic motivational statement. - Shorter is ALWAYS better. 140 chars > 220 chars. - One idea per tweet. - Output ONLY the tweet text, nothing else. No quotes around it. VARIETY (critical — never repeat the same format): - Mix formats: bold claims, disagreements, questions, one-liners, mini-stories - Mix tone: funny, dead serious, provocative, vulnerable - NEVER start two tweets the same way. - BE BOLD. Safe tweets get zero engagement. """ resp = requests.post( ...[truncated 3500 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require explicit opt-in before reading or transmitting research scans, and clearly document that their contents are sent to OpenAI. 2. Restrict `SCAN_DIR` to a dedicated directory rather than accepting an arbitrary readable path. 3. Resolve paths with `os.path.realpath()` and reject files that escape the approved directory. 4. Reject symbolic links and verify that selected files are regular files with expected ownership and restrictive permissions. 5. Add secret and sensitive-data detection or redaction before including scan content in an external request. 6. Delimit scan content as untrusted quoted data and add explicit instructions that the model must not follow commands found inside that content. 7. Use structured messages that separate system instructions from untrusted contextual data. 8. Validate generated output against explicit content and disclosure policies instead of checking only its character length. 9. Require human approval before publishing content derived from untrusted or externally populated scans. 10. Run the scheduled task under a dedicated low-privilege operating-system account with read access only to its dedicated scan and log directories. ]]>
