T09 · Insecure Skill Coding Practices
- Location
scripts/run_briefing.py:44- Finding
Automatic Publication of Unsanitized External Content
- Content
View full analysis
Vulnerability Details
File Location:
scripts/run_briefing.py:44-48, 51-70, 91-103, 137-140, 169-174;scripts/run-briefing.sh:7
Vulnerability Type: Untrusted external content used in an automatic social-media publishing sink
Risk Level: HighVulnerable Code
python def fetch_profile_markdown(handle: str, timeout: int = 25) -> str: url = f"https://r.jina.ai/http://x.com/{handle}" r = requests.get(url, timeout=timeout) r.raise_for_status() return r.textpython def extract_signal_lines(md: str, max_lines: int = 8) -> List[str]: lines = [ln.strip() for ln in md.splitlines()] cleaned = [] bad_prefixes = ( "Title:", "URL Source:", "Published Time:", "Markdown Content:", "Pinned", "Quote", "[![Image", "![Image" ) for ln in lines: if not ln or len(ln) < 40 or len(ln) > 320: continue if ln.startswith(bad_prefixes): continue if re.match(r"^@?[A-Za-z0-9_\.-]+$", ln): continue if "http" in ln and len(ln) < 80: continue if ln in cleaned: continue cleaned.append(ln) if len(cleaned) >= max_lines: break return cleanedpython md = fetch_profile_markdown(h) lines = extract_signal_lines(md, max_lines=6) if not lines: unavailable.append((h, name, "页面可读但未提取到有效近况")) continue total_lines += len(lines) bullets = "\n".join([f"- {x}" for x in lines[:4]]) section = ( f"### @{h} ({name})\n" f"- 近{days}天可见高信号摘录(基于公开页面抓取):\n" f"{bullets}\n" ) sections.append(section) top_items.append({"handle": h, "name": name, "line": lines[0]})python tweet = "📊 AI Creator Briefing ({date})\n\nTop updates:\n{items}\n\nFull briefing saved in workspace reports.\n\n#AI #OpenClaw #Agent".format( date=date_str, items="\n".join([f"{i+1}. @{it['handle']}: {it['line'][:90]}" for i, it in enumerate(top_items[:3])]) or "1. No strong public updates captured ...[truncated 2965 chars]- Remediation
View remediation
Remediation Suggestions
- Make draft-only behavior the default. Remove
--publishfromscripts/run-briefing.shand require a separate, explicit publication action. - Add a human approval gate that displays the exact final tweet and requires confirmation immediately before invoking the posting tool.
- Treat mirror output as untrusted input. Parse structured post records rather than selecting arbitrary page lines.
- Validate post provenance, author identity, post URL, and timestamp. Enforce the requested date window before content becomes eligible.
- Allow only expected text characters and normalize Unicode. Remove bidirectional controls, zero-width characters, unexpected line breaks, and other control characters.
- Reject or neutralize external URLs and mentions unless they pass explicit allowlists. Revalidate the fully rendered tweet rather than only individual source lines.
- Apply the configured keyword, engagement, active-account, and content-safety filters in code. Fail closed when extraction or validation is ambiguous.
- Add integrity and availability controls for the external mirror, or use an authenticated and structured upstream API where feasible.
- Record the exact source post URL and validation decisions in metadata so operators can audit why content was selected.
- Ensure scheduled jobs generate drafts only, or route drafts into an approval queue instead of directly publishing them.
- Make draft-only behavior the default. Remove
