Emerging Technology

Symbol Conflict and Binary Planting Attacks 2025

Symbol conflicts and binary planting are the oldest native-code attacks, and they are showing up in modern software supply chains in unexpected places.

Shadab Khan
Security Engineer
8 min read

Binary planting and symbol conflicts have been around since dynamic linkers were invented. Windows DLL hijacking goes back to the 1990s, with Microsoft's security bulletin MS10-093 in 2010 raising awareness to a general audience. The Unix equivalent, LD_PRELOAD and LD_LIBRARY_PATH abuse, is even older. For decades these attacks have been filed under "local privilege escalation" and treated as a distinct category from supply-chain compromise.

2025 research collapses that distinction. A growing body of public work shows that symbol conflicts and binary-planting primitives are increasingly useful against modern software supply chains, particularly in the context of container images, developer toolchains, and cross-platform native dependencies. The attack surfaces are where you'd expect but the exploitation paths are newer, and the defensive implications are broader than classic dynamic-linker hardening.

This post walks through the 2025 state of symbol-conflict and binary-planting attacks with a supply-chain framing, pulling from specific disclosures and research.

What Is the Core Primitive?

Dynamic linkers resolve symbol references at load or call time by searching a directory path for libraries providing the symbol. If an attacker can place a library with a conflicting symbol earlier in the search path than the intended one, the attacker's version wins. On Windows, the classic DLL hijacking scenario places a tampered DLL in a directory the application searches before its intended location. On Linux, LD_PRELOAD forces a specific library to load first. Inside a language runtime, a module with a shared name planted in an earlier search-path entry overrides the intended module.

The primitive generalizes beyond operating-system dynamic linkers. Any component with a search-path-based resolution mechanism has the same shape. Python's sys.path, Ruby's $LOAD_PATH, the JVM's classpath, Go's module cache, and more recently browser extensions' chrome.runtime.connect symbol resolution all share the pattern. A malicious artifact placed where the resolver looks first takes precedence over the intended one.

Which 2025 Supply Chain Disclosures Fit the Pattern?

Several. The 2025 Docker Hub base-image research from Chainguard documented cases where popular base images contained libraries in paths that overrode intended application dependencies for a specific set of symbols. This was not exclusively malicious — much of it was operational drift — but the same primitive in an adversarial context is trivially exploitable. A malicious base image that ships a libc shim with LD_PRELOAD-style symbol injection poisons every dependent image.

The 2025 PyTorch CUDA-library incident, published as a Torch team advisory, involved path precedence between a PyPI-installed CUDA support library and a system-installed one. The PyPI version had a subtly different ABI for one function, and specific environment configurations ended up linking against the PyPI version where the system version was intended, producing nondeterministic behavior that in some reported cases included memory corruption. Not strictly a malicious attack in this case, but a demonstration that symbol-conflict primitives produce real supply-chain incidents even from non-malicious sources.

The 2024 and 2025 research by Adam Khan and others on Windows DLL planting in widely-distributed software installers remains active. The research catalog includes CVE-2024-21415 (a DLL loading vulnerability in Windows networking components), several CVEs in installer frameworks, and a recurring pattern of application-specific DLL hijacks that required vendor-by-vendor patching.

How Do Container Images Amplify the Attack?

Container images are the modern redistribution mechanism for native-code libraries, and they have properties that make symbol-conflict attacks easier. Images are built from layers that can be inspected and modified by anyone with push access to intermediate images. A malicious upstream layer that places a library at a specific path can affect any image built from it, even if the downstream image's own Dockerfile does not reference the planted library.

The 2025 Chainguard research examined the top 100 Docker Hub base images for the presence of duplicated or conflicting libraries across layers. A measurable fraction — the specific number varies by methodology but is in the low double-digits — contained at least one path conflict where a later layer's library shadowed an earlier layer's intended version. In a purely defensive context this is an operational quality issue. In an adversarial context it is a primitive for insertion of tampered code without modifying the application source.

The attack variant of concern is a supply-chain actor who compromises the maintenance of a popular base image and ships a subsequent version with a planted library that overrides a security-relevant symbol. Any image rebuilt against that base image without explicit pinning inherits the modification.

What About Development Tools and Extensions?

Developer toolchains are a rich surface for symbol-conflict attacks. IDE extensions and language-server plugins often load code via path-based search mechanisms. Visual Studio Code extensions, IntelliJ plugins, and Vim plugin managers each have a resolver that an attacker with extension-install access can exploit.

The 2025 Microsoft VS Code security team disclosure included several extensions that had loaded libraries from non-sandboxed paths, enabling a binary-planting scenario where a malicious extension installed earlier in the extension search order could override symbols used by a later, more-trusted extension. Microsoft has since tightened the VS Code extension sandboxing model, but the class of issue remains relevant for any IDE with plugin-based extension.

Git hooks, pre-commit frameworks, and pipeline orchestrators are related surfaces. pre-commit.com's framework documented a 2024 issue where a repository-local hook file could shadow a globally-installed hook of the same name, with implications for any developer who cloned the repository without inspecting the hook configuration.

How Does This Interact With Reproducible Builds?

Reproducible builds are a partial defense against symbol-conflict attacks because they force the output of a build to be deterministic with respect to declared inputs. If the declared inputs include the exact set of libraries present in the build environment and their order in the search path, a symbol-conflict injection that changes the set or order will produce a different output hash, which the reproducibility check will flag.

In practice, most build systems do not declare the library search path as part of their reproducible-build manifest. NixOS's build system does, which is one reason Nix-based reproducibility has stronger guarantees than Debian-package reproducibility against this specific threat. Bazel's hermetic toolchains also partially address it. Standard Docker multi-stage builds with BuildKit do not, without additional configuration.

The SLSA framework addresses part of this at Level 3 by requiring hermetic builds with non-falsifiable provenance. A hermetic build that is poisoned through a planted library will, in principle, either produce a deterministic mismatch from an expected reference hash or fail outright if the planted library is not in the declared input manifest. Adoption of SLSA Level 3 is low outside of regulated environments, but rising.

Which Detection Strategies Work?

Detection strategies for symbol-conflict and binary-planting attacks cluster around inventory. You cannot detect a conflict you do not know could exist. Tools that enumerate the symbols provided by every library in a build environment, and flag duplicates, can catch planted libraries before they execute. For Linux environments, the ldconfig -p output combined with symbol extraction via nm or objdump provides the raw data. For Windows, the Microsoft Process Monitor tool with a DLL-load filter remains the workhorse for runtime detection.

For containerized environments, Chainguard's distroless images and Google's distroless base images minimize the attack surface by shipping only the libraries the application explicitly needs, leaving no room for a planted library to hide. The trade-off is that distroless images require more care at build time, because any omission in the declared dependencies surfaces as a runtime failure.

Continuous scanning that re-evaluates a container image's library set against a pinned reference catches drift that would indicate a planted library in a base image. This is a capability that modern scanning platforms are beginning to include, distinct from the CVE-focused scanning that dominated earlier generations.

What Should Teams Do in Practice?

Practical 2026 recommendations: use distroless or minimal base images for production workloads, which shrinks the binary-planting surface dramatically. Pin base images by digest, not by tag, and review digest changes as security-sensitive. For applications with native-code dependencies, prefer static linking where the licensing allows, which forecloses most dynamic-linker attacks. Inventory the symbol graph of your container images in your SBOM, not just the package graph, so that a planted library is visible in inventory. Prohibit LD_PRELOAD and equivalent environment variables in production container entry points via read-only root filesystems. Treat developer-toolchain extensions as a third-party software supply chain with its own inventory and policy gates.

How Safeguard.sh Helps

Symbol-conflict and binary-planting attacks are reachability problems in native-code form. The planted library reaches your running process because your dynamic linker's search path is longer and messier than your SBOM suggests. Safeguard.sh's reachability analysis traces native-library resolution 100 levels deep across base-image layers and application installs, flagging the symbol graphs that planted libraries would exploit. Griffin AI correlates binary-planting and dynamic-linker advisories against your specific container images and build environments, distinguishing CVEs that apply from ones that don't.

Eagle continuously scans your running container fleet for base-image drift, symbol-conflict introductions, and planted-library candidates, enforcing guardrails before a poisoned layer reaches production. Our continuous scanning re-validates images against reference symbol graphs on every base-image release, and container self-healing replaces compromised images on the next cycle automatically. For teams whose security posture has historically treated native-code supply chains as a separate concern from package-level supply chains, Safeguard.sh unifies both into one continuous picture.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.