T09 · Insecure Skill Coding Practices
- Location
SKILL.md:55- Finding
Live API Key Exposed in Output and Persisted Without Security Controls
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This marketplace skill is mostly coherent, but it asks users to expose powerful account credentials in unsafe ways.
Review before installing. Do not send a JWT or API key through Telegram, chat, logs, or transcripts, and only store credentials in a secure secret manager. Use this skill only when you intentionally want Pactum marketplace actions, and confirm purchases, credit top-ups, escrow deposits, shipping-address submission, disputes, and payment release before execution.
SKILL.md:55Live API Key Exposed in Output and Persisted Without Security Controls
SKILL.md:353Primary Marketplace JWT Disclosed to an External Telegram Bot
The trigger phrases include very generic terms like "buy", "pactum", "marketplace", and "search for", which are likely to activate on ordinary user requests unrelated to this specific marketplace. Over-broad activation increases the chance the skill engages unexpectedly and starts steering users into account creation, payment, or data-sharing flows without clear intent.
The skill explicitly instructs users to send their JWT to a Telegram bot, which is a credential-sharing pattern with a third party and no warning about token sensitivity or account takeover risk. Anyone with the JWT can typically act as the user for its validity period, exposing orders, messages, addresses, and payment-related actions.
Telling users to provide their JWT to a Telegram bot exposes a live bearer token to an external party. Because bearer tokens are often sufficient for authentication on their own, compromise of the bot, transport, logs, or operator access could directly enable unauthorized account actions.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# ⚠️ ASK THE USER for their email address first
email = "user@example.com" # ← get this from the user
r = requests.post(f"{WALLET_URL}/v1/register", json={"email": email})
r.raise_for_status()
# A 6-digit code has been sent to the user's email.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# ⚠️ ASK THE USER for their email address first
email = "user@example.com" # ← get this from the user
r = requests.post(f"{WALLET_URL}/v1/register", json={"email": email})
r.raise_for_status()
# A 6-digit code has been sent to the user's email.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# Step 2: Verify → get credentials
# ⚠️ Execute IMMEDIATELY after getting the code — codes expire quickly
r = requests.post(f"{WALLET_URL}/v1/verify", json={"email": email, "code": code})
r.raise_for_status()
data = r.json()
API_KEY = data["api_key"] # pk_live_... — save this permanently
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.
API_KEY = data["api_key"] # pk_live_... — save this permanently
WALLET = data["wallet_address"] # 0x...
# Step 3: Get JWT token (do this immediately, don't ask the user)
r = requests.post(f"{BASE_URL}/market/auth/wallet", json={"api_key": API_KEY})
r.raise_for_status()
TOKEN = r.json()["token"] # valid for 7 days
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
WALLET = data["wallet_address"] # 0x...
# Step 3: Get JWT token (do this immediately, don't ask the user)
r = requests.post(f"{BASE_URL}/market/auth/wallet", json={"api_key": API_KEY})
r.raise_for_status()
TOKEN = r.json()["token"] # valid for 7 days
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
WALLET = data["wallet_address"] # 0x...
# Step 3: Get JWT token (do this immediately, don't ask the user)
r = requests.post(f"{BASE_URL}/market/auth/wallet", json={"api_key": API_KEY})
r.raise_for_status()
TOKEN = r.json()["token"] # valid for 7 days
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
r = requests.post(f"{WALLET_URL}/v1/register", json={"email": email})
r = requests.post(f"{WALLET_URL}/v1/recover", json={"email": email, "code": code}) API_KEY = r.json()["api_key"] # new key, old one invalidated
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# Search items by keyword
r = requests.post(f"{BASE_URL}/market/discover", json={"q": "crypto funding rate"})
items = r.json()["items"]
for item in items:
price = f"${item['price']}" if item["price"] > 0 else "FREE"
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# Search items by keyword
r = requests.post(f"{BASE_URL}/market/discover", json={"q": "crypto funding rate"})
items = r.json()["items"]
for item in items:
price = f"${item['price']}" if item["price"] > 0 else "FREE"
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
headers = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
# Check item.required first — if required.description is true, include "query"
r = requests.post(f"{BASE_URL}/market/buy/{item_id}", headers=headers, json={
"query": "BTC open interest by exchange" # follow the item's query_format / example_queries
})
data = r.json()
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
headers = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
# Check item.required first — if required.description is true, include "query"
r = requests.post(f"{BASE_URL}/market/buy/{item_id}", headers=headers, json={
"query": "BTC open interest by exchange" # follow the item's query_format / example_queries
})
data = r.json()
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
headers = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
# Check item.required first — if required.description is true, include "query"
r = requests.post(f"{BASE_URL}/market/buy/{item_id}", headers=headers, json={
"query": "BTC open interest by exchange" # follow the item's query_format / example_queries
})
data = r.json()
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# Top up credit ($1–$500)
# provider: "stripe" (card), "alipay", or "wechat"
r = requests.post(f"{BASE_URL}/market/credit/topup", headers=headers, json={
"amount": 10, # USD
"provider": "stripe" # or "alipay" or "wechat"
})
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
escrow_info = data["escrow"]
# Step 2: Deposit USDC to escrow contract
r = requests.post(f"{WALLET_URL}/v1/escrow-deposit", headers=wallet_headers, json={
"escrow_contract": escrow_info["contract"],
"usdc_contract": escrow_info["usdc_contract"],
"order_id_bytes32": escrow_info["order_id_bytes32"],
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
tx_hash = r.json()["deposit_tx"]
# Step 3: Submit payment proof
r = requests.post(f"{BASE_URL}/market/buy/{item_id}", headers={
**headers,
"X-Payment-Proof": tx_hash,
"X-Order-Id": order_id,
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
r = requests.post(f"{BASE_URL}/market/orders/{order_id}/messages",
headers={"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"},
json={"content": "Can you also include ETH data?"})
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
Freezes payment. Admin will review and decide fund allocation.
r = requests.post(f"{BASE_URL}/market/orders/{order_id}/dispute",
headers={"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"},
json={"reason": "Seller delivered wrong data"})
The skill collects a full shipping address and transmits it to an external service without any explicit privacy notice, minimization guidance, or handling safeguards. This creates unnecessary privacy and compliance risk because users may disclose sensitive personal data without being informed how it is stored, used, or protected.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# ⚠️ ASK THE USER for their shipping details
r = requests.put(f"{BASE_URL}/market/address",
headers={"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"},
json={"address": {
"name": "John Doe", "street": "123 Main St",
No suspicious patterns detected.