Close Open Privacy Scan

bolt Snapshot: commit 3317809
science engine v1.23
schedule 2026-07-27T22:10:10.623717+00:00

verified_user No application data leak found

No high-confidence exfiltration was found in application code. Dependency data flows are listed separately and do not affect this verdict.

smart_toy MCP server detected: @modelcontextprotocol/sdk — detected in dependencies, not a safety judgment.

App Privacy Score

87 /100
Low privacy risk

Low risk · 54 finding(s)

Based on: 1 first-party package(s) · 5/5 deps analyzed

Dependency score: 67 (Medium risk)

bar_chart Score Breakdown

egress −10
env_fs −3

list Scan Summary

0 high 1 medium 53 low
First-party packages: 1
Dependency packages: 3
Ecosystem: npm

swap_horiz Application data flows

No application data flows were found. See dependency data flows below.

hub Dependency data flows (1)
medium axios dependency Credentials parsed from the request URL are applied as authorization on the same outbound HTTP request. This is intentional URL authentication, not unexpected data exfiltration.
  1. 1sourcepkgs/npm/[email protected]/lib/adapters/http.js:861
  2. 2sinkpkgs/npm/[email protected]/lib/adapters/http.js:1062

</> First-Party Code

first-party (npm)

npm first-party
expand_more 11 low-confidence finding(s)

</> Dependencies

axios

npm dependency
medium pii_flow dependency Excluded from app score #2bb6b8476d11e851 Credentials parsed from the request URL are applied as authorization on the same outbound HTTP request. This is intentional URL authentication, not unexpected data exfiltration.
pkgs/npm/[email protected]/lib/adapters/http.js:1062 · flow /tmp/closeopen-8xqdwio5/pkgs/npm/[email protected]/lib/adapters/http.js:861 → /tmp/closeopen-8xqdwio5/pkgs/npm/[email protected]/lib/adapters/http.js:1062
      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)
low egress Outbound request to a variable or assembled URL on a network client. Review what data is sent to this destination. 2 locations
low env_fs dependency Excluded from app score #d487f0211ae4d59f capability detected · no path traced Environment-variable access.
pkgs/npm/[email protected]/lib/helpers/shouldBypassProxy.js:168
  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 dependency
expand_more 38 low-confidence finding(s)
low egress Outbound request to a variable or assembled URL on a network client. Review what data is sent to this destination. 22 locations
low egress tooling Excluded from app score unknown #208803f60ec8302e capability detected · no path traced Hardcoded external endpoint. Review what data is sent to this destination.
pkgs/npm/@[email protected]__reposrc/scripts/fetch-spec-types.ts:16
    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.

low env_fs tooling Excluded from app score unknown #65aabbe90696de2c capability detected · no path traced Filesystem access.
pkgs/npm/@[email protected]__reposrc/scripts/fetch-spec-types.ts:77
        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.

low env_fs Environment-variable access. 14 locations

express

npm dependency
expand_more 1 low-confidence finding(s)
low env_fs dependency Excluded from app score #e4c73bc9ba1cbb5b capability detected · no path traced Environment-variable access.
pkgs/npm/[email protected]/lib/application.js:91
  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.