Sitemap

Securing Your Stress Testing

How safeguarding dependencies, secrets, and communication channels ensures reliable stress test results

Press enter or click to view image in full size
Photo by Luke Chesser on Unsplash

At first, this might sound strange, tests to support other tests? But when working on a software engineering project, I learned something important: stress testing only works when the rest of your system is ready for it.

Stress testing is not just about pushing your app to the limit. It’s about making sure your system can handle real-world pressure after you’ve done the basics right. This blog shares how I applied a mix of QA techniques to help make our stress testing efforts truly reliable.

1. Stress Testing with k6

Press enter or click to view image in full size
Source: https://tsh.io/

This was the heart of our testing process. It’s not enough for your app to work in ideal conditions. It has to survive when hundreds or even thousands of users hit it at once. Can your backend scale? Will the server crash? Will response times spike?

Stress testing with k6 helped us answer those questions.

Critique of Previous Approach

Most teams stop after unit tests or some basic integration tests. But apps that “pass all tests” can still fail in production under heavy load. Without stress testing, you’ll never know how your system holds up under pressure. And the cost of finding out too late can be huge.

The Hidden Risk in Overlooking Performance Under Load

  • User Dissatisfaction: Slow response times or crashes during peak usage directly hurt the user experience
  • Operational Costs: Performance issues can force expensive infrastructure changes
  • Reputational Damage: Outages during critical periods can hurt a brand’s trust and image

Improved Implementation with k6

To address this, I used k6, an open-source stress testing tool, to evaluate the performance boundaries of our backend. I focused on the income transaction chart data API in our staging environment. This endpoint is critical because our B2B partners depend on it for financial insights.

I designed a 5-stage load profile, with each stage lasting 5 seconds. The target virtual user counts for each stage were: 10, 25, 30, 25, and 10. The peak was 30 users.

stages: [
{ duration: '5s', target: 10 },
{ duration: '5s', target: 25 },
{ duration: '5s', target: 30 },
{ duration: '5s', target: 25 },
{ duration: '5s', target: 10 },
],

The key metrics I monitored were errors and http_req_duration for 200 OK responses. To define success, I set thresholds:

thresholds: {
'errors': ['rate<0.05'],
'http_req_duration{status:200}': ['avg<500'],
},

This is the initial stress test result:

Press enter or click to view image in full size
Initial stress test with 30 concurrent users completed successfully.

The green checkmarks showed that the system passed both thresholds under 30 concurrent users. This gave us a clear performance baseline.

Next, I increased the peak to 40 users to test the system’s breaking point.

Press enter or click to view image in full size
Stress test with 40 concurrent users resulted in failure.

As expected, performance dropped. The average http_req_duration for 200 OK responses reached 517.25ms, exceeding our 500ms threshold. This revealed that our current performance ceiling is around 30 concurrent users for this API.

Impact on the Team and Project

This stress testing effort gave us actionable data, replacing assumptions with clear evidence. For the team, this meant:

  • Informed Scalability Planning: We now know where the bottlenecks are, and can optimize the backend. This will help us plan future scaling, possibly using Kubernetes
  • Targeted Optimization: With metrics like http_req_duration for 200 OK responses, we can focus on specific backend logic or SQL queries that need improvement

By approaching stress testing strategically, we turned performance from a post-deployment problem into a measurable process, ensuring a reliable user experience.

2. Making Stress Testing Secure and Reliable

Performance means nothing if the system isn’t secure. All the stress test results won’t matter if the code can be easily compromised. That’s why we made security testing a must-do before pushing our system to the limit.

2.1. Dependency Scanning with Retire.js

Source: https://github.com/RetireJS

Modern apps rely on a lot of third-party packages. These libraries save time, but they also add security risks.

Press enter or click to view image in full size
Overview of all backend and frontend dependencies used in my project.

In our project, the total number of dependencies from both backend and frontend reached nearly 50+ packages!

Critique of Previous Approach

Most teams only check for issues once when installing packages. If nothing shows up, they move on. But:

  • New CVEs (security vulnerabilities) are published all the time
  • Transitive dependencies (packages your packages use) are often ignored
  • Teams don’t re-scan regularly, especially in fast-moving projects
  • As a result, issues quietly build up over time

The Hidden Risk in Dependencies

A package that looked safe yesterday might become a known security risk today. If you don’t scan regularly, you may never notice, until it’s too late.

Improved Implementation with Retire.js and npm audit

To solve this, I used Retire.js, a simple tool that scans JavaScript projects for known vulnerabilities. At first, I tried the Chrome extension for quick checks.

For more details, you can visit the official Retire.js website here.

Press enter or click to view image in full size
Retire.js Chrome extension scanning results for my project.

Here’s a snapshot of Retire.js scanning my project. It not only detected major packages like react-dom, but also tools like Clarity that we used for usability testing. Luckily, there were no issues found at this stage.

To double-check, I also ran npm audit in the backend and frontend directories. And this time, it found something critical. It flagged a vulnerability in the formidable library, which came from a deeper dependency called hexoid. This issue allowed for filename guessing, which could be exploited under certain conditions.

Press enter or click to view image in full size
Press enter or click to view image in full size
npm audit output after running scans in backend and frontend directories.

Thankfully, npm audit also told me that a fix was available. So I simply ran:

npm audit fix

This command automatically resolved the vulnerability.

Why This Supports Stress Testing

Stress testing tells us how the system performs under load. But without dependency scanning, we might be testing a system that already has security holes. These scans helped us make sure we were working with a clean and secure codebase, so our stress test results could actually be trusted.

2.2. Secret Detection with GitLeaks

Source: https://github.com/gitleaks

Even if your dependencies are safe, accidentally exposing secrets can instantly undermine your entire system. Our stress tests evaluate how well the backend performs under pressure, but if someone gets access through a leaked API key, all that performance work becomes irrelevant.

Get Kristoforus Adi Himawan’s stories in your inbox

Join Medium for free to get updates from this writer.

In our project, I had a helper file called preload.js where I loaded several sensitive environment variables for stress testing. Here's a simplified version of how it looked:

require("dotenv").config();
const { execSync } = require("child_process");
const path = require("path");

const TEST_EMAIL = process.env.TEST_EMAIL;
const TEST_PASSWORD = process.env.TEST_PASSWORD;
const BACKEND_HOST = process.env.BACKEND_HOST;
const LOGIN_URL = `${BACKEND_HOST}/v1/api/login`;
const SUMMARY_URL = `${BACKEND_HOST}/v1/summary/api`;

const stressTestPath = path.resolve(__dirname, "stress.test.js");
const escapedPath = stressTestPath.replace(/\\/g, "\\\\");

execSync(`k6 run "${escapedPath}"`, {
env: {
...process.env,
TEST_EMAIL,
TEST_PASSWORD,
LOGIN_URL,
SUMMARY_URL,
},
stdio: "inherit",
});

You can clearly see how many sensitive values like API endpoints, credentials, and URLs I load from .env. If even one of these variables were ever hardcoded or accidentally committed, it would be a major security issue.

Critique of Previous Approach

The usual strategy in many teams is to “be careful” and just hope that no one commits secrets. But this isn’t sustainable. In practice:

  • Secrets are easy to commit by mistake, especially in testing or fast-moving dev environments
  • Even if reverted, Git history retains them
  • Manual code reviews often miss secrets
  • Once exposed, secrets can lead to unauthorized access, data breaches, or API abuse

Improved Implementation with GitLeaks

To prevent this, I used GitLeaks, a security tool built specifically to detect and stop hardcoded secrets like API tokens and passwords in Git repositories.

I began testing it through the GitLeaks Playground, which is available on their official site. You can try it yourself by uploading a file here.

For my first scan, I chose our frontend dashboard file, a critical component that interacts with many backend APIs. Given its sensitivity, this file had to be clean.

Press enter or click to view image in full size
GitLeaks Playground scan results for my project repository.

The scan came back clean with no secrets found. This gave us peace of mind that our most important frontend logic wasn’t exposing anything sensitive.

Why It Supports Stress Testing

A secure testing environment is a prerequisite for any meaningful stress test. If secrets like API keys or credentials are accidentally committed and exposed in a helper file like preload.js, attackers could exploit them. GitLeaks plays a critical role in ensuring the integrity and safety of the environment where stress tests are run.

By catching exposed secrets before they enter version control, GitLeaks ensures that:

  • Authentication tokens and test credentials remain secure, so attackers can’t interfere with load endpoints during testing
  • The system’s true performance is measured, not one influenced by external abuse or misconfigured access

In short, GitLeaks fortifies the foundation that stress testing depends on: a secure, uncompromised codebase. It shifts focus from reactive incident handling to proactive testing.

2.3. SSL/TLS Configuration Validation with SSL Labs

Press enter or click to view image in full size
Source: https://www.ssllabs.com/

While application logic and dependencies matter, securing communication channels is just as critical, especially when your app handles sensitive financial transactions. All our performance testing would be meaningless if the underlying transport layer was vulnerable to tampering.

Critique of Previous Approach

Before we introduced formal validation, our team operated under a common but dangerous assumption: having an SSL certificate meant communication was secure. In reality, certificates only indicate that encryption exists, not that it’s implemented securely.

Here’s why that’s risky:

  • Many servers still support deprecated protocols like SSLv3 or TLS 1.0, which are known to be vulnerable
  • Weak or misconfigured cipher suites can leave encrypted traffic exposed to attackers
  • Improper certificate chains can result in browsers showing security warnings or rejecting the connection altogether
  • Without a detailed scan, man-in-the-middle (MITM) vulnerabilities may go undetected

Improved Implementation with SSL Labs

To eliminate these risks, I used SSL Labs, a free tool by Qualys that performs in-depth SSL/TLS configuration audits. It evaluates critical factors like:

  • Supported protocol versions (e.g., TLS 1.3, 1.2)
  • Cipher suite strength
  • Certificate trust and transparency
  • Vulnerability to known SSL/TLS exploits

You can try the service yourself by visiting the SSL Labs website here.

Press enter or click to view image in full size
SSL Labs grade A confirming our server meets high security standards.
Press enter or click to view image in full size
Press enter or click to view image in full size
Detailed breakdown of factors contributing to the SSL Labs score.

For our project, the scan returned an A grade, indicating that our server met high security standards. Here’s a breakdown of what contributed to that score:

  • Certificate Integrity: The certificate was valid, correctly chained, and registered in public Certificate Transparency logs, helping to detect any misused certificates
  • Protocol Support: Our server only supported modern, secure protocols (TLS 1.3 and 1.2), and explicitly disabled insecure ones like SSLv3, TLS 1.0, and 1.1
  • Cipher Strength: We used strong cipher suites such as AES-GCM and CHACHA20_POLY1305, ensuring end-to-end data confidentiality and integrity

Why It Supports Stress Testing

Stress testing evaluates system performance under extreme load. But, these results are only meaningful if the communication layer is secure. Without properly configured SSL/TLS, encrypted data flows can be intercepted or tampered with, invalidating test results and exposing sensitive data during testing.

By validating our SSL/TLS setup with SSL Labs, we ensured:

  • Stress tests run in a trusted environment, where data in transit can’t be intercepted or altered by attackers
  • Authentication and session flows (often bottlenecks under load) are securely protected
  • Any performance degradation observed is due to real infrastructure limits, not the result of insecure protocols or man-in-the-middle risks

Secure communication is a requirement for valid stress testing, especially in modern applications that rely heavily on API interactions and sensitive user sessions.

Conclusion

Ensuring robust security measures is essential for stress testing to provide trustworthy results. Without a secure foundation covering dependency management, secret protection, and encrypted communication, performance tests risk being invalidated by vulnerabilities or breaches.

By proactively integrating tools like Retire.js, GitLeaks, and SSL Labs, we create an environment where stress tests can confidently simulate real-world conditions. Ultimately, security and stress testing go hand in hand to build reliable and high-performing applications.