# Static linking: pitfalls, harms and challenges

Bastien Roucariès

► To cite this version:

Bastien Roucariès. Static linking: pitfalls, harms and challenges. DebConf25, IRISA, Jul 2025, Brest, France. pp.10. hal-05334923

HAL Id: hal-05334923

https://hal.science/hal-05334923v1

Submitted on 28 Oct 2025

HAL is a multi-disciplinary open access
archive for the deposit and dissemination of sci-
entific research documents, whether they are pub-
lished or not. The documents may come from
teaching and research institutions in France or
abroad, or from public or private research centers.

L'archive ouverte pluridisciplinaire HAL, est
destinée au dépôt et à la diffusion de documents
scientifiques de niveau recherche, publiés ou non,
émanant des établissements d'enseignement et de
recherche français ou étrangers, des laboratoires
publics ou privés.

<figure><img src="image_1.png" /></figure>
Static linking: pitfalls, harms and challenges

Bastien Roucariès

SATIE Laboratory, CY Cergy Paris University CNRS, Paris-Saclay University, Cergy, France

bastien.roucaries@ens-paris-saclay.fr

Abstract—A static library or a statically linked library contains functions and data that can be included in a computer program at build-time such that the library does not need to be accessible in a separate file at run-time. Static linking is an old concept that, during the 2000s, was considered a legacy approach and was gradually phased out in favor of dynamic libraries.

Dynamic libraries offer significant advantages in code reusability, security, and memory efficiency. In contrast, static libraries provide potential speed optimization by reducing dead code and enabling seamless code integration without relying on API or ABI stability, including the application of custom patches to upstream code.

In the 2010s, this seamless code integration became known by various terms, such as vendorizing (Go terminology), packing, bundling, browserifying (JavaScript terminology), and uber-jar (Java terminology). At its essence, it represents a form of static linking, even within interpreted languages.

The widespread use of static linking presents significant challenges for release managers and security managers. While some workarounds, such as Static-Built-Using package metadata, binNMU, or mass rebuilds, exist, they are often insufficient or overly cumbersome in practice.

Moreover, following a Thompson-like argument, a Reflections on Static Trusting Trust approach should be undertaken from a security perspective to ensure the removal of insecure code. Practical assistance could be obtained from reproducible builds, though these lack theoretical guarantees.

Introducing new concepts, such as Transiently Stable Dynamic Linking and leaf static linking, could help alleviate certain challenges and contribute to improving the current status quo. Index Terms—Linkers, Software maintenance

# I. Introduction

Dynamic linking of object files was introduced to reduce code complexity and optimize the memory footprint of executables. By enabling shared library usage at runtime, this approach minimizes redundant code across multiple programs, enhances modularity, and improves resource efficiency in large-scale software systems [1].

Because dynamic libraries facilitate code sharing, they play a crucial role in security by enabling a single patch to propagate across all dependent applications. This mechanism ensures that newly launched programs automatically integrate the fixed code, minimizing exposure to vulnerabilities, maintaining system-wide consistency in protection, and significantly reducing the window of exploitability.

Some authors express concerns about patching dynamically linked libraries due to the risk of ABI incompatibility, which can lead to regressions in dependent applications. However, in practice, this risk is well understood and can

be effectively mitigated using tools like ABI Compliance Checker [2], which analyze binary compatibility and help ensure smooth integration of updates without breaking existing functionality. Additionally, robust automated test suites can pinpoint security patch regressions [3], ensuring that functionality remains intact while vulnerabilities are efficiently remediated.

In contrast, static linking introduces the clone attack [4] problem, where identical copies of vulnerable code are embedded across multiple executables. This approach necessitates extensive tracking of code duplication and individual patching or recompiling of each affected binary, significantly increasing the complexity and overhead of security updates. As a result, ensuring timely remediation across all instances of the code becomes challenging, leaving systems more susceptible to prolonged exposure to vulnerabilities.

Although dynamic linking offers significant benefits, static linking remains widespread in software development due to a mix of technical and practical considerations. Perceived performance gains, simplified deployment, and compatibility concerns are often cited as justifications for its continued use. Additionally, poor dependency management and lack of developer diligence can reinforce its persistence, as maintaining dynamically linked environments requires meticulous coordination to ensure seamless and reliable integration of updates. This study is structured into three key parts. First, it examines the current industrial practices of static linking, analyzing its continued adoption, typical applications, and associated trade-offs. Next, it explores security tools designed to help track code duplication, identify vulnerabilities, and streamline patch management, ensuring better oversight in static linking environments. Finally, the study discusses strategies for improvement.

# II. Taxonomy of static linking

The Debian Security Team maintains a database of cloned and statically linked code in the embedded-code-copies file on the security tracker, along with documented reasons for limited support as outlined in the debian-security-support package. Several distinct cases can be inferred from the team's findings.

## A. Dynamic linking unavailable

The C language serves as the reference implementation for dynamic linking, offering near-perfect support due
to portable assembler nature and direct interaction with
system libraries. However, many other languages either
lack native support for dynamic linking or provide only
partial compatibility, often constrained by architectural
limitations or restricted functionality.

Languages with limited dynamic linking support, ranked
according to GitHub index, include Go, Rust, Haskell and
FreePascal.

The absence of dynamic linking limits the scope of
security support on the Debian side, as documented in
release notes [5, §5.2.2.2.], with all golang packages being
particularly affected.

B. Vendorin

Vendororing is the practice of embedding third-party
dependencies directly into a project's source code, rather
than relying on external package managers or dynamic
linking. The perceived advantages of vendororing include
keeping dependencies self-contained and ensuring they
remain unaffected by upstream changes. Vendororing is also
referred to as bundling, Uber-Jar (in Java terminology),
or encapsulation. Vendororing is wide spread in go language
ecosystem [6]. Vendororing may also encompass a simplified
approach, where code is directly copied and pasted [7]
(cloned) rather than properly integrated or managed
through structured dependency mechanisms. Vendororing
can be utilized upstream to bypass ABI incompatibilities,
providing a temporary solution to mitigate binary interface
issues, such as those observed in CVE-2025-47153.

Node.js is a well-known example of a package that
employs vendorizing.

C. Browserifing, webpackin

Browserifying and webpacking refer to techniques used
in modern web development to manage and optimize
JavaScript dependencies for browser execution. Due to
the absence of a native filesystem in browsers, JavaScript
code must be consolidated into a single executable unit
and transpiled to ensure compatibility with the browser
environment [8]. Note that Browserify-generated code can
be derived from languages such as C or C++, leveraging
LLVM's Emscripten target, which facilitates compilation
of supported LLVM source languages into JavaScript [9]
or WASM.

Notably, all libjs packages are among the well-known
packages affected.

D. Inlining

Inlining refers to the practice of substituting a function
or operation directly within the calling code, rather than
invoking it through a separate function call, with the goal
of reducing execution overhead and improving performance.
Inline functions, especially those defined in headers, can
be susceptible to vulnerabilities such as CVE-2020-27767.
Tracing inlining in binaries remains an active area of
research program [10].

A notable example of inlining is found in Boost's header-
only template libraries, where functionality is provided
entirely through headers, leading to widespread code
duplication at compile time.

III. Security Strategies for Statically Linked Code

Static linking has been acknowledged as a challenge by
the Debian project, prompting the adoption of several
actionable strategies to mitigate its impact.

A. Automated Analysis of Static Linking Dependencies

Package manager can be utilized during build time to
construct a dependency tree of statically linked binaries,
ensuring proper tracking and management of embedded
dependencies. This approach represents Debian's current
strategy, leveraging the Static-Built-Using: package meta-
data to ensure this traceability.

B. BinNMU

Under certain conditions, such as library transitions,
binary packages can be rebuilt without modifying their
source packages. This process is essential to correct
builds performed in flawed environments (e.g., a faulty
compiler), verify that a package remains compatible
with an updated dependency, or explicitly trigger a
rebuild against a new shared library when the previous
binary is incompatible. To facilitate this, maintainers can
request a binNMU (binary Non-Maintainer Upload), an
established yet somewhat misleading term for initiating
such rebuilds. This mechanism can be leveraged to address
security vulnerabilities in statically linked packages. This
mechanism should be applied incrementally (mass rebuild),
processing dependencies in batches at each depth level of
the dependency graph to ensure a structured and efficient
rebuild. However, arch:all packages currently cannot utilize
this approach, meaning interpreted languages such as
JavaScript require a full package upload by the maintainer,
which is a more time-consuming process. Additionally,
manual intervention is required when dependency loops
occur, ensuring that the rebuild process successfully
eliminates insecure code. In such cases, Build-profiles can
be utilized to tailor the compilation process, selectively
adjusting dependencies [11].

C. Static checker

Static checkers can be employed to detect embedded
code, aiding in security and compliance verification. Under
Debian, Lintian [12] performs various checks, including the
detection of JavaScript snippets, ensuring proper packaging
practices, and recommending de-embedding when necessary.
If necessary, this process could be complemented by a
systematic checker such as Mantilla [13].
## D. Reproducible Builds

Since static snippets are not confined within a discrete code unit (such as a library), any vulnerable binary code may propagate throughout the entire executable. This issue is especially relevant for self-hosted compilers that are statically linked, such as Golang. In such cases, reproducible builds [14] can help eliminate static code snippets, ensuring security and consistency. However, achieving a stable and reproducible binary requires iterative recompilation until deterministic output is consistently obtained. This issue aligns with the concerns raised in Ken Thompson's Reflections on Trusting Trust, vulnerabilities in statically linked, self-hosted compilers like Golang can propagate insecure code throughout binaries, thereby creating a trust issue. It is important to note that reproducible builds provide only a practical guarantee. As discussed in the section on inline code, detecting statically embedded code within binaries remains an open challenge.

# IV. Potential Enhancements

While current strategies signify progress beyond a laissez-faire approach, they fall short of fully addressing the challenges at hand, thereby necessitating further targeted enhancements.

## A. Tracking Static Code via Debug Symbols

Debug symbol packages are automatically generated for select programming languages, providing essential metadata for code analysis. Debian, by default, includes a debug symbol repository, providing easy access to debug information for packaged binaries<fnref n="1" />. The DWARF debug format enables precise tracking of statically embedded code copies, facilitating deeper inspection of binaries for security and compliance purposes. Static code can sometimes be optimized away during compilation, making direct identification challenging. However, certain proof-of-concept implementations applied to the BSD kernel appear to yield valuable insights [15].

## B. binNMU of architecture independent packages

The boundary between binary and architecture independent packages has become increasingly blurred due to the rise of compiled or transpiled languages in arch:all packages (such as Java or JavaScript). As a result, performing a binNMU on arch:all packages can significantly aid in security-related rebuilds.

## C. Identifying Related Issues via Security Tracker

Debian's Security Tracker is an internal Git repository dedicated to monitoring and documenting security vulnerabilities. Upstream patches are referenced via specific URL pointers using dedicated annotations, ensuring a systematic approach to tracking and managing issues. Debian CodeSearch [16] is a high-performance regular

expression search engine that leverages RE2 syntax to perform efficient pattern matching across a 130 GiB source archive, delivering results in sub-second query times. Leveraging patch references to automate fuzzy searches or integrate AI-driven analysis within Debian CodeSearch could significantly enhance vulnerability detection. This method would improve static code copy detection, optimize search accuracy, and reduce manual overhead, making large-scale security assessments more efficient. Recent advances appear to support the feasibility of this approach [17], [18].

## D. Transiently Stable Dynamic Linking ABI

Certain languages, such as Go, deem dynamic linking unsuitable for production environments due to the absence of a stable internal ABI, which prevents reliable compatibility across versions and dependencies. However, from a security management perspective, an ABI should maintain stability only throughout the release cycle and across successive applied patches, thus requiring only a Transiently Stable ABI and not a strong stable ABI. In this case, from a release manager's perspective, a binNMU of dependencies (using a field like Static-Build-Using) should be performed whenever the upstream version of the package changes, ensuring consistency and compatibility. However, when the Debian version of a package is updated, the maintainer should rebuild only that specific package, maintaining stability while minimizing unnecessary recompilations. The need for mass rebuilds could also be significantly reduced by employing an ABI checker (ideally on binary or DWARF symbols) as a decision-support tool.

## E. Leaf static linking

Some languages, such as JavaScript, require static linking to bundle dependencies and ensure predictable execution environments. However, these bundles are linked and transpiled from libraries that support dynamic loading, notably through import statements in JavaScript, used mainly for Node.js context. In Debian terminology, only libjs packages require static linking, whereas nodejs packages should use dynamic linking<fnref n="2" />. This leaf static linking strategy parallels Link-Time Optimization (LTO) in binaries, but rather than focusing on performance optimization, it aims to enhance the maintainability of bundled binaries. By applying this strategy, only the leaf packages — those at the terminal points of the dependency graph — and the packages directly impacted by the vulnerability require rebuilding, thereby reducing the overall security maintenance burden.

# V. Conclusion

Static linking imposes a notable burden on both security teams and release managers, yet remains unavoidable in various distribution scenarios.

In this paper, we present a taxonomy of static linking within the context of software distributions and propose

<footnote n="1">¹If the programming language is capable of producing debug symbols like C, C++, Rust and Go.</footnote>

<footnote n="2">²This practice does not align with industry standards, as rpm packages are often statically linked.</footnote>
a set of actionable measures aimed at mitigating its
operational impact, particularly in the case of Go, Rust,
and JavaScript packages that currently receive limited
support, despite users' expectations of full support.

References

[1] J. Q. Arnold, "Shared libraries on UNIX™ system V," in 1986 Summer Technical Conference & Exhibition, Conference Proceedings, (Atlanta, GA, USA, Jun. 9-13, 1986), M. O'Dell, Ed., USENIX Association, El Cerrito, CA, USA: USENIX Association, 1986, ch. Operating Systems 2, pp. 395-404. Accessed: Jun. 14, 2025. [Online]. Available: https://archive.org/details/1986-proceedings-summer-tech-atlanta

[2] A. Ponomarenko and V. Rubanov, “Automatic backward compatibility analysis of software component binary interfaces,” in 2011 IEEE International Conference on Computer Science and Automation Engineering, CSAE 2011, (Shanghai, China, Jun. 10–12, 2011), S. Li and Y. Dai, Eds., vol. 3, Beijing, China: Institute of Electrical and Electronics Engineers. Beijing Section, 2011, pp. 167–173, doi: 978-1-4244-8727-1. [doi: 10.1109/CSAE.2011.5952657]

[3] C. Artho, K. Suzaki, R. Di Cosmo, R. Treinen, and S. Zacchiroli, “Why do software packages conflict?” In 2012 9th IEEE Working Conference on Mining Software Repositories (MSR), Proceedings, (Zurich, Switzerland, Jun. 2–3, 2012), M. Lanza, M. Di Penta, and E. Shihab, Eds., Passau, Germany: Conference Publishing Solutions, 2012, pp. 141–150, doi: 978-1-4673-1761-0. [doi: 10.1109/MSR.2012.6224274]

[4] A. Nappa, R. Johnson, L. Bilge, J. Caballero, and T. Dumitras, “The attack of the clones: A study of the impact of shared code on vulnerability patching,” in 2015 IEEE Symposium on Security and Privacy SP 2015, Proceedings, (San Jose, CA, USA, May 18–20, 2015), S. Peisert, Ed., IEEE Computer Society, Los Alamitos, CA, USA: IEEE Computer Society Conference Publishing Services (CPS), 2015, pp. 692–708, doi: 978-1-4673-6949-7. [doi: 10.1109/SP.2015.48]

[5] The Debian Documentation Project, Ed. “Release notes for debian 13 (trixie),” Accessed: Jun. 30, 2025. [Online]. Available: https://www.debian.org/releases/trixie/release-notes/index.en.html

[6] K. Hightower, “What’s new in go 1.6 — vendorings,” ;LOGIN:, The USENIX Magazine, vol. 41, no. 2, Summer 2016, [doi: 10.1109/MS.2021.3073045]

[7] C. Ragkhitwetsagul, J. Krinke, M. Paixao, G. Bianco, and R. Oliveto, “Toxic code snippets on stack overflow,” IEEE Transactions on Software Engineering, vol. 47, no. 3, pp. 560–581, Mar. 2021, [doi: 10.1109/TSE.2019.2900307]

[8] J. Rack and C.-A. Staicu, “Jack-in-the-box: An empirical study of javascript bundling on the web and its security implications,” in Proceedings of the 2023 ACM SIGSAC Conference on Computer and

Communications Security, (Copenhagen, Denmark,
Nov. 26–30, 2023), W. Meng and C. D. Jensen,
Eds., ACM Special Interest Group on Security, Audit
and Control, New York, NY, USA: Association for
Computing Machinery, 2023, pp. 3198–3212, [doi:
979-8-4007-0050-7. doi: 10.1145/3576915.3623140]

[9] A. Zakai, “Emscripten: An LLVM-to-JavaScript compiler,” in Proceedings of the ACM International Conference Companion on Object Oriented Programming Systems Languages and Applications Companion, (Portland, Oregon, USA, Oct. 22–27, 2011), New York, NY, USA: Association for Computing Machinery, 2011, pp. 301–312, [doi: 978-1-4503-0942-4. doi: 10.1145/2048147.2048224]

[10] L. Binosi, M. Polino, M. Carminati, and S. Zanero, “BINO: Automatic recognition of inline binary functions from template classes,” Computers & Security, vol. 132, p. 103 312, Jun. 2023, [doi: 10.1016/j.cose.2023.103312]

[11] P. Abate and J. Schauer, “Bootstrapping software distributions,” in Proceedings of the 16th International ACM Sigsoft Symposium on Component-Based Software Engineering, Federated Events on Component-Based Software Engineering and Software Architecture, (Vancouver, British Columbia, Canada, Jun. 17–21, 2013), P. Kruchten, Ed., ACM SIGSOFT, New York, NY, USA: Association for Computing Machinery, 2013, pp. 131–142, [doi: 978-1-4503-2122-8. doi: 10.1145/2465449.2465461]

[12] M. F. Krafft, K.-J. Stol, and B. Fitzgerald, “How do free/open source developers pick their tools? a delphi study of the debian project,” in ICSE’16, Proceedings of the 38th International Conference on Software Engineering Companion, (Austin, TX, USA, May 16–22, 2016), ACM SIGSOFT, New York, NY, USA: Association for Computing Machinery, 2016, pp. 232–241, [doi: 978-1-4503-4205-6. doi: 10.1145/2889160.2889248]

[13] J. Carrillo-Mondéjar and R. J. Rodríguez, “Identifying runtime libraries in statically linked linux binaries,” Future Generation Computer Systems, vol. 164, p. 107 602, Mar. 2025, [doi: 10.1016/j.future.2024.107602]

[14] C. Lamb and S. Zacchiroli, “Reproducible builds: Increasing the integrity of software supply chains,” IEEE Software, vol. 39, no. 2, pp. 62–70, 2022. [doi: 10.1109/MS.2021.3073045]

[15] C. Margiolis. “Using dwarf to find call sites of
inline functions,” Accessed: Jun. 18, 2025. [Online].
Available: https://margiolis.net/w/dwarf在线/

[16] M. Stapelberg, “Debian code search,” Bachelor The-
sis, Fakultät für Informatik, Hochschule Mannheim,
Mannheim, Germany, Dec. 9, 2012. Accessed: Jun. 18,
2025. [Online]. Available: https://michael.stapelberg.
ch/dcs/bsc-thesis.pdf
[17] K. Kim et al., “FaCoY: A code-to-code search engine,” in Proceedings of the 40th International Conference on Software Engineering, (Gothenburg, Sweden, May 27–Jun. 3, 2018), M. Chaudron, Ed., SIGSOFT, New York, NY, USA: Association for Computing Machinery, 2018, pp. 946–957, doi: 978-1-4503-5638-1. doi: 10.1145/3180155.3180187

[18] K. Kim et al., “Big code search: A bibliography,” ACM Computing Surveys, vol. 56, no. 1, pp. 1–49, Jan. 2024, Art. no. 25, ISSN: 0360-0300. doi: 10.1145/3604905