Have you ever felt uneasy about the numerous dependency packages while operating a Node.js project? It's both fascinating and terrifying that these dependencies, which enable fast and convenient development, can become unexpected security holes. It's like a meticulously built house with dozens of doors and windows, some of which are unlocked. Attackers specifically target such small gaps.
Recently, software supply chain attacks have been continuously increasing. This isn't just a problem for well-known large corporations, but something that applies to all of us. We've already witnessed through various cases how a single vulnerability hidden in a small open-source library can bring down an entire system. The Node.js ecosystem, in particular, requires extra caution because countless packages are shared through a huge hub called NPM (Node Package Manager). Attackers often try to find vulnerabilities in older versions of popular packages or in sub-dependencies hidden within the dependency tree. Here's the twist: these vulnerabilities are even easier to overlook because they are not code we developed ourselves.
The Security Journey of a Growing Startup
Let's hear the story of a rapidly growing fintech startup. This company was developing innovative financial services with a Node.js-based microservices architecture. Their goal was to quickly launch services to the market and optimize user experience. The development team added new features daily and actively utilized numerous open-source libraries. They moved quickly, maximizing the advantages of the Agile development methodology. However, there was one crucial aspect they overlooked during this process: 'dependency security.' It was akin to speeding down a highway at 200 km/h but forgetting to check the tire pressure.
This company was preparing for ISMS-P (Information Security and Personal Information Protection Management System) certification to ensure regulatory compliance and customer trust. During the audit process, numerous vulnerabilities found in Node.js dependency packages were highlighted as a major problem. The development team, with a 'no way' attitude, ran the npm audit command they had been using, but the results were devastating. Dozens of High and Critical level vulnerabilities poured out. From an attacker's perspective, this situation is like a perfectly set table. Especially since web services are a direct communication channel with users, even a single vulnerability can be exploited to steal user information or cripple the entire service. For example, if an RCE (Remote Code Execution) vulnerability were found in a commonly used web framework or utility library, attackers would try to completely take over the server using it. This company now faced the significant challenge of effectively managing these complex dependency vulnerabilities while maintaining development speed.
Limitations of Manual Management and the Need for Automation
The challenges faced by the company were clear. Manually managing the distinct Node.js projects within each of their numerous microservices, along with the tens to hundreds of nested dependency packages, was nearly impossible. It was unrealistic for developers to request security team reviews every time a new package was added or to periodically update all packages. Previously, the main approach was for developers to run the npm audit command locally and manually address only Critical-level vulnerabilities. However, this method had fatal limitations. npm audit often provides only basic information, failing to convey actual exploitability or detailed context. Most importantly, the biggest problem was that it could easily be overlooked if not done manually.
This manual approach caused several operational problems. The development team had to spend too much time responding to security issues, which ultimately led to a slowdown in new feature development. From the security team's perspective, it was difficult to grasp and manage the dependencies of all projects in real-time. Moreover, it conflicted with the company's goal of establishing a DevSecOps culture. Security needed to be embedded throughout the development pipeline, yet it was still being treated as merely a 'checklist' item in the later stages of development. Therefore, the company determined that an automated solution was needed to meet the following key requirements. First, it should be able to automatically scan and detect dependency vulnerabilities for all Node.js projects. Second, it needed to be integrated into the CI/CD pipeline to identify and block security issues from the early stages of development. Third, it had to provide detailed information on detected vulnerabilities along with priority-based management capabilities. Finally, it needed to be an efficient method that could enhance security without imposing unnecessary burdens on developers.
Technology Selection: Focusing on Practicality and Efficiency
To address these challenges, the company compared and analyzed various technologies and solutions. They carefully weighed the pros and cons of several candidates. Broadly, options could be categorized into commercial solutions and self-built, open-source-based approaches.
The first options considered were commercial SAST (Static Application Security Testing) tools like Snyk or Veracode. While these solutions offer powerful features and convenient UIs, they had the limitation of potentially being too costly for a startup's budget. Especially in a rapidly changing environment, license fees and complex implementation procedures could become significant obstacles. Furthermore, as they were already effectively using GitHub-based CI/CD, seamless integration into existing workflows was also an important consideration.
Next, GitHub's Dependabot was reviewed. Dependabot is a very convenient service that integrates with GitHub repositories to automatically detect dependency vulnerabilities and generate update Pull Requests. It can be an optimal choice for open-source projects or small teams. However, this company required more in-depth analysis and customizable control features beyond simple update suggestions, in accordance with their internal security policies. For instance, they wanted to fail the build itself for vulnerabilities exceeding a certain threshold, and there was also a requirement to manage specific packages with a whitelist. Above all, there were some limitations in applying consistent security policies across various repositories and CI/CD environments.
Ultimately, the company chose a 'hybrid' approach, leveraging open-source tools integrated into their own CI/CD pipeline. This offered the advantages of cost-effectiveness and flexible scalability to suit the team's characteristics and requirements. Crucially, they decided to use npm audit and audit-ci to automatically check for vulnerabilities during the build phase, and further, to add a final pre-deployment verification step using a general-purpose container/OS scanner like Trivy. This approach was deemed the most practical solution, enabling continuous security validation from early development to the operational phase without significantly altering existing development workflows.
Implementing Node.js Dependency Security: Automated Pipeline
Now, let's take a detailed look at how this company built its automated dependency security pipeline, step by step. This is the process of proactively identifying and defending against weaknesses targeted by attackers.
1. Initial Vulnerability Detection and Baseline Setting (npm audit & audit-ci)
First, the company sought ways to more effectively utilize the existing npm audit. npm audit quickly finds known vulnerabilities based on the Node.js project's package-lock.json file. The key here is to use it in conjunction with a tool called audit-ci. audit-ci can take the results of npm audit and cause a CI build to fail if vulnerabilities of a certain severity level or higher are found. This is a crucial first step in fundamentally preventing developers from deploying vulnerable code to production environments.
{
"name": "my-nodejs-app",
"version": "1.0.0",
"scripts": {
"audit": "npm audit",
"audit:ci": "audit-ci --audit-level=moderate --config audit-ci.json"
},
"devDependencies": {
"audit-ci": "^6.6.0"
}
}
Then, by creating an audit-ci.json file, you can define the minimum severity level for vulnerabilities to be scanned or rules to ignore specific packages. The company initially applied build failures for Critical and High severity vulnerabilities, then gradually expanded to include Moderate severity.
{
"auditLevel": "high",
"allowlist": [
"CVE-2023-XXXX"
],
"denyList": [],
"exclude": [],
"packageConfig": {}
}
With this setup, the npm run audit:ci command is executed in the CI/CD pipeline, and if the configured criteria are not met, the build automatically stops. Developers must resolve vulnerabilities before merging their code. To specifically examine why this is dangerous, the vulnerabilities found by npm audit can include serious Server-Side Request Forgery (SSRF) or OS Command Injection issues. Such vulnerabilities can be directly used by attackers to seize control of the system or leak sensitive information. Through this, the company significantly helped establish a Shift-Left security culture, enabling early detection and remediation of security issues during the development phase.
2. CI/CD Pipeline Integration
The company integrated audit-ci into its build pipeline using GitHub Actions. They configured it so that dependency scans automatically run whenever a PR (Pull Request) is created or code is pushed to the main branch. This provides developers with immediate feedback on whether their code meets security requirements.
# .github/workflows/nodejs-audit.yml
name: Node.js Dependency Audit
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run audit-ci
run: npm run audit:ci
This pipeline was configured as a mandatory 'Security Check' item at the PR stage. Consequently, PRs could not be merged if they failed this check, enforcing a crucial security gate. This is akin to installing an automated security gate within the development pipeline. Initially, developers were sometimes flustered by build failures, but as they became accustomed to it, a culture naturally formed where they actively maintained up-to-date dependencies or sought alternative packages with security patches. What's interesting here is that as developers became personally invested in security, they began to consider even more robust architectures.
3. Deep Scan Before Deployment (Utilizing Trivy)
While npm audit and audit-ci examined vulnerabilities within Node.js packages themselves, the deployment stage required a process to verify the security of the entire container image. This company was deploying all its microservices as Docker containers. For this, they adopted Trivy. Trivy is a versatile scanner that finds vulnerabilities, misconfigurations, and even secret information across various targets, including container images, file systems, and Git repositories.
After building Docker images in the deployment pipeline, they configured Trivy to scan those images. For example, the following commands can be added to the CI/CD:
docker build -t my-nodejs-app:latest .
trivy image --severity HIGH,CRITICAL --exit-code 1 my-nodejs-app:latest
The --exit-code 1 option causes the scan process to fail and stops the build if Critical or High severity vulnerabilities are found. This served as an effective last line of defense. Unexpectedly, Critical vulnerabilities were sometimes found in the base OS image (e.g., Alpine Linux) or other system libraries, beyond just Node.js packages. In such cases, additional reviews were conducted using KYRA AI Sandbox to analyze the likelihood of actual exploitation or to detect any hidden zero-day attack code. Trivy also offers SBOM (Software Bill of Materials) generation capabilities, which greatly helped the company clearly identify all software components it managed and prepare for potential supply chain risks.
4. Integrated Monitoring and Alerting (Seekurity SIEM/SOAR)
Managing all security events and vulnerability information generated from the automated scan pipeline at a glance was also crucial. The company adopted Seekurity SIEM/SOAR to centrally manage security logs and reports generated by Trivy and audit-ci. When Critical vulnerabilities were found in scan results, Seekurity SIEM automatically generated alerts, and a Seekurity SOAR playbook was configured to send Slack notifications to the responsible development team or create Jira tickets. This dramatically reduced the time spent manually consolidating and analyzing reports.
# Seekurity SIEM/SOAR Playbook Example (Conceptual)
name: nodejs_dependency_vulnerability_alert
trigger:
type: alert
condition: 'source = "trivy" AND severity IN ("CRITICAL", "HIGH")'
actions:
- type: slack_notification
channel: '#devsecops-alerts'
message: 'CRITICAL Node.js Dependency Vulnerability detected: {{alert.description}} in {{alert.asset.name}}'
- type: jira_ticket_creation
project: 'DEVSEC'
summary: 'Fix CRITICAL Node.js Dependency Vulnerability: {{alert.description}}'
assignee: 'security_lead'
priority: 'Highest'
This enabled the security team to understand the dependency security status of the entire system in real-time, and the development team to receive only the necessary information accurately and respond promptly. In particular, Seekurity SIEM demonstrated excellent performance in analyzing security trends by comparing past scan history with the current state and visualizing how quickly specific vulnerabilities were being resolved. Furthermore, by integrating with FRIIM CNAPP/CSPM solutions, a foundation was laid for comprehensively managing security configurations across the entire cloud infrastructure and container runtime security. All these processes went beyond mere tool adoption, playing a decisive role in naturally spreading the culture of 'security is everyone's responsibility.'
Achievements and Changes: A More Robust and Secure System
After implementing the Node.js dependency security automation pipeline, the company experienced remarkable changes. They achieved positive outcomes, both quantitatively and qualitatively.
First, let's look at the quantitative achievements:
| Measurement Item | Before Automation (Manual Review) | After Automation (Pipeline Applied) | Improvement Rate |
|---|---|---|---|
| Average time from CRITICAL/HIGH vulnerability detection to resolution | Avg. 15 days | Avg. 3 days | 80% reduction |
| Vulnerability inclusion rate at deployment | Approx. 25% | Less than 1% | Over 96% reduction |
| Developer security review time | 4 hours per week | Less than 1 hour per week | Over 75% reduction |
Before automation, it took an average of 15 days for Critical/High severity vulnerabilities to be detected and resolved, but after implementing the automated pipeline, this time was dramatically reduced to just 3 days. Additionally, the rate of vulnerabilities included in production deployments sharply decreased from 25% to less than 1%. This signifies a groundbreaking increase in the security reliability of the service. Developers' manual security review time was also significantly saved, allowing them to focus more on their core development tasks.
Qualitative achievements are also noteworthy. Above all, collaboration between the development and security teams became much more organic. Developers now perceive security not as an 'annoying task' but as an 'essential part of the development process.' With the natural establishment of a Shift-Left security culture, the habit of considering security from the early stages of development was formed. Furthermore, the company received high evaluations for its dependency management system during the ISMS-P certification process. These changes played a decisive role in positioning the company not merely as a technology firm, but as a trustworthy fintech service provider with integrated security.
Unexpected Lessons and a Better Future
The company's journey was not always smooth. Contrary to expectations, there was some resistance from the development team initially. There were complaints that frequent build failures were slowing down development. However, the security team went beyond mere 'enforcement,' continuously communicating and educating why such measures were necessary and what long-term benefits they offered. As a result, this process actually served as an opportunity to raise the development team's security awareness.
If this process were to be repeated, they would likely have started by focusing audit-ci's auditLevel solely on Critical or High severity levels from the beginning. Then, they would have gradually expanded to Moderate levels, reducing the development team's burden while still driving change. Gradual adaptation is more important than radical shifts.
There were also unexpected side effects. Automating dependency scans led developers to not just blindly use the latest packages, but to pay more careful attention to a package's security history and maintenance status. This fostered an architecture that aimed to be 'less dependent,' ultimately contributing to the overall robustness of the system. Furthermore, based on data obtained through Seekurity SIEM/SOAR, they could identify which types of dependency vulnerabilities frequently appeared in their environment and which packages posed the greatest risks, providing valuable insights for establishing future development guidelines. Ultimately, this entire process was a journey not just to 'eliminate vulnerabilities,' but to achieve the larger goal of 'security by design.'
Guide to Applying This in Your Environment
Based on this company's experience, why not consider building an automated dependency security pipeline in your Node.js environment? Rather than trying to build everything perfectly from the start, we recommend a phased implementation.
First, a critical prerequisite is having a well-established CI/CD pipeline. It doesn't matter what environment you use, whether it's GitHub Actions, GitLab CI, or Jenkins. Next, we propose a phased implementation roadmap:
- Step 1: Initial Diagnosis and Understanding
Select a few core Node.js projects and runnpm audit. It's crucial to identify what vulnerabilities exist and how severe they are. Why not share the results with your team members and jointly acknowledge the problem? - Step 2: CI Build Integration (audit-ci)
Integrateaudit-ciinto the CI/CD pipeline of your selected projects. Initially, it's best to configure it to fail builds only for Critical or High severity vulnerabilities, then gradually expand the scope. During this process, close communication with developers is essential to minimize misunderstandings. - Step 3: Container Image Scanning (Trivy or Similar Tools)
If you are using Docker containers, add a tool like Trivy to your deployment pipeline to scan built container images. This will be a great help in comprehensively checking for vulnerabilities in the OS or system libraries, in addition to Node.js packages. - Step 4: Integrated Monitoring and Alerting
Build a system to manage all generated security events in one place. Using solutions like Seekurity SIEM/SOAR allows you to integrate and analyze data collected from various security tools, automatically send alerts when threats occur, or execute response playbooks. Furthermore, integrating with FRIIM CNAPP/CSPM to manage the overall security of your cloud infrastructure will establish an even stronger defense system. - Step 5: Continuous Improvement and Education
Security is not a one-time build but an ongoing process that must constantly evolve and improve. Do not overlook efforts to periodically explore new security tools and conduct security training for team members to establish a 'security by design' culture. If suspicious packages are found, utilizing KYRA AI Sandbox for in-depth analysis is also a good approach.
Dependency security in Node.js environments has now become a necessity, not an option. Remember that attackers target small vulnerabilities that are easy for us to overlook. If you maintain vigilance against security threats through automated systems, you will be able to build more secure and robust services.

