Back to skill

Security audit

Contact Enrichment

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches contact enrichment, but it needs review because it can fetch arbitrary URLs and send contact/profile data to Hunter.io without enough scoping.

Install only if you are comfortable with the agent making outbound requests to target websites, WHOIS services, and optionally Hunter.io. Use it only for public business websites, provide a Hunter.io key only if you intend third-party enrichment, and avoid running it on untrusted or internal URLs until URL validation and redirect/IP restrictions are added.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:74
Finding

Unrestricted URL Fetching Enables Server-Side Request Forgery

Content
View full analysis
tuple[str, str]: """Fetch a page. Returns (html, final_url).""" try: r = requests.get(url, headers=HEADERS, timeout=8, allow_redirects=True) if r.status_code < 400: return r.text, r.url except Exception: pass return "", url ``` The vulnerable request is reached through the following contact-page logic: ```python def scrape_contact_pages(base_url: str, existing_html: str = "") -> dict: """ Scrape multiple pages for contact info. existing_html: pass HTML already fetched by website-auditor to avoid re-fetching. """ from urllib.parse import urljoin all_emails = set() all_phones = set() business_name = "" # Try homepage first (using already-fetched HTML if available) if existing_html: data = extract_from_html(existing_html) all_emails.update(data["emails"]) all_phones.update(data["phones"]) business_name = data["business_name"] # Try contact/about pages contact_paths = ["/contact", "/about", "/contact-us", "/about-us", "/get-in-touch", "/reach-us", "/find-us"] for path in contact_paths: if all_emails: break # Found emails — no need to keep crawling url = urljoin(base_url, path) html, _ = scrape_page(url) if html: data = extract_from_html(html) all_emails.update(data["emails"]) all_phones.update(data["phones"]) if not business_name: business_name = data["business_name"] ``` ### Technical Analysis The Skill accepts a `base_url`, derives additional URLs with `urljoin()`, and passes them to `requests.get()` without validating the scheme, hostname, destination port, or re ...[truncated 2302 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:205
Finding

Hunter API Credential Exposed in URL Query Parameters

Content
View full analysis
dict: """Verify if an email is deliverable.""" api_key = os.environ.get("HUNTER_API_KEY") if not api_key: return {"valid": None} params = {"email": email, "api_key": api_key} r = requests.get("https://api.hunter.io/v2/email-verifier", params=params) data = r.json().get("data", {}) return {"valid": data.get("status") == "valid", "score": data.get("score")} ``` ### Technical Analysis The API key is loaded from an environment variable and placed in the `params` dictionary of a GET request. The `requests` library serializes these parameters into the URL, producing a request resembling: ```text https://api.hunter.io/v2/domain-search?domain=example.com&api_key=SECRET&limit=5&type=personal ``` HTTPS protects the request from ordinary network eavesdropping while in transit, and the destination is the declared Hunter.io service. However, URL query strings are frequently retained by HTTP client diagnostics, application telemetry, reverse proxies, monitoring systems, exception reports, and server access logs. Anyone with access to an unredacted log containing the complete request URL could recover the credential. The network operation is neces ...[truncated 1547 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (4)

External Transmission

Medium
Category
Data Exfiltration
Confidence
50% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

md
}
    
    try:
        r = requests.get("https://api.hunter.io/v2/domain-search", params=params, timeout=10)
        data = r.json().get("data", {})
        
        contacts = []

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The Hunter.io domain-search code collects additional personal profile attributes such as first/last name, job title, confidence score, and LinkedIn URL, which exceed the manifest’s narrow stated purpose of extracting contact information from a website. This expands the skill into personal profiling and third-party enrichment, increasing privacy risk and the chance of using more data than users expect or need.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill implements an email verification function that transmits candidate email addresses to Hunter.io even though verification is not described in the declared workflow. That creates an undocumented external disclosure of personal data and broadens the skill’s capability from contact extraction into validation and profiling without clear necessity or user consent.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
84% confidence
Finding

This request sends a specific email address to Hunter.io’s verifier endpoint, which is a stronger privacy concern than domain search because it transmits personal contact data to a third party. Since this capability is undocumented and not clearly necessary for the advertised enrichment flow, the external transmission is unsafe in context.

Content

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

if not api_key: return {"valid": None} params = {"email": email, "api_key": api_key} r = requests.get("https://api.hunter.io/v2/email-verifier", params=params) data = r.json().get("data", {}) return {"valid": data.get("status") == "valid", "score": data.get("score")}

text

Static analysis

No suspicious patterns detected.