Parameter Logic Bugs
Null Safety
The concept of null variables dates back to 1965 in computer programming. The inventor of the NULL reference famously referred to it as "The Billion Dollar Mistake", because of the numerous issues it introduced to computer programs throughout the years. Null pointers in C, for example, led to various software vulnerabilities and bugs.
This should give us a basic idea as to why allowing null variables in code is generally considered a bad idea, as they may introduce run-time errors that can break the user experience. Null variables may also introduce flaws that allow users to bypass certain restrictions and access data they should not have access to, not through access control issues, but through logic bugs, as we will see in the coming sections.
Such kinds of vulnerabilities are so common that I personally encountered one while writing this very section, in the Facebook app no less. I noticed that when I accessed a comment by clicking on a notification (which triggers the app to navigate to the URI set by the notification), then whenever I would add a comment, it would fail and ask me to retry. Then, I noticed that it said reply as (null), so it was probably still loading my user details, which made it fail to add the comment, likely to missing identifiers (e.g. userId).

While this is a very minor user-inconvenience logic bug, it shows that such bugs occur even with organizations that have very strict coding and security standards, which is why we should learn about them and take measures to prevent them.
Null Variables
A null variable is a variable with no value assigned to it. It is most often introduced when a variable is declared without an initial value (e.g. var count; instead of var count=0;). This may be useful under specific conditions, like while awaiting the value of a certain variable to be pulled from a remote resource.
This leads developers to declare the variable without an initial value, and then assign it a value once it is retrieved. If the variable is never accessed or used before it is assigned a new value, then the code is considered null-safe. However, if the variable is accessed or passed to a function/method (e.g. count.toString()), then it would lead to a run-time error, known as a null reference error, and crash part/all of the application.
There are numerous situations where the variable may accessed before it is assigned a value. For example, a front-end web application may fail to obtain the value of a variable from a remote resource (e.g. user device not connected to the internet), so it may proceed to render the page without that variable being assigned a value, which would cause a run-time error and crashes the page.
This is why it is important to ensure we know how to write code that is null-safe to prevent null-related run-time errors, some of which may potentially lead to logic bugs that we can take advantage of.
Null Safety
Modern languages that support null safety ensure that null variables are never accessed without having a value, by enforcing certain checks/rules during edit-time or before the code is compiled. Some of the languages that have implemented null safety solutions are:
- TypeScript
- Rust
- C#
- Swift
- Kotlin
- Dart
However, many other languages, like JavaScript, do not yet fully support null safety, so many developers tend to use certain checks to ensure a null variable is not accessed before being assigned a value. For example, a developer may test if the variable is null (e.g. if (count === null) or if !(count)), or may perform type validation tests to ensure that the current value matches the expected type and is not null.
Even with such checks, we cannot fully avoid null reference errors, as there could be unpredicted cases that lead to accessing variables before assigning them a value.
While each language has a slightly different approach that fits its own environment, most languages utilize similar basic concepts to allow null-safe code. Some of these are:
| Concept | Description | Example |
|---|---|---|
| Non-Nullable variables | Variables that must be initialized with a value, and cannot hold null when being used, or the compiler/IDE will throw an error. | let count: number; |
| Nullable variables | Variables that may still hold null as their value "must be used with caution" | let count: number | null; |
?.: Null aware operator (or optional chaining operator) |
Used with nullable variables, and allows to only access the variable objects (e.g. .length) if the nullable variable is not null |
total = list?.length |
??/??=: Null-coalescing operator/assignment |
Used with nullable variable, and allows to set a default value if the nullable variable is null | total = count ?? 0 / count ??= 0 |
!: Non-Null assertion operator |
Used with nullable variables, allows us to bypass the null safety checks, if we are sure that at this point the variable would not be null (i.e. override the IDE's null safety check) | total = list!.length |
Null-safe languages support both nullable and non-nullable variables, while other languages usually support only nullable variables. For this reason, some non-null-safe languages, like JavaScript, started to support some of the above null operators, like ?. or ??, to reduce potential null errors.
This also shows that even though an application may be coded in a null-safe language, it can still produce code that is not null-safe, as it may be overriding some of its null safety checks (e.g. by using !), which may lead to the null safety logic bugs. This is why we should try to avoid overriding these checks as much as possible, and only use null safety overrides when we are 100% sure that the variable will not be null (e.g. with if (count !== null)).
Note: You can refer to this article, which rates each language's null safety, and provides a list of the best/worst languages in terms of null safety.
Identifying Null Bugs
Unlike most logic bugs, null safety issues can be reliably identified through tools, as most languages mentioned above do during edit-time. However, this only identifies potential cases where a variable may be accessed while being null, and does not perform any logic analysis of what would be affected if it does. Also, as mentioned earlier, even null-safe languages that override safety checks (e.g. through ! or turning off null safety altogether), can still have null safety logic bugs. So, for null-safe languages, we would focus on null safety overrides.
So, the process we can follow is to determine potential null variables that are user controllable, and then look into the potential logic bug that can be caused by that. For the first step, we can do the following, depending on the type of null safety:
-
For languages without null safety: Look for
uninitializedvariables or ones that get assigned null afterward. -
For null-safe languages: review uses of
non-null assertion operator (!), and see if it could lead to a null-reference error.
After we identify those, we need to review the null safety checks being done for these variables, like type validation or condition tests if (count !== null). If we can determine a case that may bypass these checks, then we can shortlist this variable for further local testing and code reviews to determine whether it can lead to a potential logic bug.
With this in mind, in the next section we can start by creating a list of all potential null variables, and then proceed with the next steps.
Exercise: By now, you should have a pretty good idea of how to navigate a codebase and understand how it works. So, it is time to test your skills before continuing with the rest of the module. Try to use the above process to identify potential null safety logic bugs in the codebase. You can then compare your findings, as well as the process you followed, with what the upcoming sections will cover, which is an essential step to know what you may have done better.
/ 1 spawns left
Questions
Answer the question(s) below to complete this Section and earn cubes!
Table of Contents
Logic Bugs
Introduction to Logic Bugs Types of Logic Bugs Module Methodology Setting UpValidation Logic Disparity
Validation Logic Disparity Code Review - Validation Logic Disparity Local Testing - Validation Logic Disparity PoC and Patching - Validation Logic DisparityUnexpected Input
Unexpected Input Code Review - Unexpected Input Local Testing (Validation) - Unexpected Input Local Testing (Manipulation) - Unexpected Input PoC and Patching - Unexpected InputNull Safety
Null Safety Code Review (Null Variables) - Null Safety Code Review (Optional Parameters) - Null Safety Local Testing (Schemas) - Null Safety Local Testing (functions) - Null Safety PoC and Patching - Null SafetyAvoiding Parameter Logic Bugs
Avoiding Parameter Logic BugsSkill Assessment
Skill Assessment - Parameter Logic BugsMy Workstation
OFFLINE
/ 1 spawns left