T09 · Insecure Skill Coding Practices
- Location
SKILL.md:125- Finding
Apify API Token Exposed Through URL Query Parameters in Skill Instructions
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is a coherent web-scraping helper, but it needs Review because its Apify examples put API tokens in URLs and its scraping/data-sharing guidance is under-scoped.
Install only if users understand that scraping targets, queries, actor inputs, and results may be sent to Firecrawl or Apify. Prefer authorization headers and environment variables for tokens, avoid query-string tokens, do not scrape confidential/internal/authenticated pages without approval, and start with small limits and site-compliant use.
SKILL.md:125Apify API Token Exposed Through URL Query Parameters in Skill Instructions
references/code-templates.md:111Apify Code Templates Transmit API Tokens as Query Parameters
The skill's invocation rules are overly broad and directive, including phrases like 'always use this skill' for many generic web-data requests. This can cause the agent to route ordinary information-retrieval tasks into active scraping/crawling flows, increasing the chance of unnecessary external requests, policy bypass, and data collection from third-party sites without adequate user intent verification.
The skill encourages scraping and crawling but provides no warning or gating around privacy, terms-of-service, sensitive data capture, or load/impact on target websites. In practice, this omission can lead the agent to help collect personal or restricted data, or perform large crawls without informing the user of legal and operational constraints.
This code performs an outbound API request to Firecrawl and includes a target URL in the request body, meaning user-selected browsing targets are transmitted to an external service. In the context of a scraping skill, that behavior is expected, but it is still security-relevant because it can expose sensitive URLs, metadata, or extracted content to a third party.
API_KEY = "fc-YOUR_API_KEY"
response = requests.post(
"https://api.firecrawl.dev/v2/scrape",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={
This code performs an outbound API request to Firecrawl and includes a target URL in the request body, meaning user-selected browsing targets are transmitted to an external service. In the context of a scraping skill, that behavior is expected, but it is still security-relevant because it can expose sensitive URLs, metadata, or extracted content to a third party.
API_KEY = "fc-YOUR_API_KEY"
response = requests.post(
"https://api.firecrawl.dev/v2/scrape",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={
The examples send user-supplied URLs, queries, and page content to third-party scraping services without any accompanying disclosure that data leaves the local environment. In a skill explicitly meant for web extraction, this creates a real privacy and data-handling risk because operators may unknowingly forward sensitive targets, search terms, or scraped content to external vendors.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
API_KEY = "fc-YOUR_API_KEY"
response = requests.post(
"https://api.firecrawl.dev/v2/scrape",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={
"url": "https://example.com",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
API_KEY = "fc-YOUR_API_KEY"
response = requests.post(
"https://api.firecrawl.dev/v2/scrape",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={
"url": "https://example.com",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
API_KEY = "fc-YOUR_API_KEY"
response = requests.post(
"https://api.firecrawl.dev/v2/scrape",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={
"url": "https://example.com",
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
API_KEY = "fc-YOUR_API_KEY"
response = requests.post(
"https://api.firecrawl.dev/v2/scrape",
headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
json={
"url": "https://example.com",
The crawl example submits a site URL and crawl configuration to Firecrawl, causing external transmission of the user's chosen target and potentially large-scale content retrieval via a third-party processor. Because this skill is specifically designed to crawl websites, the behavior is intentional, but it can still leak sensitive internal or proprietary targets if used carelessly.
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
# Start crawl
resp = requests.post(f"{BASE}/crawl", headers=HEADERS, json={
"url": "https://docs.example.com",
"limit": 50,
"scrapeOptions": {"formats": ["markdown"]}
The search-and-scrape example sends search queries to Firecrawl, which may expose user intent, research topics, or potentially sensitive business queries to a third party. In a scraping/search skill this is normal functionality, but without disclosure it still presents a meaningful confidentiality issue.
resp = requests.post(f"{BASE}/search", headers=HEADERS, json={
"query": "best Python web scraping libraries 2025",
"limit": 5,
"scrapeOptions": {"formats": ["markdown"]}
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
TOKEN = "YOUR_APIFY_TOKEN"
ACTOR = "apify/google-search-scraper"
BASE = "https://api.apify.com/v2"
# Start run
resp = requests.post(
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
TOKEN = "YOUR_APIFY_TOKEN"
ACTOR = "apify/google-search-scraper"
BASE = "https://api.apify.com/v2"
# Start run
resp = requests.post(
This example starts an Apify actor run by sending query terms and configuration to Apify over the network, exposing the task inputs to an external service. The action is core to the skill's purpose, but it remains a true security concern where users may assume scraping is performed locally or may submit sensitive targets.
BASE = "https://api.apify.com/v2"
# Start run
resp = requests.post(
f"{BASE}/acts/{ACTOR}/runs",
params={"token": TOKEN},
json={"queries": "web scraping", "maxPagesPerQuery": 1}
The synchronous Apify example transmits query data to an external API and immediately retrieves results, which can disclose user interests and scraping targets to a third party. Although expected in this skill, the lack of surrounding warning makes it a real data-sharing risk.
resp = requests.post(
f"{BASE}/acts/{ACTOR}/run-sync-get-dataset-items",
params={"token": TOKEN},
json={"queries": "Jaipur restaurants", "maxPagesPerQuery": 1}
The file-writing example writes directly to results.json in overwrite mode without warning, which can destroy an existing local file and lead to unintended data loss. This is a real but low-severity safety issue because it affects local integrity rather than enabling code execution or privilege escalation.
No suspicious patterns detected.