T09 · Insecure Skill Coding Practices
- Location
scripts/fb_deploy.py:71- Finding
Hardcoded Supabase Database Credential
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This is a real Facebook ad deployment skill, but it ships a hardcoded database password and performs risky runtime package installation, so it should be reviewed carefully before use.
Install only if you trust the publisher and have reviewed the database credential issue. Rotate or remove the embedded Supabase password before use, supply your own least-privilege database credentials securely, run the tool in an isolated virtual environment, avoid the URL method for token exchange, and treat any Facebook access token as a high-value secret that can create ads and spend money.
scripts/fb_deploy.py:71Hardcoded Supabase Database Credential
scripts/fb_deploy.py:36Automatic Installation of Unpinned Third-Party Packages at Runtime
FB_SETUP_GUIDE.md:127Facebook App Secret and Access Token Placed in a Browser URL
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
**Requirements:**
- Facebook Developer Account + App
- `ads_management` + `ads_read` permissions
- Access token (long-lived)
- Python SDK: `pip install facebook-business`
**API Object Creation Order:**
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Credential | Format | Where It Goes |
|-----------|--------|---------------|
| Access Token | Long string starting with `EAA...` | `--setup` prompt |
| Ad Account ID | `act_XXXXXXXXXX` | `--setup` prompt |
| Page ID | Number like `123456789` | `--setup` prompt |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Credential | Format | Where It Goes |
|-----------|--------|---------------|
| Access Token | Long string starting with `EAA...` | `--setup` prompt |
| Ad Account ID | `act_XXXXXXXXXX` | `--setup` prompt |
| Page ID | Number like `123456789` | `--setup` prompt |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Credential | Format | Where It Goes |
|-----------|--------|---------------|
| Access Token | Long string starting with `EAA...` | `--setup` prompt |
| Ad Account ID | `act_XXXXXXXXXX` | `--setup` prompt |
| Page ID | Number like `123456789` | `--setup` prompt |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Credential | Format | Where It Goes |
|-----------|--------|---------------|
| Access Token | Long string starting with `EAA...` | `--setup` prompt |
| Ad Account ID | `act_XXXXXXXXXX` | `--setup` prompt |
| Page ID | Number like `123456789` | `--setup` prompt |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Credential | Format | Where It Goes |
|-----------|--------|---------------|
| Access Token | Long string starting with `EAA...` | `--setup` prompt |
| Ad Account ID | `act_XXXXXXXXXX` | `--setup` prompt |
| Page ID | Number like `123456789` | `--setup` prompt |
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Credential | Format | Where It Goes |
|-----------|--------|---------------|
| Access Token | Long string starting with `EAA...` | `--setup` prompt |
| Ad Account ID | `act_XXXXXXXXXX` | `--setup` prompt |
| Page ID | Number like `123456789` | `--setup` prompt |
The guide directs the user to paste a long-lived access token into a script on a server via an interactive setup flow. In this skill context, that is more dangerous because server-side prompts, shell history, terminal recording, support logs, or script-side logging could expose a token that grants advertising account access and could be abused for fraudulent campaigns or account manipulation.
It will prompt for:
Access Token: [paste your long-lived token]
Ad Account ID (act_XXX): [paste act_XXXXXXXXXX]
Page ID: [paste your page ID number]
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
| Issue | Fix |
|-------|-----|
| "Invalid OAuth access token" | Token expired — regenerate and run `--setup` |
| "User does not have permission" | Check that your token has `ads_management` scope |
| "Ad account is disabled" | Check payment method in Business Manager |
| "Page not found" | Make sure Page ID is correct and your app has `pages_manage_ads` |
The stated purpose sounds like straightforward ad assembly and deployment, but the behavior includes more sensitive functionality: credential persistence, database access, campaign/ad set creation, and live metrics retrieval. This mismatch is dangerous because operators may grant trust based on the summary while the skill performs broader and more privileged actions than expected.
The documentation explicitly requires obtaining a long-lived access token with ads management privileges, which is a sensitive credential. While requesting such a token is functionally necessary for the skill, it materially increases risk because compromise of the token could allow unauthorized advertising actions and access to account data.
ads_management permission2. Store credentials:
The skill states that it saves the Facebook access token, ad account ID, and page ID to a local config file under the user's home directory. Persisting high-value API credentials in a local file is dangerous if the file is stored in plaintext, backed up insecurely, readable by other users/processes, or later exfiltrated by another tool.
python3 scripts/fb_deploy.py --setup
Prompts for access token, ad account ID, and page ID. Validates against FB API and saves to ~/.config/ad-engine/fb_config.json.
The script embeds a live-looking Supabase/Postgres DSN with username, host, and password directly in source code. Anyone who can read the skill gains database access, which can expose or modify ad content, message history, metadata, and any other reachable records; in an agent environment this creates immediate unauthorized data access risk.
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
"""Interactive setup for Facebook credentials."""
print("\n=== Ad Engine — Facebook Setup ===\n")
print("You need 3 things from Facebook Business Manager:\n")
print("1. ACCESS TOKEN — From developers.facebook.com → your app → Marketing API")
print(" Generate a long-lived token with ads_management permission")
print(" Docs: https://developers.facebook.com/docs/marketing-api/overview/authorization\n")
print("2. AD ACCOUNT ID — From Business Manager → Ad Accounts")
The script interactively collects a Facebook access token and then persists it locally in a JSON config file. Although intended for legitimate use, storing a high-privilege token on disk increases the risk of credential compromise from local malware, weak workstation hygiene, backups, or multi-user systems.
print("3. PAGE ID — From your Facebook Page → About → Page ID")
print(" This is the page the ads will run from\n")
token = input("Access Token: ").strip()
account = input("Ad Account ID (act_XXX): ").strip()
page = input("Page ID: ").strip()
The spec describes Facebook Pixel, Conversions API, UTM tracking, dynamic ad-name parameters, DM automation via ManyChat, and syncing ad performance back into Supabase, but it does not include any requirement to present a privacy notice, obtain any needed consent, or disclose how message and tracking data will be used. In an ad-deployment skill, this is materially risky because the behavior operationalizes user tracking and message capture at scale, increasing the chance of noncompliant data collection and downstream privacy violations.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
**If you don't have one yet:**
1. Go to **https://business.facebook.com**
2. Click **"Create Account"**
3. Enter business name (e.g., "ClawAgents" or your name)
4. Enter your email
5. Done
The guide explicitly instructs users to paste a long-lived Facebook access token and then states the script saves credentials to ~/.config/ad-engine/fb_config.json, but it gives no warning about credential sensitivity, file permissions, or secure storage. In an agent/server context, storing reusable API tokens in plaintext on disk can enable account takeover or unauthorized ad spend if the host, home directory, backups, or logs are exposed.
The skill documentation describes operations that require broad capabilities including filesystem access, network access, shell execution, and credential handling, but it does not declare any explicit tool scope or permission boundaries. In an agent environment, this increases the risk of over-privileged execution because the agent may be allowed to access more resources than are necessary for ad deployment tasks.
The skill instructs users to store a long-lived Facebook access token locally but does not warn about the sensitivity of the token, file permissions, rotation, or secure storage practices. Long-lived marketing API tokens can enable unauthorized ad creation, budget spend, and access to campaign data if the local config file is exposed.
Auto-installing packages at runtime is not necessary for assembling and deploying ads and grants the skill an unnecessary code-execution capability. In an agent skill context, this is more dangerous because it lets the skill alter the host environment and potentially pull executable content from package repositories during normal operation.
Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.
}
for module, pkg in deps.items():
try:
__import__(module)
except ImportError:
import subprocess
print(f"Installing {pkg}...", file=sys.stderr)
The script automatically invokes pip at runtime to install packages, which expands the skill's execution and supply-chain attack surface beyond its stated purpose. If package sources, dependency resolution, or the execution environment are compromised, running this skill can execute untrusted code during installation with the user's privileges.
import subprocess
print(f"Installing {pkg}...", file=sys.stderr)
try:
subprocess.check_call([
sys.executable, "-m", "pip", "install",
"--break-system-packages", "-q", pkg
])
This fallback pip invocation again performs runtime package installation and can execute arbitrary code from package installation hooks or compromised dependencies. The fallback broadens compatibility at the cost of silently mutating the environment and increasing supply-chain risk.
"--break-system-packages", "-q", pkg
])
except subprocess.CalledProcessError:
subprocess.check_call([
sys.executable, "-m", "pip", "install", "-q", pkg
])
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
# Validate token
print("\nValidating credentials...", file=sys.stderr)
resp = requests.get(f"{FB_BASE_URL}/{account}", params={
"access_token": token,
"fields": "name,account_status,currency"
})
No suspicious patterns detected.