T09 · Insecure Skill Coding Practices
- Location
scripts/screenshot_tweet.py:221- Finding
API Key Exposure Through Command-Line Arguments
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This skill is a straightforward Twitter/X screenshot generator that uses the documented TwitterShots API, but users should understand that tweet identifiers and an API key are sent to that third-party service.
Install only if you are comfortable sending tweet IDs, rendering options, optional background image URLs, and your TwitterShots API key to TwitterShots. Prefer TWITTERSHOTS_API_KEY from a protected environment or secret manager instead of --api-key or shell history, and use the skill only when you explicitly want a screenshot generated.
scripts/screenshot_tweet.py:221API Key Exposure Through Command-Line Arguments
SKILL.md:17Unpinned Third-Party Python Dependency
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
url = f"{API_BASE}/{tweet_id}"
response = requests.get(
url,
headers={
"X-API-KEY": api_key,
The README describes generating screenshots through the TwitterShots API but does not clearly warn users that tweet URLs, tweet IDs, and related formatting choices are sent to an external service. This omission undermines informed consent and can expose user activity, targets of interest, or sensitive workflow context to a third party.
The README states that the skill 'triggers automatically when you paste a tweet URL in the chat' without defining scope, confirmation behavior, or data-handling boundaries. In an agent environment, broad automatic triggers can cause unintended invocation and silent transmission of user-provided tweet URLs to the external TwitterShots service, increasing the risk of privacy leaks and prompt-trigger abuse.
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.
Skills live in ~/.claude/skills/. Clone this repo:
git clone https://github.com/twittershots/skills.git ~/.claude/skills/twittershots
The phrase 'invoke the skill when relevant' is too vague for a security-sensitive integration because it leaves invocation decisions to broad model interpretation. That ambiguity can lead to accidental execution in unrelated contexts and unintended disclosure of tweet URLs or IDs to an external service.
The usage section encourages natural-language triggering like 'Simply paste a tweet URL or ID' and 'automatically invoke this Skill' without clear constraints or consent steps. In practice, this can make the skill fire on incidental content and send user-supplied links or identifiers to a third-party API without sufficiently explicit intent.
The skill performs network access to a third-party API and reads a secret from the environment, but it does not declare an explicit tool/permission scope. That omission weakens reviewability and policy enforcement because consumers cannot easily tell that the skill will transmit user-supplied tweet identifiers and an API credential to an external service.
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.
generate tweet image, convert tweet to PNG/SVG/HTML, create tweet screenshot
for social media (Instagram, TikTok), or mentions "TwitterShots", "tweet screenshot",
"capture tweet", "tweet image". Triggers on tweet URLs (twitter.com/*/status/* or x.com/*/status/*)
or tweet IDs. Default to format=png and theme=light without asking follow-up questions;
if the user explicitly provides format and/or theme, use the user-provided values.
homepage: https://github.com/twittershots/skills
source: https://github.com/twittershots/skills
This skill is explicitly designed to send tweet identifiers and rendering options to api.twittershots.com, along with an API key in a request header. External transmission is expected for the feature, but it still creates confidentiality and supply-chain risk because user content and metadata are sent to a third party.
Endpoint: GET https://api.twittershots.com/api/v1/screenshot/:statusId
Required Header:
The skill allows a user-controlled backgroundImage HTTPS URL to be forwarded to the external rendering service. That can enable server-side fetching by the third-party service, creating SSRF-like or privacy risks against the remote service and causing user-supplied URLs to be transmitted without restriction.
# Gradient background
curl -X GET "https://api.twittershots.com/api/v1/screenshot/1617979122625712128?format=png&containerBackground=linear-gradient(90deg,%23003f5b,%232b4b7d,%235f5195)" \
-H "X-API-KEY: YOUR_API_KEY" \
-H "Accept: image/png" \
-o tweet-gradient.png
The Python example performs the actual outbound request and includes the API key header, confirming the skill sends data and credentials to a third-party service. This is expected functionality, but it remains security-relevant because compromise or misuse of the remote service could expose request contents or abuse the credential.
params["backgroundImage"] = background_image
response = requests.get(
f"https://api.twittershots.com/api/v1/screenshot/{tweet_id}",
headers={
"X-API-KEY": api_key,
"Accept": f"image/{format}" if format != "html" else "text/html"
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
sys.exit(1)
API_BASE = "https://api.twittershots.com/api/v1/screenshot"
def extract_tweet_id(input_str: str) -> str:
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
sys.exit(1)
API_BASE = "https://api.twittershots.com/api/v1/screenshot"
def extract_tweet_id(input_str: str) -> str:
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
sys.exit(1)
API_BASE = "https://api.twittershots.com/api/v1/screenshot"
def extract_tweet_id(input_str: str) -> str:
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
sys.exit(1)
API_BASE = "https://api.twittershots.com/api/v1/screenshot"
def extract_tweet_id(input_str: str) -> str:
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
sys.exit(1)
API_BASE = "https://api.twittershots.com/api/v1/screenshot"
def extract_tweet_id(input_str: str) -> str:
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
sys.exit(1)
API_BASE = "https://api.twittershots.com/api/v1/screenshot"
def extract_tweet_id(input_str: str) -> str:
This markdown file applies to SQP-2, and it explicitly tells the agent to "Save buffer to file" as part of the workflow. While file output is part of the skill's purpose, the documentation does not warn the user that using the skill may create local files or require choosing a safe path/filename, which is a missing disclosure for a data-affecting action.
This code makes an HTTP request to a third-party service and transmits the requested tweet ID plus user-supplied rendering options. Although the script's purpose implies API usage, there is no clear disclosure in the runtime messages or docstring that user input is sent to an external service.
The code accesses the TWITTERSHOTS_API_KEY environment variable, which is a sensitive credential source. While required for functionality, the file does not include an explicit warning or comment noting that it reads credentials from the environment.