T09 · Insecure Skill Coding Practices
- Location
index.js:42- Finding
Unrestricted API Base URL Can Expose Bearer Credentials and Patient Data
- Content
View full analysis
Vulnerability Details
File Location:
index.js:42-77, with attacker-influenced request construction atindex.js:4,index.js:12,index.js:20, andindex.js:33-39
Vulnerability Type: Unvalidated network destination receiving sensitive credentials and data
Risk Level: HighVulnerable Code
js async function apiFetch(url, method, body, token) { const opciones = { method, headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', 'Accept': 'application/json', }, }; if (body && ['POST', 'PUT', 'PATCH'].includes(method)) { opciones.body = JSON.stringify(body); } let res; try { res = await fetch(url, opciones); } catch (err) { return { error: true, message: `Error de red: ${err.message}` }; } const texto = await res.text(); let datos; try { datos = JSON.parse(texto); } catch { return { error: true, status: res.status, message: texto.slice(0, 500) }; } if (!res.ok) { return { error: true, status: res.status, ...datos }; } return datos; }The sensitive appointment request is constructed as follows:
js return apiFetch( `${config.baseUrl}/api/agendar_turno.php`, 'POST', { paciente_id, doctor_id, fecha, hora, motivo }, config.apiKey );Technical Analysis
All request destinations are derived from the unrestricted
config.baseUrlvalue. The code does not parse or validate the configured URL before attachingconfig.apiKeyas a bearer credential and transmitting the request.The manifest declares only the
network:api.odontosoft.com.pypermission, but itsbaseUrlconfiguration is a free-form required string. Consequently, the implementation itself does not guarantee the README's claim that requests are limited toapi.odontosoft.com.py.The runtime may independently enforce the manifest ...[truncated 2008 chars]
- Remediation
View remediation
Remediation Suggestions
- Remove
baseUrlfrom user-controlled configuration if the Skill only supports the production Odontosoft service. Use a fixed trusted origin instead. - If multiple deployments must be supported, parse the value with
new URL(config.baseUrl)and enforce:protocol === 'https:';- an exact allowlist of approved hostnames;
- an approved port or the default HTTPS port;
- no embedded username or password;
- no unexpected path, query string, or fragment in the configured origin.
- Construct request URLs with the
URLAPI rather than string concatenation. - Maintain independent runtime egress controls that permit only the approved Odontosoft host.
- Avoid forwarding authorization headers across redirects, or reject redirects entirely for authenticated API calls.
- Validate that the final request origin is approved immediately before attaching the bearer token.
- Add tests confirming rejection of HTTP URLs, attacker-controlled hosts, internal IP addresses, malformed URLs, alternate ports, and credential-bearing URLs.
- Rotate the API token if there is evidence that the Skill has operated with an untrusted
baseUrl.
- Remove
