Why Analyse Your Code?
Security is paramount in RegTech and FinTech projects. Even when designed with security in mind, software solutions become vulnerable and less secure over time. For example, problems may arise in used libraries and frameworks, protocols, trusted server software, or operating systems. Because modern solutions are an intricate mesh of various components, defects or loopholes in one element can make the entire ecosystem vulnerable.
Common Security Vulnerabilities
Let’s use one of our recent projects as an example. When merging two products handling tax clearance for a client, our team took proactive steps to ensure security. Our engineers initiated a nightly vulnerability scanning procedure using a Veracode Source Code Analyzer. It assesses the source code and generates a report categorising all findings as Very High, High, Medium, Low, or Very Low severity flaws.
Initial analysis of the legacy codebase revealed the following vulnerabilities in the project:
1. Credential Management
Flaws in credential management make user accounts vulnerable to attacks. These vulnerabilities typically manifest in two main vectors:
Credential stuffing:
Attackers make an automated brute-force attempt to “pick up” a pair of usernames and passwords, breaking the actual credential management mechanisms. This type of attack relies on “leaked” data — exploiting lists of commonly used and leaked passwords.
Weak Credential Management:
Attackers exploit vulnerabilities in how credentials are encoded, stored, transferred, or managed.
In our case, the problem stemmed from how passwords and usernames were handled in the staging environment’s unit tests. Some passwords and usernames were stored in variables; in some instances, the usernames and passwords were used as parameters in the UI components, which is not considered a secure practice. We solved these issues by replacing all passwords and usernames with environment variables in the Webpack configuration. Here’s an example of the update:
// Before:
const USERNAME = “test_user”;
const PASSWORD = “password123”;
…
login(USERNAME, PASSWORD);
// After:
const USERNAME = process.env.USERNAME;
const PASSWORD = process.env.PASSWORD;
…
login(USERNAME, PASSWORD);
This solution ensures that sensitive credentials are not hard-coded or directly used in the UI components. Instead, they are being securely managed through environment variables.
It is also important to remember that unit tests should not be deployed onto the production environment under any circumstances!
2. SQL Injection
SQL injection, as illustrated in the classic “Little Bobby Tables” comic, occurs when oversights in the code allow attackers to inject SQL statements, thus gaining unauthorised access to the database. This is one of the most common types of attack, and it causes countless businesses and organisations around the world significant misery.
We encountered an SQL injection vulnerability in the application, specifically in a function that used parameters to build an SQL query. To address this issue, we implemented a function to construct the query parameters safely.
Here’s an example of the initial code:
OrderBy($” {filter.OrderColumn} {filter.OrderBy} \n”)
To resolve this vulnerability, we implemented a function that safely constructs the order parameters:
Func<InvoiceViewModel, object> orderFunc = order => {
var propertyInfo = order.GetType().GetProperty(filter.OrderColumn);
if (propertyInfo != null) {
return propertyInfo.GetValue(order);
} else {
throw new ArgumentException(“Invalid property name.”, nameof(filter.OrderColumn));
}
};
One preventive measure for this vulnerability is so-called input sanitising and whitelisting. However, static code analysers may not always detect whether proper sanitising measures have been implemented. They rely on the code’s text analysis (structure and semantics) without executing the application, which can lead to “false positive” detections.
====
Input Sanitising: Removing or encoding potentially dangerous characters and validating formats to ensure inputs are safe for processing.
Whitelisting: Specifying and allowing only pre-approved and known safe inputs, activities, or operations while blocking all others.
====
3. CRLF Injection
Similarly, attackers can inject Carriage Return (CR) and Line Feed (LF) special character elements into an HTTP stream. This breaks the HTTP response, allowing attackers to modify the application’s data or trigger the application to perform unexpected actions.
In our case, the issue was hiding in a response-generating function that constructed HTTP headers by directly concatenating strings. Here’s an example:
string httpResponse = $”HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {contentLength}\r\n\r\n{responseBody}”;
An attacker could exploit this by injecting a CR or LF into the responseBody, causing the server to misinterpret the structure of the response. For example, the responseBody could contain
“\r\nSet-Cookie: sessionId=attackerSession; Path=/\r\n”, which inserts a malicious HTTP header.
To fix this, we implemented a safer method for constructing HTTP responses, which checks and sanitises the response body for special characters.
4. Cryptographic Issues
Using weak hashing algorithms is another significant security risk, as highlighted in the OWASP Top Ten list. Outdated hashing algorithms such as MD5 and SHA1 compromise the integrity and security principles that hashing provides, as they are susceptible to collisions and other attacks. To address the issue:
- We replaced the vulnerable SHA1 algorithm with the more secure SHA256, which offers stronger resistance to collisions and attacks due to its larger output size and higher computational complexity.
- We reviewed our key management practices, ensuring keys are securely stored and rotated periodically to prevent unauthorised access and strengthen overall encryption integrity.
5. Directory Traversal
Directory (or path) traversal is another type of HTTP attack that allows attackers to access restricted directories and execute commands on the server, typically outside the web server’s root directory. This vulnerability can hide at many levels — from application plugins and source code to the web server.
In our case, we discovered the vulnerability in a file download function, which took a relative file path as input from the user’s request. Here’s how it initially worked:
public void DownloadFile(string relativePath) {
string fullPath = Server.MapPath($”~/files/{relativePath}”);
byte[] fileData = File.ReadAllBytes(fullPath);
Response.ContentType = “application/octet-stream”;
Response.AddHeader(“Content-Disposition”, $”attachment; filename={Path.GetFileName(fullPath)}”);
Response.BinaryWrite(fileData);
}
This implementation allows attackers to input directory traversal sequences like ../ to navigate outside the intended directory and access sensitive files on the server.
To fix this vulnerability, we implemented a strict path sanitisation mechanism. It scrutinises input containing directory traversal patterns like ../ and rejects it before processing the request. Additionally, we limited file downloads to a specific set of permitted directories, adding another layer of protection against traversal attacks.
6. Insufficient Input Validation
Insufficient input validation is a vulnerability that arises when user inputs or input parameters are not validated correctly in the application’s code. Attackers can exploit this weakness to inject malicious data, execute unauthorised commands, or gain unintended access to the application’s resources. Input validation issues can lead to various types of attacks, such as SQL injection and cross-site scripting (XSS).
In our case, the vulnerability arose from not properly validating input parameters or user inputs in our code. We implemented a solution by adding a Bind attribute to all controllers in our application:
[Bind(Include = “BaseUrl”)]
It restricts the allowed inputs to a specified set of properties, preventing unexpected or malicious inputs from being processed.
7. Vulnerabilities in Third-Party Libraries
Applications usually utilise numerous third-party libraries, making it important to scan those libraries for vulnerabilities regularly. Thankfully, modern code analysers can detect such issues and bring them to developers’ attention.
We encountered this issue in our project and had to update several libraries to meet the required security levels.
Security Flaw Heat Map
Veracode’s Security Flaw Heat Map shows the latest trends in vulnerabilities by language. This information is useful for making informed decisions when choosing technology for new projects or evaluating existing ones.