BytesafeDependency Firewall

Block install scripts

Match npm packages that declare install scripts and PyPI sdists that run code at build time, with the install-scripts selector function.

The install-scripts selector function inspects the package artifact and matches packages that declare code hooks which run on the developer's machine during install or build. It runs where the artifact is available: the download phase for installs and the upload phase for publishes. It supports npm and PyPI and has no options.

An install script runs the moment the package is installed, before any of your code imports it, which is what makes it worth knowing about. Many legitimate packages declare one, so this rule needs a review period before you turn on blocking.

What counts as an install script

EcosystemMatchesDoes not match
npmAny of preinstall, install, postinstall declared in the package's package.json scriptsOther lifecycle scripts (prepare, postpublish, ...), scripts in dependencies of the package
PyPIA source distribution (.tar.gz or .zip) with a setup.py at the root, or a root pyproject.toml whose [build-system] declares backend-path (an in-tree PEP 517 build backend)Wheels (.whl), which install without running package code; sdists using an external build backend such as setuptools.build_meta without backend-path

For PyPI, only files at the sdist root (or its single top-level directory) count; a setup.py under tests/ does not match.

Add the rule

The rule is not part of the default rule set; create it yourself. In the dashboard, open the firewall, go to Rules, and create a rule:

  • Execution phase: download
  • Selector function: Install scripts (no options)
  • Effect: start with log only

If the firewall receives publishes, add the same rule on the upload phase.

As JSON:

[
  {
    "id": "log-install-scripts-download",
    "executionPhase": "download",
    "selector": { "function": { "name": "install-scripts" } },
    "ruleEffect": { "block": false, "log": true },
    "description": "Log packages that declare install scripts"
  },
  {
    "id": "log-install-scripts-upload",
    "executionPhase": "upload",
    "selector": { "function": { "name": "install-scripts" } },
    "ruleEffect": { "block": false, "log": true },
    "description": "Log published packages that declare install scripts"
  }
]

To apply the JSON without the dashboard: export the config with bsfw config export, add the rules to the rules array, and import it back. See config import.

Unlike malware blocking, do not block on day one. Widely used packages (native modules, postinstall downloads) legitimately declare install scripts, and a blocking rule without review will break installs. Run log-only, review the matches in logs, add exceptions for the packages you accept, then switch the effect to block.

What a match looks like

The log entry's message names what was found. For npm:

{
  "message": "Install scripts detected: preinstall, postinstall",
  "scripts": ["preinstall", "postinstall"]
}

For PyPI, the rule output also records the finding locations:

{
  "message": "PyPI source-build hooks detected: setup.py",
  "ecosystem": "pypi",
  "artifactType": "sdist",
  "findings": [
    { "kind": "setup.py", "path": "demo-1.0.0/setup.py" }
  ]
}

A pyproject.toml backend-path finding additionally carries the declared backend and backendPath values.

Limits

Inspection reads the package manifest inside the artifact: package.json for npm, a root setup.py or pyproject.toml for a PyPI sdist. Results are cached by the artifact's SHA-256, so an artifact is inspected once rather than on every install.

Verify

With the log-only rule in place, install a package that declares a postinstall script through the firewall, then find the log entry with the Install scripts detected message (see View logs). For PyPI, install a package that only ships an sdist; a wheel install will not match.

On this page