Close Open Privacy Scan
App Privacy Score
Medium risk · 14 finding(s)
Dependency score: 97 (Low risk)
bar_chart Score Breakdown
list Scan Summary
swap_horiz Potential data exfiltration in application code
External domains:
api.opencollective.com
repo/lib/adapters/http.js:863 → repo/lib/adapters/http.js:1064</> First-Party Code
first-party (npm)
npm first-party 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, scheduleProgress), 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();
}
});
});
User/PII-bearing data flows to an external sink — the classic data-exfiltration shape.
Fix: Confirm no user identifiers reach this sink; redact/hash before sending, or remove the flow.
expand_more 10 low-confidence finding(s)
const response = await axios.post('https://api.opencollective.com/graphql/v2', {
query: getAllSponsorsQuery,
});
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 axios.post('https://api.opencollective.com/graphql/v2', {
query: getActiveSponsorsQuery,
});
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.
fs.writeFileSync('./data/sponsors.json', JSON.stringify(sponsorsByTier, null, 2));
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.
import fs from 'fs';
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 npm = JSON.parse(await fs.readFile('package.json'));
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.
await fs.writeFile('package.json', JSON.stringify(npm, null, 2));
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.
var npm = JSON.parse(await fs.readFile('package.json'));
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.
await fs.writeFile(
envFilePath,
Object.entries({
VERSION: (argv.bump || npm.version).replace(/^v/, ''),
})
.map(([key, value]) => {
return `export const ${key} = ${JSON.stringify(value)};`;
})
.join('\n')
);
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 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.
import fs from 'fs';
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.
</> Dependencies
form-data
npm dependencyexpand_more 1 low-confidence finding(s)
var fs = require('fs');
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.
proxy-from-env
npm dependencyexpand_more 2 low-confidence finding(s)
return process.env[key.toLowerCase()] || process.env[key.toUpperCase()] || '';
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[key.toLowerCase()] || process.env[key.toUpperCase()] || '';
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.
Skipped dependencies
Production
- https-proxy-agent prod — dist-only: no readable source