Back to skill

Security audit

Funda Listings Gateway

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to do its advertised Funda gateway job, but it uses unhardened network/image fetching and pinned dependencies that need review before installation.

Install only in a trusted local environment, keep the gateway bound to 127.0.0.1, and avoid exposing it to other users or networks. Before broad use, update vulnerable dependencies, add host/IP allowlisting and response-size limits for image downloads, and prefer hashed dependency locks.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/funda_gateway.py:239
Finding
Upstream-Controlled Image URLs Enable Server-Side Request Forgery## Vulnerability Details **File Location**: `scripts/funda_gateway.py`, lines 178-181 and 239-246 **Vulnerability Type**: Server-Side Request Forgery (SSRF) and unbounded response download **Risk Level**: Medium ### Vulnerable Code ```python photo_urls = sorted(listing.get("photo_urls") or []) if not photo_urls: return {"id": id, "count": 0, "previews": []} photo_ids_to_urls = {extract_id(url): url for url in photo_urls} ``` ```python for index, url in enumerate(urls_to_download, start=1): photo_id = extract_id(url) try: request = urllib.request.Request( url, headers={"User-Agent": "Mozilla/5.0"} ) with urllib.request.urlopen(request, timeout=funda_timeout) as response: content = response.read() ``` ### Technical Analysis Image URLs obtained from the upstream listing data are passed directly to `urllib.request.urlopen`. The implementation does not validate: - The URL scheme. - The destination hostname. - The resolved IP address. - Redirect destinations. - Whether the destination is loopback, private, link-local, reserved, or multicast. - The response content length before reading it into memory. The local API caller cannot directly provide an arbitrary URL. Exploitation therefore requires control over, or compromise of, the upstream listing response or a dependency that supplies `photo_urls`. Nevertheless, the code crosses a documented trust boundary: `SKILL.md` states that external data must be treated as untrusted. The use of `response.read()` without a byte limit also permits an upstream server to return a very large response, potentially causing excessive memory consumption. The configured timeout limits waiting time but does not limit the number of downloaded bytes. ### Attack Path 1. An attacker compromises or influences the upstream listing-data source, or a dependency involved in constructing `photo_urls`. 2. The attacker supplies a URL targeting an address reachable from ...[truncated 1457 chars]
Remediation
## Remediation Suggestions 1. Parse every image URL using `urllib.parse.urlsplit` and accept only HTTPS URLs. 2. Maintain an explicit allowlist of expected Funda image hostnames. Perform exact hostname or controlled subdomain matching rather than substring matching. 3. Resolve the hostname before connecting and reject every address that is loopback, private, link-local, reserved, multicast, or unspecified. 4. Disable automatic redirects or validate the scheme, hostname, and resolved IP address at every redirect hop. 5. Stream the response in bounded chunks and stop after a conservative maximum size rather than calling an unrestricted `response.read()`. 6. Check the declared content type and accept only supported image media types, while continuing to verify the actual file through Pillow. 7. Apply outbound network restrictions at the process or container level so the gateway can reach only required Funda services. 8. Log rejected destinations without recording sensitive query strings or response content.

T08 · Insecure Dependencies

Note
Location
scripts/requirements.txt:1
Finding
Third-Party Dependencies Are Installed Without Cryptographic Integrity Verification## Vulnerability Details **File Location**: `scripts/requirements.txt`, lines 1-5; installation instructions in `SKILL.md`, lines 24-31 and `WORKFLOW.md`, lines 34-41 **Vulnerability Type**: Insufficient dependency artifact integrity controls **Risk Level**: Low ### Vulnerable Code ```text pyfunda==2.5.0 simple_http_server==0.22.3 curl-cffi==0.14.0 certifi==2026.1.4 Pillow==11.2.1 ``` The documented installation command is: ```bash pip install -r scripts/requirements.txt ``` The workflow also instructs: ```bash python -m pip install --upgrade pip python -m pip install -r scripts/requirements.txt ``` ### Technical Analysis All direct dependencies are pinned to exact versions, which reduces exposure to unexpected version upgrades. However, the requirements file does not specify SHA-256 artifact hashes, and the installation command does not use pip's `--require-hashes` option. Consequently, installation trusts whichever package index and artifact source are configured in the runtime environment. Exact version pinning does not detect an altered artifact published under the same version. Transitive dependencies may also remain insufficiently constrained unless resolved into a complete hashed lock file. No evidence was found that any listed package is malicious, typosquatted, or intentionally sourced from an unsafe domain. This finding concerns the absence of artifact integrity enforcement rather than a confirmed compromise of a particular dependency. ### Attack Path 1. An Agent follows the documented first-run setup procedure. 2. Pip connects to its configured package index or mirror. 3. An attacker who has compromised the index, mirror, package-maintainer account, or artifact delivery path substitutes a malicious artifact for an expected package version. 4. Because no expected hashes are configured, pip accepts and installs the substituted artifact. 5. Malicious package code executes during installation or when imported by the gateway. ### ...[truncated 540 chars]
Remediation
## Remediation Suggestions 1. Produce a fully resolved lock file containing all direct and transitive dependencies. 2. Record SHA-256 hashes for every permitted wheel or source distribution. 3. Install dependencies using: ```bash python -m pip install --require-hashes -r requirements.lock ``` 4. Explicitly configure a trusted package index rather than relying on an unknown environment-level pip configuration. 5. Prefer reviewed binary wheels from trusted publishers and verify dependency provenance before updating the lock file. 6. Run installation and the gateway under a dedicated, minimally privileged account or isolated container. 7. Add automated dependency vulnerability and provenance checks to continuous integration. 8. Review and regenerate hashes deliberately whenever dependency versions or supported platforms change.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (9)

Known Vulnerable Dependency: curl-cffi==0.14.0 — 2 advisory(ies): CVE-2026-33752 (curl_cffi: Redirect-based SSRF leads to internal network access in curl_cffi (wi); CVE-2026-33752 (curl_cffi: Redirect-based SSRF leads to internal network access in curl_cffi (wi)

Critical
Category
Supply Chain
Confidence
98% confidence
Finding
The requirements pin curl-cffi to 0.14.0, which is reported as affected by a redirect-based SSRF vulnerability. In a skill described as a local HTTP gateway that performs listing detail fetches and previews, outbound HTTP requests are core functionality, so a vulnerable HTTP client materially increases the risk that attacker-controlled redirects could access internal or loopback resources.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented skill purpose is a local Funda gateway, but the finding indicates the implementation includes generic outbound HTTP capability and a reusable TLS/browser impersonation shim not clearly limited to Funda-specific targets. That mismatch is dangerous because a caller or reviewer may trust the skill as narrowly scoped while it can potentially be repurposed as a broader proxy or scraping client, increasing SSRF-like abuse and unintended external access risk.

Ae1

High
Category
analysis-evasion
Content
pip install -r scripts/requirements.txt
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Known Vulnerable Dependency: Pillow==11.2.1 — 16 advisory(ies): CVE-2026-55379 (Pillow `BdfFontFile`: `Image.new()` called without `_decompression_bomb_check()`); CVE-2026-55798 (Pillow: WindowsViewer.get_command() OS command injection via unescaped shell pat); CVE-2026-54060 (Pillow: `FontFile.compile()`: `Image.new()` called without `_decompression_bomb_) +13 more

High
Category
Supply Chain
Confidence
95% confidence
Finding
The requirements pin Pillow to 11.2.1, which is flagged with multiple advisories including image-processing denial-of-service issues and at least one command-injection issue in platform-specific viewer functionality. This skill explicitly handles image previews, so an image library with numerous known flaws is relevant: malformed images could trigger excessive resource consumption, and any exposed helper/viewer paths would broaden impact depending on how the package is used.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill explicitly documents network access and file-writing behavior but declares no permissions or allowed-tools scope, creating a mismatch between stated metadata and actual capabilities. In agent environments, this can lead to overbroad execution, reduced operator visibility, and accidental use of network or filesystem actions without explicit approval boundaries.

Unbounded Resource Access

Medium
Category
Excessive Agency
Content
return base_dir


def is_port_listening(port, host="127.0.0.1", timeout=0.5):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.settimeout(timeout)
        return sock.connect_ex((host, int(port))) == 0
Confidence
75% confidence
Finding
Skill allows unbounded resource consumption (API calls, storage, compute). Without rate limits or quotas, a compromised or misbehaving agent can cause denial-of-service or cost overruns.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The `get_previews` route supports `save=1` and then writes image data to a local path with `output_path.write_bytes(...)`. While the parameter names imply saving behavior, there is no confirmation prompt, user-facing log/print, or nearby comment/docstring warning that this endpoint persists files to disk.

Missing User Warnings

Low
Confidence
90% confidence
Finding
This markdown file documents that `save=1` will store preview images under a user-controlled relative directory, but it does not include an explicit warning that this operation writes files to local disk and may persist downloaded data. Under the markdown criteria for missing user warnings, file-writing behavior that can affect user data or system state should be disclosed clearly.

Missing User Warnings

Low
Confidence
78% confidence
Finding
The `get_previews` handler issues network requests to external image URLs using `urllib.request.urlopen(...)`. Although network access is part of the gateway's functionality, this specific data-fetching behavior lacks a visible user-facing disclosure in code such as logging, print statements, or documentation comments near the operation.

Static analysis

No suspicious patterns detected.