CISA measures memory-unsafe code across critical open source
The June study finds widespread use of memory-unsafe languages and shows how dependency analysis changes the picture. Its counts need to be interpreted as an inventory, with explicit limits on what they establish about deployed software.
A repository's main language cannot describe every memory-management obligation in the software it produces. Dependencies can introduce additional implementations, and repository counts may include code that never reaches a deployed executable. The distinction is central to CISA's 26 June announcement. Its joint study with the FBI and Australian and Canadian partners examines memory-unsafe language use in critical open source projects. The resulting inventory is useful because it also explains where inventory stops being an exposure assessment.
C's role in interoperability is a large part of why I still value it. Many programs written in other languages rely on interfaces expressed in C terms. That makes the implementation behind an interface relevant to a memory-safety assessment, even when the application code does not manipulate raw memory itself.
The measured population has a defined boundary
The study analyzes repositories for 172 projects selected from an OpenSSF critical-project list. It uses cloc to classify source and count lines. Ninety projects, about 52%, contain code in languages the study classifies as memory-unsafe. Such code accounts for 55% of the aggregate lines. The study explicitly describes its language classification as a simplification and does not assess individual code quality.
Those percentages answer different questions. The project count treats a small amount of qualifying code as enough to put a repository in the containing category. The aggregate line count gives larger repositories more influence. Neither percentage is a probability that a selected deployed application contains an exploitable defect. Turning one into such a probability would require evidence the study does not provide.
The denominator is also part of the result. These are selected critical projects, with specific repository choices. They are not a random sample of every open source program. The study discusses selection bias and the limitations of forge-based activity measures. This gives readers a reason to use the findings for investigating their own dependency graph, without claiming that the headline percentage describes every software population.
For a product owner, that distinction is practical. An organization may use only part of a selected repository, or combine several repositories into one delivered component. A repository-level category cannot identify the deployed subset by itself. The next useful question is how the inventory relates to the particular artifact the organization ships.
Lines of source do not identify reachable defects
One of the study's examples is a project with a small C test file. The analysis does not exclude test directories wholesale. Its authors explain that a blanket exclusion could itself be too coarse. This is a sensible limitation to state, because directory naming is not evidence about all the ways code can execute.
The implication is that a source count supplies a location for further inquiry. A test fixture may execute only during development. Build helpers may run while producing a release. A library may become part of an installed process. These roles create different questions about authority and input, even if the files share the same implementation language.
My preference is to preserve those roles when moving from a survey to an engineering decision. Calling every counted line equally exposed would make prioritization less precise. Removing every development file from consideration would also miss the possibility that build-time execution matters. The meaningful boundary depends on which process executes the code and which inputs can reach that process.
This reasoning also explains why finding a memory-unsafe language does not prove the presence of a memory-safety bug. The language classification identifies where developers retain particular obligations. Establishing a defect requires examining whether an execution violates them. A useful inventory supports that examination without presenting its classification as a substitute for it.
Dependencies alter both numerator and denominator
The study performs additional dependency analysis for Ansible, Distribution and Home Assistant. Each gains memory-unsafe code when the selected dependencies are included. The authors limit the analysis to dependencies they can resolve through the chosen mechanisms and exclude operating-system libraries and development requirements. They also describe incomplete visibility into further dependencies behind Python packages.
A subtle consequence follows when percentages are used to compare the two views. Adding dependencies can increase the absolute amount of memory-unsafe code while reducing its percentage of all code. The denominator can grow faster than the numerator. A smaller ratio therefore cannot establish that the product now has fewer memory-management obligations.
That observation matters for reporting a migration. If a project adds a large body of memory-safe code, its unsafe percentage may decline even though its existing unsafe component remains unchanged. Conversely, replacing a small but important parser may barely change the percentage. A volume ratio cannot express the importance of that parser's input or privileges.
The dependency boundary also needs to be reproducible. A report should say which package versions and optional components it counted. Otherwise, two analyses can disagree because they examined different compositions. That is an interpretation problem before it is a disagreement about memory safety. Preserving the scope makes later comparisons meaningful.
The inventory can inform a specific replacement proposal
The earlier memory-safe roadmap guidance asks manufacturers to plan for reducing memory-safety vulnerabilities. June's contribution is to show why those plans need to account for external code. Choosing a memory-safe application language does not settle the implementation choices made by every dependency supplier.
A useful proposal can start with a dependency the inventory identifies and describe its function in the delivered product. It can then explain which inputs reach it and what a replacement must preserve. That creates an assessable unit of work. Replacing an entire repository based only on its language percentage supplies much less information about the expected security benefit.
The same proposal needs to preserve integration requirements. A replacement must communicate with its callers through a defined contract. Ownership of returned objects and the lifetime of borrowed data remain relevant where implementations meet. The inventory identifies where to investigate, while the component design determines which obligations a replacement removes and which remain at that boundary.
For a C-dependent system, the study's useful result is a more precise question about composition. The application language describes one part of the implementation. A deployment assessment needs the selected dependencies and their roles, together with an account of what the source-counting method omitted. Those details let a manufacturer connect a broad roadmap commitment to a particular component it can change.