- COMP.SEC.100
- 16. Software Security
- 16.2 Detection of vulnerabilities
Detection of vulnerabilities¶
The earlier a vulnerability is detected and can be fixed, the more cost-effective it is; however, vulnerabilities must in any case be identified at different stages of software development: design, implementation, and maintenance.
A sound detection technique can infer that a particular vulnerability (or a set of vulnerabilities) is not present in the examined target. An unsound technique does not find all defined vulnerabilities.
A complete detection technique produces findings that are always true vulnerabilities. In other words, it does not produce false positives.
Software bill of materials (SBOM)¶
One key problem has become the dependencies between software components. When a program uses external software, such as a software library, a dependency is formed. For example, if a vulnerability is found in a library used by a program, the program often also contains the same vulnerability.
As a solution, the SBOM (Software Bill of Materials) was developed in the United States, where it is required for systems in critical infrastructure and the defence industry. The EU Cyber Resilience Act (CRA) will require SBOMs for new network-connected software starting from December 2027. In any case, SBOM is already an important means of improving software security.
In an SBOM, metadata is created about the components used by the software, such as software libraries. The metadata includes, for example, information about the libraries used and their versions, release dates, potential vulnerabilities, and licensing information. In practice, this is done using a tool that generates metadata from the program’s source code and stores it in a file. This file is called an SBOM file. Once an SBOM file has been created for a program, the program can be regularly checked—including after modifications—for possible vulnerabilities.
Static analysis (advanced)¶
In static analysis, program code or binary code is examined without executing it. The advantage is that the program does not need to be complete, and the entire codebase can be analysed. Static analysis may also be considered to include code reviews performed by humans. Code reviews have their place because humans can understand the overall behaviour of code better than tools. On the other hand, static analysers are more effective at detecting common, known issues. Static analysis can be divided into heuristic static analysis and sound static analysis.
Heuristic analysis is based on rules aimed at identifying errors in the code. For example, certain insecure coding practices, array over-indexing, or unsafe API calls may be detected. The analyser may also build a model of the program and its data flows in order to identify broader issues beyond individual errors.
Where heuristic analysis aims to identify known errors or their variations, sound analysis aims to prove that such errors do not exist. In sound analysis, formal methods are used to demonstrate the safety of code in certain respects, such as correct memory handling. The idea of sound analysis is that if a known type of error exists in the program, it will be found. In practice, however, compromises must be made, and not all errors can be detected.
Static analysis therefore does not find all errors. It may also produce many false positives, which can make the use of the tool laborious and error-prone. Much depends on the program and how it is used. Static analysers are naturally tied to specific programming languages. Nevertheless, static analysers are an extremely important tool in secure software development. For example, a company may require that a program must pass selected static analysis tools without serious issues.
Dynamic analysis (advanced)¶
In dynamic detection, observation is performed during program execution. Dynamic detection can prevent problems caused by vulnerabilities even while the program is running. However, this comes at the cost of reduced performance.
Monitoring (advanced)¶
Monitoring involves tracking program execution during runtime. In principle, monitoring could completely prevent vulnerabilities. In practice, however, this would result in such a significant reduction in performance and increase in memory usage that compromises must be made.
Modern C/C++ compilers include options to add monitoring during compilation, allowing the program to automatically detect and prevent runtime memory management errors.
In input monitoring, the challenge is that input and output are often undefined for the monitoring program from a security perspective.
Monitoring race conditions is difficult, but in some cases it is possible to monitor shared memory and verify that access rights do not conflict.
One important way to find vulnerabilities is to identify execution paths and suitable inputs. Fuzz testing helps with this by automatically generating a very large number of test inputs. Among the program’s inputs, there will be a large amount of faulty and unpredictable data. The testing tool also documents abnormal program behaviour, making it possible to trace errors.
Fuzz testing can be divided into black-box and white-box testing:
In black-box testing, source code is not used, so testing is not based on knowledge of the program’s structure. Black-box testing can be divided into three approaches:
- Truly random
- Random within a defined value range (also referred to as parameterisation)
- Mutation-based, where an initial input is provided and the testing tool begins to modify it, producing mutations
In white-box testing, the source code helps the testing tool identify input domains and program branching. This allows the tool to find more suitable test data than black-box testing, covering potential faulty inputs more effectively. This is often referred to as “coverage based fuzzing”.