BytesafeDependency Firewall

Block install-time code execution

Match npm lifecycle scripts, PyPI source-build hooks, and Composer plugins with the install-scripts selector function.

The install-scripts selector function matches releases that can execute package-author code during installation or build. It supports npm, PyPI, and Composer and has no options.

For npm and PyPI, it inspects the package artifact in the download and upload phases. For Composer, it reads plugin metadata and supports versions and download. Many legitimate packages match these conditions, so review log-only results before you enable blocking.

What matches

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
ComposerA release with package type composer-plugin or the legacy composer-installerOther package types, including the default library type

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 select Add Rule. Choose Block packages from being downloaded on the intent step, then select Continue.

  • Execution phase: Download for any supported ecosystem, or Versions for Composer when you want matching releases removed before resolution
  • Selector function: Install-time code execution (no options)
  • Effect: start with log only

For npm or PyPI publishing, add the same rule on the Upload phase. Composer has no upload operation.

As JSON:

{
  "id": "log-install-time-code-download",
  "executionPhase": "download",
  "selector": { "function": { "name": "install-scripts" } },
  "ruleEffect": { "block": false, "log": true },
  "description": "Log releases that can execute code at install time"
}

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

Unlike malware blocking, do not block on day one. Native modules, postinstall downloads, build hooks, and Composer plugins can all be legitimate. 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.

For Composer, the rule output records the package type and any plugin classes declared in extra.class:

{
  "message": "Composer plugin detected: Composer\\Installers\\Plugin",
  "ecosystem": "composer",
  "packageType": "composer-plugin",
  "pluginClasses": ["Composer\\Installers\\Plugin"]
}

Inspection source

npm reads package.json from the package artifact. PyPI reads a root setup.py or pyproject.toml from an sdist. Composer reads type and extra.class from repository metadata, so it can match before the package file is downloaded.

Verify

With the log-only rule in place, follow the install verification on the relevant ecosystem page, then inspect the matching entry in Logs. npm entries begin with Install scripts detected, PyPI entries with PyPI source-build hooks detected, and Composer entries with Composer plugin detected.

On this page