Back to skill

Security audit

Meta Ad Library API - Facebook and Instagram Ad Search

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward guide for using Scavio's Meta Ad Library API, with expected third-party API calls and no hidden persistence or destructive behavior.

Install/use this skill if you are comfortable sending ad research queries, page IDs, ad archive IDs, and the Scavio API key to Scavio. Prefer the direct HTTPS examples or install the SDKs in an isolated environment, and set a page or credit budget before deep pagination crawls.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T08 · Insecure Dependencies

Warning
Location
SKILL.md:217
Finding

Unverified Third-Party SDK Installation Creates Supply-Chain Risk

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 217-242
Vulnerability Type: T08: Insecure Dependencies
Risk Level: Medium

The Skill recommends installing Python and npm SDK packages from public package registries. Although both dependencies are pinned to version 0.15.0, the instructions do not provide integrity hashes, lockfiles, package provenance verification, or controls against installation-time scripts.

bash
pip install scavio==0.15.0
python
from scavio import ScavioClient

client = ScavioClient()  # reads SCAVIO_API_KEY

page1 = client.meta_ads.search("project management software", country="US",
                               active_status="active")
page2 = client.meta_ads.search("project management software",
                               cursor=page1["data"]["next_cursor"])
by_page = client.meta_ads.advertiser("20531316728", country="US")
one = client.meta_ads.ad("1234567890123456")
bash
npm install scavio@0.15.0
js
import { Scavio } from "scavio";

const scavio = new Scavio(); // reads SCAVIO_API_KEY
const ads = await scavio.metaAds.search({ query: "project management software", country: "US" });
const { next_cursor } = ads.data as Record<string, any>;
const next = await scavio.metaAds.search({ query: "project management software",
                                           cursor: next_cursor });

Technical Analysis

Package installation is an executable trust boundary. Python packages may run build-backend or setup logic during installation, while npm packages may execute lifecycle scripts such as preinstall, install, and postinstall. Version pinning limits unintended version upgrades but does not verify the integrity or provenance of the selected artifact.

The installed SDKs are expected to read SCAVIO_API_KEY. Consequently, a compromised registry account, malicious release, substituted artifact, or compromised ...[truncated 2178 chars]

Remediation
View remediation

Remediation Suggestions

  1. Prefer the documented direct HTTPS API requests, which avoid installing executable SDK dependencies.
  2. If SDK installation remains supported, publish verified package provenance and links to the authoritative package and source repositories.
  3. Provide reproducible lockfiles containing exact transitive dependency versions and integrity metadata.
  4. For Python, distribute and verify package hashes, for example through a requirements file used with pip install --require-hashes.
  5. For npm, provide a reviewed lockfile and use npm ci rather than an unconstrained install workflow.
  6. Disable npm lifecycle scripts with --ignore-scripts when the SDK does not require them.
  7. Install dependencies in a dedicated virtual environment, container, or other sandbox under a non-privileged account.
  8. Do not install packages with administrator or root privileges.
  9. Expose only SCAVIO_API_KEY to the SDK process and remove unrelated secrets from its environment.
  10. Document credential rotation procedures so the API key can be promptly revoked if dependency compromise is suspected.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (6)

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

This example performs an authenticated POST to an external service with user-controlled search parameters. In context, the behavior is expected for the skill, but it still constitutes external data transmission and can expose sensitive research terms or operational metadata to a third party if users are not clearly informed.

Content

Scanner excerpt · SKILL.md (reported line 142)May include surrounding context.

md
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# 1. Keyword search - 30 ads on page 1
ads = requests.post(f"{BASE}/api/v1/meta-ads/search", headers=HEADERS,
    json={"query": "project management software", "country": "US",
          "active_status": "active", "media_type": "video"}).json()

External Transmission

Medium
Category
Data Exfiltration
Confidence
87% confidence
Finding

This call sends a page identifier and filters to an external API under bearer-token authentication. Although the page ID itself may be public, the user's investigative target and usage patterns may still be sensitive, so the issue is the undocumented transmission of user intent and query context to a third party.

Content

Scanner excerpt · SKILL.md (reported line 147)May include surrounding context.

md
"active_status": "active", "media_type": "video"}).json()

# 2. Everything one Page is running, by numeric page id
advertiser = requests.post(f"{BASE}/api/v1/meta-ads/advertiser", headers=HEADERS,
    json={"page_id": "20531316728", "country": "US"}).json()

# 3. One ad by archive id

External Transmission

Medium
Category
Data Exfiltration
Confidence
86% confidence
Finding

This request transmits an ad archive ID to an external service using the configured API key. While functionally legitimate, it is still an external transmission pathway and should be treated as a privacy-sensitive operation if the identifier or lookup context is confidential.

Content

Scanner excerpt · SKILL.md (reported line 151)May include surrounding context.

md
json={"page_id": "20531316728", "country": "US"}).json()

# 3. One ad by archive id
ad = requests.post(f"{BASE}/api/v1/meta-ads/ad", headers=HEADERS,
    json={"ad_archive_id": "1234567890123456"}).json()

# 4. Political ads, where spend and reach are actually published

External Transmission

Medium
Category
Data Exfiltration
Confidence
88% confidence
Finding

This example sends politically themed search terms to an external provider, which may be especially sensitive because political interests and research topics can be high-sensitivity data in some environments. The skill normalizes the transmission but does not add any privacy warning or consent step.

Content

Scanner excerpt · SKILL.md (reported line 155)May include surrounding context.

json={"ad_archive_id": "1234567890123456"}).json()

4. Political ads, where spend and reach are actually published

political = requests.post(f"{BASE}/api/v1/meta-ads/search", headers=HEADERS, json={"query": "climate", "country": "US", "ad_type": "political_and_issue_ads"}).json()

text

External Transmission

Medium
Category
Data Exfiltration
Confidence
91% confidence
Finding

The crawl helper repeatedly sends request payloads and cursors to an external API, amplifying the volume of externally transmitted data and metadata. In context this is core functionality rather than malicious behavior, but it increases privacy exposure and billing risk because deeper crawls reveal more of the user's investigative scope and consume paid credits automatically.

Content

Scanner excerpt · SKILL.md (reported line 169)May include surrounding context.

md
for _ in range(max_pages):
        # The cursor carries the filters. Sending them again changes nothing.
        payload = {"cursor": cursor} if cursor else body
        data = requests.post(f"{BASE}/api/v1/meta-ads/{path}",
                             headers=HEADERS, json=payload).json()["data"]
        pages.append(data)
        if not data.get("has_next_page"):

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
82% confidence
Finding

The skill instructs agents to send user-supplied queries and identifiers to a third-party API using an API key, but it does not explicitly warn that those inputs will be transmitted off-platform. This is a real privacy/transparency issue because users may provide sensitive search terms, page IDs, or ad archive IDs without realizing they are being sent to Scavio.

Content

No source excerpt is available for this finding.