T09 · Insecure Skill Coding Practices
- Location
scripts/billing_config.py:1- Finding
Hardcoded SkillPay API Credential and Sensitive Billing Data Transmission
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill’s portfolio tools are mostly coherent, but it ships unsafe billing code with a hardcoded payment API key and a charge function that can send user IDs and amounts to an external billing service.
Review this skill before installing. The portfolio optimizer itself is user-invoked and uses expected market-data lookups, but the bundled billing files should not ship with a hardcoded SkillPay key or an unconstrained charge method. Install only if the publisher rotates the exposed credential, removes secrets from source, clearly documents billing consent and data flow, and fixes the stale Social Media Manager metadata and broken --file interface.
scripts/billing_config.py:1Hardcoded SkillPay API Credential and Sensitive Billing Data Transmission
The top-level documentation says this file is for "SkillPay Integration for Xanadu Social Media Manager," implying social media management functionality, but the actual implemented behavior is a payment client that reads billing credentials and performs remote charge requests. This is an active intent mismatch between the documented identity/purpose of the file and what the code actually does.
This skill loads billing credentials and implements remote charging logic without any clear, documented user-facing purpose or authorization flow in the provided context. In an agent skill ecosystem, undisclosed payment and credential-handling capabilities are dangerous because they enable monetization or data transmission beyond what a user may reasonably expect.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
def __init__(self, api_key: str = None, skill_id: str = None):
self.api_key = api_key or SKILLPAY_API_KEY
self.skill_id = skill_id or SKILL_ID
self.base_url = "https://api.skillpay.me/v1"
if not self.api_key:
raise ValueError("SkillPay API key required")
This code performs an external POST to a payment endpoint, transmitting billing-related data off-system. External transmission is especially sensitive in agent skills because it can expose user identifiers and trigger financial actions without transparent review or runtime controls.
amount = amount or DEFAULT_PRICE
try:
response = requests.post(
f"{self.base_url}/charge",
json={
"api_key": self.api_key,
The charge method sends an API key, user ID, and amount to an external service with no visible disclosure, consent, or confirmation mechanism. In a skill context this can result in silent billing, unexpected transmission of identifiers, and misuse of payment credentials if the function is invoked by another component without strong policy checks.
A live-looking secret API key is hardcoded directly in source code, which makes it accessible to anyone with repository or artifact access and likely to be harvested automatically by secret-scanning tools or attackers. Exposure of a billing or payment-related credential can enable unauthorized API use, fraudulent charges, service abuse, or compromise of connected billing operations.
The script sends user portfolio ticker symbols to yfinance without explicit disclosure or consent. While symbol lookups are central to the tool's purpose, portfolio composition can still be sensitive financial metadata, and transmitting it to a third-party service may leak private investment information or violate user expectations in local/offline contexts.
Sector analysis performs additional third-party lookups for each portfolio symbol, increasing unnecessary disclosure beyond the minimum required for core valuation. Repeated undisclosed requests can expand the privacy footprint of the user's portfolio and make traffic analysis easier.
Historical price retrieval for volatility analysis makes further external requests for portfolio symbols without clearly informing the user. In a financial tool, this can expose additional details about user holdings and analysis behavior to third-party services, even if no direct compromise occurs.
The harvest subcommand defines an optional --file argument, implying the tool can read holdings from a JSON file. However, the dispatch logic always calls tax_loss_harvest(args.holdings) and never uses args.file, so the documented interface contradicts actual behavior.
No suspicious patterns detected.