Not every MXNet workload can be ported this year, and pretending otherwise produces the worst outcome of all: an official migration project that stalls, while the production system drifts along with neither maintenance nor a plan. The disciplined alternative is containment — running an unsupported framework on purpose, with the risk bounded, monitored, and given an expiry date. Here's what that looks like in practice.
Step one: make it rebuildable
The single highest-value containment action costs nothing but honesty: try to rebuild every MXNet environment from source control, today, on a clean machine. Not "we have a Dockerfile" — actually run the build.
Most aging estates fail this test somewhere. Wheels that pip resolved in 2022 resolve differently now; base images got deleted or retagged; an internal mirror quietly dropped old artifacts; a build step reached out to a URL that no longer exists. Every one of these failures is cheap to fix while the knowledge still exists and expensive to fix during an incident.
The goal state: fully pinned dependency manifests (hash-pinned, not version-ranged), vendored copies of every artifact the build needs — MXNet wheels included, since PyPI availability is not guaranteed forever — and a CI job that rebuilds the image from scratch on a schedule, so rot is detected in weeks rather than discovered in an outage.
Step two: watch a tree nobody else is watching
Normal vulnerability management leans on upstream: a CVE lands, the maintainer patches, you upgrade. With a retired framework the second step never happens, so the process changes shape:
- Scan the full transitive tree, not just the framework — MXNet pins old versions of NumPy, protobuf, and friends, and those pins are where most findings will come from.
- Assess reachability, not just presence. A scanner will flag plenty in a frozen tree. The question that matters is whether the vulnerable path is reachable in your deployment: an image-parsing CVE matters enormously for a service accepting user-uploaded images and not at all for one scoring pre-validated feature vectors. Write the reachability verdicts down; they are your audit response.
- Decide mitigations per finding: input validation in front of the vulnerable path, removing an unused dependency from the image, patching a private fork as a last resort — with the understanding that each private patch adds to a fork you now own.
Step three: shrink the blast radius
Software that can't be patched earns stricter isolation than software that can. None of this is exotic; it's standard zero-trust hygiene applied with more conviction:
- Network segmentation: MXNet serving workloads in their own segment, with only the ingress they need and — more importantly — near-zero egress. A model server rarely needs to talk out; deny it.
- Minimal privilege: read-only filesystems where possible, no credentials in the environment beyond what serving requires, dedicated service accounts scoped to the workload.
- Dedicated runtime environments: keep frozen workloads off shared clusters where their pinned CUDA/driver requirements would otherwise hold back fleet-wide upgrades — the freeze must not spread to healthy infrastructure.
- Boring, complete telemetry: request logging, anomaly alerts on output distributions, and infrastructure monitoring that will notice when a platform change (driver upgrade, hardware move) shifts the model's numerical behavior. Frozen systems fail quietly; instrumentation is how you hear it.
Step four: write the exit plan with dates on it
Containment without an end date is deferred risk with better paperwork. The exit plan is a short document, reviewed on a schedule, that says:
- which models are contained, and why they weren't ported now;
- what has to become true for each to move — budget, staffing, retraining data, a dependency on another project;
- the order they'll move in, and the date each decision gets revisited;
- the conditions that would force the timeline early: a reachable CVE with no mitigation, a hardware refresh the stack can't follow, a failed rebuild.
This document does double duty. Internally it keeps "not yet" from decaying into "never." Externally it's what your auditors and enterprise customers actually want to see when unsupported software shows up in a questionnaire: evidence the component is known, bounded, monitored, and scheduled for removal. "We run a retired framework" is a finding; "we run a retired framework under this documented containment posture, exiting on this schedule" is a managed risk.
The posture, summarized
Containment done well is unglamorous: reproducible builds, a watched dependency tree, tight isolation, real telemetry, and a dated plan. It buys time honestly — months or years of safe operation — without pretending the clock isn't running. And because the contained system is frozen, everything you build around it (the rebuild CI, the parity corpus you'll eventually need for porting, the reachability analysis) stays valid until the day you finally move.
The one thing containment can't do is substitute for the exit. It's the bridge, not the destination — and the teams who treat the exit date as real are the ones who never get to find out what the incident would have looked like.