T09 · Insecure Skill Coding Practices
- Location
scripts/bulletin.py:277- Finding
Unrestricted Fetching of Feed-Controlled Article URLs Enables SSRF
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill mostly matches its newsletter purpose, but it can automatically use a user's SMTP account to email hard-coded third-party recipients and fetch feed-controlled article URLs without adequate guardrails.
Review and edit scripts/bulletin.py before installing or running: replace EMAIL_ADDRESSES, use least-privilege SMTP credentials, avoid enabling the cron job until recipients are confirmed, and restrict article fetching and the Ollama endpoint to trusted destinations.
scripts/bulletin.py:277Unrestricted Fetching of Feed-Controlled Article URLs Enables SSRF
scripts/bulletin.py:35Hard-Coded Third-Party Recipient List Causes Unintended Email Disclosure
SKILL.md:43Unpinned Python Dependencies Create Supply-Chain and Reproducibility Risk
The documented behavior understates what the skill does: it sends content to a hardcoded Ollama endpoint, may fetch full article pages beyond the stated feeds, and may email hardcoded recipients. This mismatch is dangerous because reviewers and users cannot accurately assess data flows, which can lead to unapproved exfiltration of content, internal-network interaction, and unintended outbound email delivery.
The skill declares environment-variable and network capabilities in metadata but does not define an explicit tool scope such as permissions or allowed-tools. That weakens containment and reviewability, making it easier for the skill to access sensitive credentials and perform outbound network actions without clear user-visible authorization boundaries.
The skill is designed to send email to configured recipients but does not require recipient verification or provide a user-facing warning before outbound transmission. In context, this increases the chance of sending generated content to unintended recipients or using the skill as an unreviewed exfiltration path.
The documentation instructs operators to provide SMTP credentials via environment variables without warning about secure handling, storage, or least-privilege use. In a skill that performs outbound email and network access, this raises the risk of credential misuse, accidental leakage, or reuse of high-privilege mailbox credentials.
The skill description says it collects and sends a digest, but the implementation additionally transmits article bodies to a remote Ollama endpoint for summarization. That extra external disclosure is security-relevant because operators may not expect third-party/internal-service sharing of fetched content, and the service is contacted over plain HTTP.
This duplicate finding points to the same outbound POST to 172.20.86.203 carrying article text. The danger is not the existence of networking alone, but that fetched content is relayed to another host over an unauthenticated cleartext channel without clear disclosure.
try:
logging.debug(f"Summarizing article with Ollama: {text}...")
resp = requests.post(
"http://172.20.86.203:11434/api/generate",
json={
"model": model,
This duplicate finding points to the same outbound POST to 172.20.86.203 carrying article text. The danger is not the existence of networking alone, but that fetched content is relayed to another host over an unauthenticated cleartext channel without clear disclosure.
try:
logging.debug(f"Summarizing article with Ollama: {text}...")
resp = requests.post(
"http://172.20.86.203:11434/api/generate",
json={
"model": model,
Article content is sent to a remote summarization service with no user-facing warning, consent, or configuration toggle. Even if the content is public, undisclosed outbound transmission to another service expands the data exposure surface and can have compliance or trust implications.
Code issues a request to a loopback, link-local, or private-range host. This can reach internal services not meant to be exposed and is a common SSRF pivot.
try:
logging.debug(f"Summarizing article with Ollama: {text}...")
resp = requests.post(
"http://172.20.86.203:11434/api/generate",
json={
"model": model,
The code fetches full article text from arbitrary external URLs and forwards that content to a separate summarization service at 172.20.86.203 without validating trust boundaries or minimizing disclosure. This creates a real data-flow issue because untrusted remote content is retransmitted to another system, which may violate data-handling expectations and can expose internal processing to prompt-injection-style manipulation of the summarizer.
try:
logging.debug(f"Summarizing article with Ollama: {text}...")
resp = requests.post(
"http://172.20.86.203:11434/api/generate",
json={
"model": model,
Output size or generation rate is not bounded. Unbounded output enables denial-of-service through resource exhaustion, log flooding, or context-window stuffing.
if not summary and article.get('description'):
desc = article['description']
# TLDR AI articles: use the full curated summary without truncation
if article.get('source') == 'TLDR AI':
summary = desc
else:
The script accesses sensitive environment variables SMTP_EMAIL and SMTP_PASSWORD, then uses them to authenticate to Gmail and send emails. Although this is functionally necessary, the file lacks a user-facing warning or explicit documentation comment alerting operators that credentials are required and will be used for outbound email.
The function docstring and module description describe sending a tech and AI news bulletin, but the actual From display name is set to 'AI Health Bulletin'. This is an active contradiction in user-facing intent and could mislead recipients about the nature of the message.
The code accesses environment variables for SMTP credentials to authenticate and send mail. While email delivery is part of the stated purpose, credential access is a sensitive capability that is not reflected in the manifest description and goes beyond simple collection/merging behavior described there.
No suspicious patterns detected.