Back to skill

Security audit

Meet-Pets-Friends❤️

Security checks for vulnerabilities and agentic risk

Overview

The skill is presented as pets-only, but the included code can search broader Gumtree categories and fetch non-Gumtree URLs, so it needs review before installation.

Review before installing. Use this only if you are comfortable with a bb-browser adapter that is broader than the pets-only description. Prefer a version that enforces pet categories, requires HTTPS URLs on www.gumtree.com, rejects redirects to other hosts, and pins the bb-browser dependency instead of installing the latest global package.

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

Error
Location
bb-sites/gumtree/listing.js:66
Finding
Unrestricted Listing URL Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `bb-sites/gumtree/listing.js`, lines 66–75 **Vulnerability Type**: Server-Side Request Forgery (SSRF) through insufficient URL validation **Risk Level**: High ### Vulnerable Code ```javascript if (!args.url) return { error: 'Missing argument: url', hint: 'e.g. bb-browser site gumtree/listing "https://www.gumtree.com/p/.../ID"' }; let path = String(args.url).trim(); if (!path.startsWith('http')) { if (!path.startsWith('/')) path = '/' + path; path = 'https://www.gumtree.com' + path; } const resp = await fetch(path, { ``` ### Technical Analysis The listing adapter accepts a caller-controlled URL. Values beginning with `http` are passed directly to `fetch()` without parsing or validating the scheme, hostname, port, resolved IP address, or redirect destination. Although the adapter metadata declares `www.gumtree.com` as its domain, this declaration is not enforced by the code. The `startsWith('http')` condition is only a string-prefix check and does not establish that the destination belongs to Gumtree. Consequently, an attacker may provide URLs targeting: - Loopback services such as `http://127.0.0.1/...` - Private network services - Link-local or cloud instance metadata endpoints - Internal administrative interfaces - Attacker-controlled hosts that redirect to internal destinations The default redirect behavior of `fetch()` creates an additional bypass path because the final destination is not validated before response processing. The response body is read and parsed for JSON-LD and Open Graph content, potentially returning information obtained from a destination that the caller could not access directly. ### Attack Path 1. An attacker invokes `gumtree/listing` with an HTTP or HTTPS URL under the attacker’s control, or directly supplies an internal-service URL. 2. The URL begins with `http`, so the adapter does not convert it into a Gumtree URL. 3. The unvalidated value is passed to `fetch()`. ...[truncated 1127 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the input using `new URL()` rather than relying on string prefixes. 2. Require the `https:` protocol. 3. Permit only the exact hostname `www.gumtree.com`, or a narrowly defined allowlist of required Gumtree hostnames. 4. Reject URLs containing credentials, unexpected ports, malformed hostnames, or unsupported schemes. 5. Disable automatic redirects and validate every redirect destination before following it. 6. Resolve destination hostnames and reject loopback, private, link-local, multicast, reserved, and otherwise non-public IP ranges for both IPv4 and IPv6. 7. Protect against DNS rebinding by ensuring that validation and connection use the same resolved address. 8. Apply request timeouts, response-size limits, and conservative content-type checks. 9. Prefer accepting a Gumtree listing path or listing identifier rather than an arbitrary absolute URL. A minimum hostname validation pattern is: ```javascript const candidate = new URL(String(args.url), 'https://www.gumtree.com'); if ( candidate.protocol !== 'https:' || candidate.hostname !== 'www.gumtree.com' || candidate.username || candidate.password || candidate.port ) { return { error: 'Only HTTPS URLs on www.gumtree.com are allowed' }; } const resp = await fetch(candidate.href, { redirect: 'manual', headers: { 'User-Agent': '...', Accept: 'text/html,application/xhtml+xml', 'Accept-Language': 'en-GB,en;q=0.9', }, }); ``` Production hardening should additionally validate redirect targets and resolved IP addresses. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:34
Finding
Unpinned Global Installation of a Third-Party Dependency<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, line 34 **Vulnerability Type**: Unsafe and mutable third-party dependency installation **Risk Level**: Medium ### Vulnerable Code ```markdown - [bb-browser](https://www.npmjs.com/package/bb-browser) (`npm i -g bb-browser`). ``` ### Technical Analysis The installation instruction requests the latest version of `bb-browser` from npm and installs it globally. It does not specify an exact reviewed version, lock dependency resolution, verify package integrity, or restrict npm lifecycle scripts. As a result, the effective dependency installed by a user can change after this skill has been reviewed. A compromised package release, compromised maintainer account, malicious transitive dependency, or unexpected future update could introduce code that was not included in the audited project. The use of global installation increases the effect of such a compromise because the package becomes available system-wide for that user and may execute lifecycle scripts during installation with the npm process’s privileges. ### Attack Path 1. A user follows the documented prerequisite and runs `npm i -g bb-browser`. 2. npm resolves the package’s mutable current release rather than a version reviewed with this skill. 3. npm downloads the package and its dependency graph from the configured registry. 4. Any enabled lifecycle scripts execute with the permissions of the installing user. 5. If the selected release or one of its dependencies is compromised, malicious code can run during installation or later when the globally installed command is invoked. ### Impact Assessment The attainable privileges are those of the user running npm. A compromised dependency could potentially: - Read or modify files accessible to that user. - Access environment variables and user-level credentials. - Make outbound network requests. - Alter the globally installed CLI or its supporting files. - Affect future invocations outside ...[truncated 175 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `bb-browser` to an exact version that has been reviewed, for example: ```bash npm install --global --ignore-scripts bb-browser@<reviewed-exact-version> ``` 2. Verify whether lifecycle scripts are required before enabling them. Keep `--ignore-scripts` when they are unnecessary. 3. Prefer a project-local installation over a global installation to reduce system-wide impact: ```bash npm install --save-exact --ignore-scripts bb-browser@<reviewed-exact-version> ``` 4. Commit and verify a lockfile when the packaging model permits it. 5. Record and verify package integrity or provenance information. 6. Review the pinned package’s transitive dependencies and lifecycle scripts. 7. Define an explicit update and re-audit process instead of automatically consuming the latest release. 8. Advise users not to run the installation command with elevated privileges. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
If the code defaults to `all` or permits arbitrary categories, the skill is not actually scoped to pets despite repeated claims that it is. This creates a trust-boundary problem: systems may approve or route the skill under a benign animal-welfare use case while it can in fact scrape generic classifieds, broadening data access and bypassing policy expectations.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
If the code defaults to `all` or permits arbitrary categories, the skill is not actually scoped to pets despite repeated claims that it is. This creates a trust-boundary problem: systems may approve or route the skill under a benign animal-welfare use case while it can in fact scrape generic classifieds, broadening data access and bypassing policy expectations.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Session Persistence

Medium
Category
Rogue Agent
Content
- This bundle includes [`bb-sites/gumtree/search.js`](bb-sites/gumtree/search.js) and [`bb-sites/gumtree/listing.js`](bb-sites/gumtree/listing.js). Install into bb-browser:

```bash
mkdir -p ~/.bb-browser/sites/gumtree
cp bb-sites/gumtree/search.js ~/.bb-browser/sites/gumtree/search.js
cp bb-sites/gumtree/listing.js ~/.bb-browser/sites/gumtree/listing.js
```
Confidence
60% confidence
Finding
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.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The adapter accepts a caller-controlled `category`/`search_category` and defaults to `all`, so it is not technically restricted to pets despite the skill metadata claiming pets-only use. This creates a scope-integrity problem: higher-level systems or users may rely on the declared pet-only constraint, but the code permits searches across unrelated Gumtree categories.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
By exposing `args.category || args.search_category || 'all'`, the skill provides a generic Gumtree search primitive rather than the narrower pet-search capability it advertises. In an agent setting, this can bypass policy or product restrictions built around the declared purpose of the skill, enabling unreviewed access to broader classified content.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The request hard-codes the Accept-Language header to "en-GB,en;q=0.9", which imposes a specific language/locale preference. This is a natural-language policy concern because the skill does not offer user opt-in or explain why a UK English locale is required.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
The request hard-codes the Accept-Language header to en-GB,en;q=0.9, which forces an English (UK) locale regardless of the user's preferences. This is a natural-language/locale policy concern because the skill does not offer any language choice or document a justified locale restriction.

Static analysis

No suspicious patterns detected.