Skip to content

Add post-build import-time behavioral monitor under network isolation #1147

@LalatenduMohanty

Description

@LalatenduMohanty

Problem

Fromager's existing network isolation (run_network_isolation.sh) blocks outbound access during PEP 517 build hooks, preventing build-time supply chain attacks from phoning home. However, some attacks deliberately place malicious code in the package's runtime paths (e.g., __init__.py) instead of build hooks, so it only executes on import, not during build.

The May 2026 "Mini Shai-Hulud" campaign (mistralai/client-python#523) demonstrated this: mistralai and guardrails-ai were compromised with backdoors in __init__.py that downloaded a credential-stealing payload via urllib.request.urlopen() and executed it as a detached process. This attack vector is invisible to build-time monitoring because the malicious code never runs during wheel compilation.

Proposal

After pep517_build_wheel() produces the .whl but before add_extra_metadata_to_wheels(), install the wheel into a temporary virtualenv and run python -c "import <package>" under the same run_network_isolation.sh used for builds.

Key design decision -- behavior-only monitoring: import failures (ImportError, ModuleNotFoundError, etc.) are expected and ignored. Many legitimate packages cannot import in a build environment (GPU packages needing CUDA runtime, packages with unmet optional dependencies). The monitor only flags anomalous behavior during the import attempt:

  • Network access attempts (blocked by existing namespace isolation)
  • Writes to sensitive filesystem paths (/tmp/, ~/.ssh/, ~/.config/)
  • Unexpected subprocess spawning (curl, wget, detached processes)

This avoids false positives without needing a per-package allowlist. Real-world import-time backdoors use except: pass and execute their payload before any import-dependent code, so behavior monitoring catches them regardless of whether the import itself succeeds.

Why this works for downstream consumers

In downstream build pipelines, this runs transparently before the post_build hook fires -- compromised wheels are caught before upload to a package registry. No downstream changes needed, no allowlist to maintain.

Related issues

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions