T09 · Insecure Skill Coding Practices
- Location
scripts/moderate.py:218- Finding
Prompt Injection Can Trigger Destructive Automatic Moderation Actions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a coherent YouTube moderation tool, but its auto mode can delete comments and post replies from LLM output with weak safeguards around OAuth and stored tokens.
Install only if you are comfortable granting YouTube comment write access. Prefer monitor or approval mode, avoid auto deletion and auto replies until safeguards are added, do not paste full OAuth callback URLs into chat, keep token/config/database files private, and restrict or rotate API keys if they may have been exposed.
scripts/moderate.py:218Prompt Injection Can Trigger Destructive Automatic Moderation Actions
scripts/setup.py:104OAuth Authorization Flow Does Not Validate State or Use PKCE
You can close this tab and return to the terminal.
""") else: OAuthCallbackHandler.error = query.get("error", ["unknown"])[0] self.send_response(400) self.send_header("Content-Type", "text/html") self.end_headers() self.wfile.write(f"scripts/setup.py:267Sensitive OAuth Tokens and Moderation Data Are Stored Without Explicit File Protections
scripts/setup.py:401YouTube API Key Is Unnecessarily Duplicated into Plaintext Configuration
skills/youtube-comment-moderator/SKILL.md:53Packaged Skill Instructions Require Users to Paste an OAuth Callback Credential into Chat
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
})
try:
with urlopen(req, timeout=30) as resp:
data = json.loads(resp.read())
text = data["candidates"][0]["content"]["parts"][0]["text"]
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
})
try:
with urlopen(req, timeout=30) as resp:
data = json.loads(resp.read())
text = data["candidates"][0]["content"]["parts"][0]["text"]
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"https://www.googleapis.com/youtube/v3/videos?part=snippet&id={video_id}&key={api_key}"
req = Request(url, headers={"User-Agent": "YT-Moderator/1.0"})
try:
with urlopen(req, timeout=15) as resp:
data = json.loads(resp.read())
if data.get("items"):
return data["items"][0]["snippet"]["channelId"]
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"https://www.googleapis.com/youtube/v3/videos?part=snippet&id={video_id}&key={api_key}"
req = Request(url, headers={"User-Agent": "YT-Moderator/1.0"})
try:
with urlopen(req, timeout=15) as resp:
data = json.loads(resp.read())
if data.get("items"):
return data["items"][0]["snippet"]["channelId"]
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{BASE_URL}/{endpoint}?{urlencode(params)}"
req = Request(url, headers={"User-Agent": "YT-Moderator/2.0"})
try:
with urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
except HTTPError as e:
print(f" API error {e.code}: {e.read().decode()[:200]}", file=sys.stderr)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{BASE_URL}/{endpoint}?{urlencode(params)}"
req = Request(url, headers={"User-Agent": "YT-Moderator/2.0"})
try:
with urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
except HTTPError as e:
print(f" API error {e.code}: {e.read().decode()[:200]}", file=sys.stderr)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{BASE_URL}/{endpoint}?{urlencode(params)}"
req = Request(url, headers={"User-Agent": "YT-Moderator/2.0"})
try:
with urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
except HTTPError as e:
print(f" API error {e.code}: {e.read().decode()[:200]}", file=sys.stderr)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{BASE_URL}/{endpoint}?{urlencode(params)}"
req = Request(url, headers={"User-Agent": "YT-Moderator/2.0"})
try:
with urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
except HTTPError as e:
print(f" API error {e.code}: {e.read().decode()[:200]}", file=sys.stderr)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{BASE_URL}/{endpoint}?{urlencode(params)}"
req = Request(url, headers={"User-Agent": "YT-Moderator/2.0"})
try:
with urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
except HTTPError as e:
print(f" API error {e.code}: {e.read().decode()[:200]}", file=sys.stderr)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{BASE_URL}/{endpoint}?{urlencode(params)}"
req = Request(url, headers={"User-Agent": "YT-Moderator/2.0"})
try:
with urlopen(req, timeout=15) as resp:
return json.loads(resp.read())
except HTTPError as e:
print(f" API error {e.code}: {e.read().decode()[:200]}", file=sys.stderr)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
headers={"Authorization": f"Bearer {token}"}
)
try:
with urlopen(req, timeout=10):
return token
except HTTPError:
pass
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
headers={"Authorization": f"Bearer {token}"}
)
try:
with urlopen(req, timeout=10):
return token
except HTTPError:
pass
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{BASE_URL}/comments/setModerationStatus?{urlencode({'id': comment_id, 'moderationStatus': status})}"
req = Request(url, method="POST", headers={"Authorization": f"Bearer {token}"})
try:
with urlopen(req, timeout=15):
return True
except HTTPError as e:
print(f" Moderation error {e.code}: {e.read().decode()[:200]}", file=sys.stderr)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{BASE_URL}/comments/setModerationStatus?{urlencode({'id': comment_id, 'moderationStatus': status})}"
req = Request(url, method="POST", headers={"Authorization": f"Bearer {token}"})
try:
with urlopen(req, timeout=15):
return True
except HTTPError as e:
print(f" Moderation error {e.code}: {e.read().decode()[:200]}", file=sys.stderr)
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
req = Request(url, data=body.encode(), headers={"Content-Type": "application/json"})
try:
with urlopen(req, timeout=60) as resp:
data = json.loads(resp.read())
text = data["candidates"][0]["content"]["parts"][0]["text"].strip()
if text.startswith("```"):
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
req = Request(url, data=body.encode(), headers={"Content-Type": "application/json"})
try:
with urlopen(req, timeout=60) as resp:
data = json.loads(resp.read())
text = data["candidates"][0]["content"]["parts"][0]["text"].strip()
if text.startswith("```"):
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
})
req = Request(url, data=body.encode(), headers={"Content-Type": "application/json"})
try:
with urlopen(req, timeout=30) as resp:
data = json.loads(resp.read())
return data["candidates"][0]["content"]["parts"][0]["text"].strip().strip('"')
except Exception as e:
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
})
req = Request(url, data=body.encode(), headers={"Content-Type": "application/json"})
try:
with urlopen(req, timeout=30) as resp:
data = json.loads(resp.read())
return data["candidates"][0]["content"]["parts"][0]["text"].strip().strip('"')
except Exception as e:
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"https://www.googleapis.com/youtube/v3/channels?part=snippet&forHandle={handle}&key={api_key}"
req = Request(url, headers={"User-Agent": "YT-Moderator/1.0"})
try:
with urlopen(req, timeout=15) as resp:
data = json.loads(resp.read())
if data.get("items"):
channel_id = data["items"][0]["id"]
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"https://www.googleapis.com/youtube/v3/channels?part=snippet&forHandle={handle}&key={api_key}"
req = Request(url, headers={"User-Agent": "YT-Moderator/1.0"})
try:
with urlopen(req, timeout=15) as resp:
data = json.loads(resp.read())
if data.get("items"):
channel_id = data["items"][0]["id"]
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"https://www.googleapis.com/youtube/v3/channels?part=snippet&forHandle={handle}&key={api_key}"
req = Request(url, headers={"User-Agent": "YT-Moderator/1.0"})
try:
with urlopen(req, timeout=15) as resp:
data = json.loads(resp.read())
if data.get("items"):
channel_id = data["items"][0]["id"]
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"https://www.googleapis.com/youtube/v3/channels?part=snippet&forHandle={handle}&key={api_key}"
req = Request(url, headers={"User-Agent": "YT-Moderator/1.0"})
try:
with urlopen(req, timeout=15) as resp:
data = json.loads(resp.read())
if data.get("items"):
channel_id = data["items"][0]["id"]
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"https://www.googleapis.com/youtube/v3/channels?part=snippet&forHandle={handle}&key={api_key}"
req = Request(url, headers={"User-Agent": "YT-Moderator/1.0"})
try:
with urlopen(req, timeout=15) as resp:
data = json.loads(resp.read())
if data.get("items"):
channel_id = data["items"][0]["id"]
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"https://www.googleapis.com/youtube/v3/channels?part=snippet&forHandle={handle}&key={api_key}"
req = Request(url, headers={"User-Agent": "YT-Moderator/1.0"})
try:
with urlopen(req, timeout=15) as resp:
data = json.loads(resp.read())
if data.get("items"):
channel_id = data["items"][0]["id"]
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"https://www.googleapis.com/youtube/v3/channels?part=snippet&forHandle={handle}&key={api_key}"
req = Request(url, headers={"User-Agent": "YT-Moderator/1.0"})
try:
with urlopen(req, timeout=15) as resp:
data = json.loads(resp.read())
if data.get("items"):
channel_id = data["items"][0]["id"]
No suspicious patterns detected.