Back to skill

Security audit

Mercedes-Benz USA Utilities

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent for Mercedes-Benz dealer and inventory lookup, but its REST server can become an unauthenticated public proxy with weak input limits if started.

Install only if you are comfortable with a skill that contacts MBUSA services and, when npm start is used, opens a local REST API. Keep it bound to localhost or behind authentication, add rate limits and strict input validation before exposing it on any network, and update the flagged npm dependencies.

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

Warning
Location
server.js:11
Finding
Unauthenticated and Unrestricted External API Proxy<![CDATA[ ## Vulnerability Details **File Location**: `server.js:11-23`, `server.js:31-66`, `server.js:74-109`, and `server.js:115-120` **Vulnerability Type**: Missing authentication, rate limiting, concurrency controls, and restrictive network binding **Risk Level**: Medium ### Vulnerable Code ```js app.get('/api/dealers', async (req, res) => { try { const zip = req.query.zip; if (!zip) return res.status(400).json({ status: "error", message: "Missing required parameter: zip" }); const start = req.query.start ? parseInt(req.query.start, 10) : 0; const count = req.query.count ? parseInt(req.query.count, 10) : 10; const filter = req.query.filter || "mbdealer"; const resultString = await getMbusaDealers(zip, start, count, filter); const resultJson = JSON.parse(resultString); if (resultJson.status === "error") return res.status(502).json(resultJson); res.status(200).json(resultJson); } catch (error) { console.error("Dealer API Error:", error); res.status(500).json({ status: "error", message: "Internal server error" }); } }); ``` ```js app.get('/api/inventory', async (req, res) => { try { if (!req.query.zip) return res.status(400).json({ status: "error", message: "Missing required parameter: zip" }); // Request parameters are forwarded to an external API. const resultString = await getMbusaInventory(params); const resultJson = JSON.parse(resultString); if (resultJson.status === "error") return res.status(502).json(resultJson); res.status(200).json(resultJson); } catch (error) { console.error("New Inventory API Error:", error); res.status(500).json({ status: "error", message: "Internal server error" }); } }); ``` ```js app.get('/api/used-inventory', async (req, res) => { try { if (!req.query.zip) return res.status(400).json({ status: "error", message: "Missing required par ...[truncated 3121 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Restrict local deployments to loopback**: ```js const HOST = process.env.HOST || '127.0.0.1'; app.listen(PORT, HOST, () => { console.log(`Server listening on http://${HOST}:${PORT}`); }); ``` 2. **Require authentication** before allowing access in any network-facing deployment. Use securely generated API keys, OAuth, or authentication supplied by a trusted reverse proxy. 3. **Add per-client rate limits and quotas**, for example with a maintained Express rate-limiting middleware. Apply stricter limits to routes that initiate outbound requests. 4. **Limit concurrent upstream operations** with a queue or semaphore so a burst cannot create an unbounded number of pending outbound requests. 5. **Set outbound request deadlines** using `AbortSignal.timeout()` or an `AbortController`: ```js const response = await fetch(apiUrl, { headers, signal: AbortSignal.timeout(10000) }); ``` 6. **Deploy behind a hardened reverse proxy** with connection limits, request timeouts, TLS, authentication, and network access controls. 7. **Document the exposure model clearly** so users do not infer from the localhost examples that the server is technically restricted to localhost. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
server.js:13
Finding
Missing Runtime Input Validation and Unbounded Pagination Parameters<![CDATA[ ## Vulnerability Details **File Location**: `server.js:13-17`, `server.js:33-60`, and `server.js:76-103` **Vulnerability Type**: Improper input validation and resource-consumption amplification **Risk Level**: Medium ### Vulnerable Code ```js const zip = req.query.zip; if (!zip) return res.status(400).json({ status: "error", message: "Missing required parameter: zip" }); const start = req.query.start ? parseInt(req.query.start, 10) : 0; const count = req.query.count ? parseInt(req.query.count, 10) : 10; const filter = req.query.filter || "mbdealer"; const resultString = await getMbusaDealers(zip, start, count, filter); ``` ```js const params = { zip: req.query.zip, dealerId: req.query.dealerId, model: req.query.model, classId: req.query.classId, bodyStyle: req.query.bodyStyle, brand: req.query.brand, exteriorColor: req.query.exteriorColor, interiorColor: req.query.interiorColor, highwayFuelEconomy: req.query.highwayFuelEconomy, fuelType: req.query.fuelType, distance: req.query.distance ? parseInt(req.query.distance, 10) : undefined, minPrice: req.query.minPrice ? parseInt(req.query.minPrice, 10) : undefined, maxPrice: req.query.maxPrice ? parseInt(req.query.maxPrice, 10) : undefined, minYear: req.query.minYear ? parseInt(req.query.minYear, 10) : undefined, maxYear: req.query.maxYear ? parseInt(req.query.maxYear, 10) : undefined, passengerCapacity: req.query.passengerCapacity ? parseInt(req.query.passengerCapacity, 10) : undefined, year: req.query.year ? parseInt(req.query.year, 10) : undefined, start: req.query.start ? parseInt(req.query.start, 10) : 0, count: req.query.count ? parseInt(req.query.count, 10) : 12 }; const resultString = await getMbusaInventory(params); ``` ```js const params = { zip: req.query.zip, invType: req.query.invType, dealerId: req.query.dealerId, model: req.query.model, classId: req.query.classId, bodyStyle: req.query.bo ...[truncated 3694 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Apply runtime validation to every HTTP route.** Use a maintained validator such as Ajv, Zod, Joi, or express-validator. Do not rely on `schema.json` being honored by direct clients. 2. **Validate ZIP codes explicitly**: ```js if (!/^\d{5}$/.test(String(req.query.zip || ''))) { return res.status(400).json({ status: 'error', message: 'zip must be a five-digit US ZIP code' }); } ``` 3. **Use strict integer parsing and bounds checks**: ```js function boundedInteger(value, defaultValue, min, max) { if (value === undefined) return defaultValue; if (!/^-?\d+$/.test(String(value))) throw new Error('Invalid integer'); const parsed = Number(value); if (!Number.isSafeInteger(parsed) || parsed < min || parsed > max) { throw new Error('Integer outside permitted range'); } return parsed; } const start = boundedInteger(req.query.start, 0, 0, 10000); const count = boundedInteger(req.query.count, 12, 1, 100); ``` 4. **Enforce documented enum values** for `invType`, distance, model, class, body style, brand, colors, year, fuel type, mileage, passenger capacity, and fuel economy. 5. **Validate price relationships and limits**, including non-negative values and `minPrice <= maxPrice`. 6. **Reject unknown query parameters** where feasible, preventing silent acceptance of unsupported inputs. 7. **Add response and request resource controls**, including outbound timeouts, concurrency limits, rate limits, and a conservative server-side maximum for `count`. 8. **Return HTTP 400 for validation failures** rather than forwarding invalid data and converting upstream failures into HTTP 502 responses. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (6)

Known Vulnerable Dependency: body-parser==1.20.4 — 1 advisory(ies): CVE-2026-12590 (body-parser vulnerable to denial of service when invalid limit value silently di)

Low
Category
Supply Chain
Confidence
89% confidence
Finding
The lockfile pins body-parser 1.20.4, which is reported to have a denial-of-service issue when invalid limit values are mishandled. This is a real dependency risk, although package-lock.json alone does not prove the vulnerable code path is exercised by the skill; if exposed through request parsing, an attacker could cause service instability or crashes.

Known Vulnerable Dependency: qs==6.14.2 — 3 advisory(ies): CVE-2026-82417 (qs: Denial of Service via Attacker Controlled isBuffer); CVE-2026-8723 (qs has a remotely triggerable DoS: qs.stringify crashes with TypeError on null/u); CVE-2026-82562 (qs array-limit bypass via bracket-key comma parsing)

Low
Category
Supply Chain
Confidence
93% confidence
Finding
The lockfile includes qs 6.14.2, which is flagged for multiple denial-of-service issues involving attacker-controlled parsing/stringification edge cases and array-limit bypass behavior. In an Express-based service, qs may be used for query/body parsing, so malformed requests could potentially consume resources or crash request handling depending on configuration and reachability.

Unpinned Dependencies

Low
Category
Supply Chain
Content
},
  "license": "MIT",
  "dependencies": {
    "express": "^4.21.2"
  }
}
Confidence
40% confidence
Finding
Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Natural-Language Policy Violations

Low
Confidence
81% confidence
Finding
The description says to "ALWAYS format the Google Maps URL as a Markdown link," which is a natural-language output policy imposed unconditionally. This constrains presentation format regardless of user preference or client compatibility and can be interpreted as a policy-style formatting requirement without opt-in.

Natural-Language Policy Violations

Low
Confidence
81% confidence
Finding
The instruction "ALWAYS format the output with Markdown links" imposes a mandatory output format in natural language rather than offering flexibility based on user or environment needs. Because it is unconditional, it may violate organizational expectations around respecting user/client formatting preferences.

Natural-Language Policy Violations

Low
Confidence
81% confidence
Finding
The phrase "ALWAYS format the output with Markdown links" is a mandatory natural-language instruction that does not allow for user choice or non-Markdown clients. This is a presentation policy constraint applied universally without documented justification.

Static analysis

No suspicious patterns detected.