T09 · Insecure Skill Coding Practices
- Location
scripts/meta_ad_creatives.py:76- Finding
Meta Access Token Exposure Through Query Strings and Exception Logging
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill does what it claims, but it handles Meta access tokens and stored ad data in ways users should review before installing.
Install only if you are comfortable giving the skill a Meta Ads access token and having ad performance data cached locally. Use a least-privilege, revocable Meta token, restrict log access, and consider modifying the script to use Authorization headers, redact errors, validate pagination hosts, and define cleanup or storage protections for the SQLite data.
scripts/meta_ad_creatives.py:76Meta Access Token Exposure Through Query Strings and Exception Logging
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
all_ads = []
try:
while url:
response = requests.get(url, params=params, timeout=60)
response.raise_for_status()
data = response.json()
all_ads.extend(data.get('data', []))
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.
all_ads = []
try:
while url:
response = requests.get(url, params=params, timeout=60)
response.raise_for_status()
data = response.json()
all_ads.extend(data.get('data', []))
The skill documentation shows it relies on environment secrets and external Meta network access, but the manifest declares no explicit tool scope or permissions boundary. That mismatch can cause the agent platform or reviewer to underestimate the skill's access needs, leading to overbroad implicit permissions, unsafe execution, or accidental secret exposure when the skill is invoked.
The requests to the Meta Graph API send ad account identifiers, access tokens, filtering parameters, and query details over the network. Although network access is central to the script's purpose, the file lacks a visible user disclosure in the CLI/help text or module documentation that running it will contact Meta's external service and process account data remotely.
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
all_ads = []
try:
while url:
response = requests.get(url, params=params, timeout=60)
response.raise_for_status()
data = response.json()
all_ads.extend(data.get('data', []))
Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.
all_ads = []
try:
while url:
response = requests.get(url, params=params, timeout=60)
response.raise_for_status()
data = response.json()
all_ads.extend(data.get('data', []))
The script persists detailed ad-performance data locally in SQLite, including account names, campaign names, ad names, spend, impressions, clicks, and performance outcomes, without any access controls, encryption, retention policy, or user disclosure. In an agent/skill environment, this can expose sensitive client marketing data to other local users, processes, backups, or later tasks that read the same workspace.
No suspicious patterns detected.