Close Open Privacy Scan
App Privacy Score
Low risk · 54 finding(s)
Dependency score: 67 (Medium risk)
bar_chart Score Breakdown
list Scan Summary
swap_horiz Application data flows
No application data flows were found. See dependency data flows below.
hub Dependency data flows (1)
pkgs/npm/[email protected]/lib/adapters/http.js:861 → pkgs/npm/[email protected]/lib/adapters/http.js:1062</> First-Party Code
first-party (npm)
npm first-partyexpand_more 11 low-confidence finding(s)
process.env.VIS_REQUEST_SERVER = "https://example.com/api/gpt-vis";
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
process.env.DISABLED_TOOLS = undefined;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
process.env.DISABLED_TOOLS = "generate_fishbone_diagram,generate_mind_map";
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
process.env.DISABLED_TOOLS = "";
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
process.env.VIS_REQUEST_SERVER =
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
process.env.DISABLED_TOOLS = undefined;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
process.env.VIS_REQUEST_SERVER ||
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
return process.env.SERVICE_ID;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const disabledTools = process.env.DISABLED_TOOLS;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const response = await httpClient.post(url, {
type,
...options,
source: "mcp-server-chart",
});
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const response = await httpClient.post(url, {
serviceId: getServiceIdentifier(),
tool,
input,
source: "mcp-server-chart",
});
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
</> Dependencies
axios
npm dependency req = transport.request(options, function handleResponse(res) {
clearConnectPhaseTimer();
if (req.destroyed) return;
const streams = [res];
const responseLength = utils.toFiniteNumber(res.headers['content-length']);
if (onDownloadProgress || maxDownloadRate) {
const transformStream = new AxiosTransformStream({
maxRate: utils.toFiniteNumber(maxDownloadRate),
});
onDownloadProgress &&
transformStream.on(
'progress',
flushOnFinish(
transformStream,
progressEventDecorator(
responseLength,
progressEventReducer(asyncDecorator(onDownloadProgress), true, 3)
)
)
);
streams.push(transformStream);
}
// decompress the response body transparently if required
let responseStream = res;
// return the last request in case of redirects
const lastRequest = res.req || req;
// if decompress disabled we should not decompress
if (decompress !== false && res.headers['content-encoding']) {
// if no content, but headers still say that it is encoded,
// remove the header not confuse downstream operations
if (method === 'HEAD' || res.statusCode === 204) {
delete res.headers['content-encoding'];
}
switch ((res.headers['content-encoding'] || '').toLowerCase()) {
/*eslint default-case:0*/
case 'gzip':
case 'x-gzip':
case 'compress':
case 'x-compress':
// add the unzipper to the body stream processing pipeline
streams.push(zlib.createUnzip(zlibOptions));
// remove the content-encoding in order to not confuse downstream operations
delete res.headers['content-encoding'];
break;
case 'deflate':
streams.push(new ZlibHeaderTransformStream());
// add the unzipper to the body stream processing pipeline
streams.push(zlib.createUnzip(zlibOptions));
// remove the content-encoding in order to not confuse downstream operations
delete res.headers['content-encoding'];
break;
case 'br':
if (isBrotliSupported) {
streams.push(zlib.createBrotliDecompress(brotliOptions));
delete res.headers['content-encoding'];
}
break;
case 'zstd':
if (isZstdSupported) {
streams.push(zlib.createZstdDecompress(zstdOptions));
delete res.headers['content-encoding'];
}
break;
}
}
responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
const response = {
status: res.statusCode,
statusText: res.statusMessage,
headers: new AxiosHeaders(res.headers),
config,
request: lastRequest,
};
if (responseType === 'stream') {
// Enforce maxContentLength on streamed responses; previously this
// was applied only to buffered responses.
if (maxContentLength > -1) {
const limit = maxContentLength;
const source = responseStream;
async function* enforceMaxContentLength() {
let totalResponseBytes = 0;
for await (const chunk of source) {
totalResponseBytes += chunk.length;
if (totalResponseBytes > limit) {
throw new AxiosError(
'maxContentLength size of ' + limit + ' exceeded',
AxiosError.ERR_BAD_RESPONSE,
config,
lastRequest
);
}
yield chunk;
}
}
responseStream = stream.Readable.from(enforceMaxContentLength(), {
objectMode: false,
});
}
response.data = responseStream;
settle(resolve, reject, response);
} else {
const responseBuffer = [];
let totalResponseBytes = 0;
responseStream.on('data', function handleStreamData(chunk) {
responseBuffer.push(chunk);
totalResponseBytes += chunk.length;
// make sure the content length is not over the maxContentLength if specified
if (maxContentLength > -1 && totalResponseBytes > maxContentLength) {
// stream.destroy() emit aborted event before calling reject() on Node.js v16
rejected = true;
responseStream.destroy();
abort(
new AxiosError(
'maxContentLength size of ' + maxContentLength + ' exceeded',
AxiosError.ERR_BAD_RESPONSE,
config,
lastRequest
)
);
}
});
responseStream.on('aborted', function handlerStreamAborted() {
if (rejected) {
return;
}
const err = new AxiosError(
'stream has been aborted',
AxiosError.ERR_BAD_RESPONSE,
config,
lastRequest,
response
);
responseStream.destroy(err);
reject(err);
});
responseStream.on('error', function handleStreamError(err) {
if (rejected) return;
reject(AxiosError.from(err, null, config, lastRequest, response));
});
responseStream.on('end', function handleStreamEnd() {
try {
let responseData =
responseBuffer.length === 1 ? responseBuffer[0] : Buffer.concat(responseBuffer);
if (responseType !== 'arraybuffer') {
responseData = responseData.toString(responseEncoding);
if (!responseEncoding || responseEncoding === 'utf8') {
responseData = utils.stripBOM(responseData);
}
}
response.data = responseData;
} catch (err) {
return reject(AxiosError.from(err, null, config, response.request, response));
}
settle(resolve, reject, response);
});
}
abortEmitter.once('abort', (err) => {
if (!responseStream.destroyed) {
responseStream.emit('error', err);
responseStream.destroy();
}
});
});
A credential (read from the environment/filesystem, or parsed from the request URL) is applied as authorization on the same outbound request. This is intentional authentication to the service the credential belongs to, not unexpected data exfiltration.
Fix: Confirm the destination is the credential's own service; scope the credential and avoid logging it. No action if this is the intended authenticated API call.
expand_more 3 low-confidence finding(s)
const req = session.request(http2Headers);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
req = transport.request(options, function handleResponse(res) {
clearConnectPhaseTimer();
if (req.destroyed) return;
const streams = [res];
const responseLength = utils.toFiniteNumber(res.headers['content-length']);
if (onDownloadProgress || maxDownloadRate) {
const transformStream = new AxiosTransformStream({
maxRate: utils.toFiniteNumber(maxDownloadRate),
});
onDownloadProgress &&
transformStream.on(
'progress',
flushOnFinish(
transformStream,
progressEventDecorator(
responseLength,
progressEventReducer(asyncDecorator(onDownloadProgress), true, 3)
)
)
);
streams.push(transformStream);
}
// decompress the response body transparently if required
let responseStream = res;
// return the last request in case of redirects
const lastRequest = res.req || req;
// if decompress disabled we should not decompress
if (decompress !== false && res.headers['content-encoding']) {
// if no content, but headers still say that it is encoded,
// remove the header not confuse downstream operations
if (method === 'HEAD' || res.statusCode === 204) {
delete res.headers['content-encoding'];
}
switch ((res.headers['content-encoding'] || '').toLowerCase()) {
/*eslint default-case:0*/
case 'gzip':
case 'x-gzip':
case 'compress':
case 'x-compress':
// add the unzipper to the body stream processing pipeline
streams.push(zlib.createUnzip(zlibOptions));
// remove the content-encoding in order to not confuse downstream operations
delete res.headers['content-encoding'];
break;
case 'deflate':
streams.push(new ZlibHeaderTransformStream());
// add the unzipper to the body stream processing pipeline
streams.push(zlib.createUnzip(zlibOptions));
// remove the content-encoding in order to not confuse downstream operations
delete res.headers['content-encoding'];
break;
case 'br':
if (isBrotliSupported) {
streams.push(zlib.createBrotliDecompress(brotliOptions));
delete res.headers['content-encoding'];
}
break;
case 'zstd':
if (isZstdSupported) {
streams.push(zlib.createZstdDecompress(zstdOptions));
delete res.headers['content-encoding'];
}
break;
}
}
responseStream = streams.length > 1 ? stream.pipeline(streams, utils.noop) : streams[0];
const response = {
status: res.statusCode,
statusText: res.statusMessage,
headers: new AxiosHeaders(res.headers),
config,
request: lastRequest,
};
if (responseType === 'stream') {
// Enforce maxContentLength on streamed responses; previously this
// was applied only to buffered responses.
if (maxContentLength > -1) {
const limit = maxContentLength;
const source = responseStream;
async function* enforceMaxContentLength() {
let totalResponseBytes = 0;
for await (const chunk of source) {
totalResponseBytes += chunk.length;
if (totalResponseBytes > limit) {
throw new AxiosError(
'maxContentLength size of ' + limit + ' exceeded',
AxiosError.ERR_BAD_RESPONSE,
config,
lastRequest
);
}
yield chunk;
}
}
responseStream = stream.Readable.from(enforceMaxContentLength(), {
objectMode: false,
});
}
response.data = responseStream;
settle(resolve, reject, response);
} else {
const responseBuffer = [];
let totalResponseBytes = 0;
responseStream.on('data', function handleStreamData(chunk) {
responseBuffer.push(chunk);
totalResponseBytes += chunk.length;
// make sure the content length is not over the maxContentLength if specified
if (maxContentLength > -1 && totalResponseBytes > maxContentLength) {
// stream.destroy() emit aborted event before calling reject() on Node.js v16
rejected = true;
responseStream.destroy();
abort(
new AxiosError(
'maxContentLength size of ' + maxContentLength + ' exceeded',
AxiosError.ERR_BAD_RESPONSE,
config,
lastRequest
)
);
}
});
responseStream.on('aborted', function handlerStreamAborted() {
if (rejected) {
return;
}
const err = new AxiosError(
'stream has been aborted',
AxiosError.ERR_BAD_RESPONSE,
config,
lastRequest,
response
);
responseStream.destroy(err);
reject(err);
});
responseStream.on('error', function handleStreamError(err) {
if (rejected) return;
reject(AxiosError.from(err, null, config, lastRequest, response));
});
responseStream.on('end', function handleStreamEnd() {
try {
let responseData =
responseBuffer.length === 1 ? responseBuffer[0] : Buffer.concat(responseBuffer);
if (responseType !== 'arraybuffer') {
responseData = responseData.toString(responseEncoding);
if (!responseEncoding || responseEncoding === 'utf8') {
responseData = utils.stripBOM(responseData);
}
}
response.data = responseData;
} catch (err) {
return reject(AxiosError.from(err, null, config, response.request, response));
}
settle(resolve, reject, response);
});
}
abortEmitter.once('abort', (err) => {
if (!responseStream.destroyed) {
responseStream.emit('error', err);
responseStream.destroy();
}
});
});
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const noProxy = (process.env.no_proxy || process.env.NO_PROXY || '').toLowerCase();
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
@modelcontextprotocol/sdk
npm dependencyexpand_more 38 low-confidence finding(s)
await client.request({ method: 'resources/list' }, ListResourcesResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const response = await fetch(url);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const response = await fetch(url);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
writeFileSync(outputPath, fullContent, 'utf-8');
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const value = process.env[key];
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const toolsResult = await client.request(toolsRequest, ListToolsResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const result = await client.request(request, CallToolResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const result = await client.request(toolRequest, CallToolResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const toolsResult = await client.request(toolsRequest, ListToolsResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
return client
.request(request, CallToolResultSchema)
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const DEFAULT_SERVER_URL = process.env.MCP_SERVER_URL || 'http://localhost:3000/mcp';
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const clientId = process.env.MCP_CLIENT_ID;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const privateKeyPem = process.env.MCP_CLIENT_PRIVATE_KEY_PEM;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const algorithm = process.env.MCP_CLIENT_ALGORITHM || 'RS256';
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const clientSecret = process.env.MCP_CLIENT_SECRET;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const result = await this.client.request(request, ListToolsResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const result = await this.client.request(request, CallToolResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const resourcesResult = await client.request(
{
method: 'resources/list',
params: {}
},
ListResourcesResultSchema
);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const toolsResult = await client.request(toolsRequest, ListToolsResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const result = await client.request(request, CallToolResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const result = await client.request(request, CallToolResultSchema, {
resumptionToken: notificationsToolLastEventId,
onresumptiontoken: onLastEventIdUpdate
});
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const promptsResult = await client.request(promptsRequest, ListPromptsResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const promptResult = await client.request(promptRequest, GetPromptResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const resourcesResult = await client.request(resourcesRequest, ListResourcesResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const result = await client.request(request, ReadResourceResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const result = await client.request(
{
method: 'tools/call',
params: {
name: 'long-task',
arguments: {}
}
},
CallToolResultSchema,
{
// Track resumption tokens for debugging
onresumptiontoken: token => {
lastEventId = token;
console.log(`[Event ID] ${token}`);
}
}
);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const toolsResult = await client.request(toolsRequest, ListToolsResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const result = await client.request(request, CallToolResultSchema);
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const MCP_PORT = process.env.MCP_PORT ? parseInt(process.env.MCP_PORT, 10) : 3000;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const AUTH_PORT = process.env.MCP_AUTH_PORT ? parseInt(process.env.MCP_AUTH_PORT, 10) : 3001;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
token: token
}).toString()
});
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const PORT = process.env.MCP_PORT ? parseInt(process.env.MCP_PORT, 10) : 3000;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const MCP_PORT = process.env.MCP_PORT ? parseInt(process.env.MCP_PORT, 10) : 3000;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const AUTH_PORT = process.env.MCP_AUTH_PORT ? parseInt(process.env.MCP_AUTH_PORT, 10) : 3001;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
const response = await fetch(endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
token: token
}).toString()
});
Data is sent to a hardcoded external endpoint; review what leaves the process.
Fix: Verify the destination and that only non-sensitive data is sent; pin and audit the dependency.
const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : 8000;
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
process.env.MCP_DANGEROUSLY_ALLOW_INSECURE_ISSUER_URL === 'true' || process.env.MCP_DANGEROUSLY_ALLOW_INSECURE_ISSUER_URL === '1';
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.
express
npm dependencyexpand_more 1 low-confidence finding(s)
var env = process.env.NODE_ENV || 'development';
Reads environment variables or the filesystem — an inventory-level capability, not a leak on its own.
Fix: Usually benign; confirm any secret read here is not later sent externally.