Thomas Fellinger | Dynatrace news https://www.dynatrace.com/news/blog/author/thomas-fellinger/ The tech industry is moving fast and our customers are as well. Stay up-to-date with the latest trends, best practices, thought leadership, and our solution's biweekly feature releases. Wed, 04 Mar 2026 14:48:13 +0000 en hourly 1 CVE-2025-55182: React2Shell Critical Vulnerability — what it is and what to do https://www.dynatrace.com/news/blog/cve-2025-55182-react2shell-critical-vulnerability-what-it-is-and-what-to-do/ https://www.dynatrace.com/news/blog/cve-2025-55182-react2shell-critical-vulnerability-what-it-is-and-what-to-do/#respond Fri, 05 Dec 2025 14:55:34 +0000 https://www.dynatrace.com/news/?p=72128 Vulnerability Radar

TL;DR: A critical flaw in React’s Flight protocol (CVE-2025-55182) allows attackers to run code on servers using React Server Components. In short, if your organization uses React Server Components, Next.js, or related frameworks, attackers could potentially take control of your servers, making this a top priority for immediate action. What’s at risk? Vulnerable: React Server […]

The post CVE-2025-55182: React2Shell Critical Vulnerability — what it is and what to do appeared first on Dynatrace news.

]]>
Vulnerability Radar

TL;DR:

A critical flaw in React’s Flight protocol (CVE-2025-55182) allows attackers to run code on servers using React Server Components. In short, if your organization uses React Server Components, Next.js, or related frameworks, attackers could potentially take control of your servers, making this a top priority for immediate action.

Dynatrace is not affected by this vulnerability. For full details, please refer to this security alert post.

What’s at risk?

  • Vulnerable: React Server Components, Next.js, React Router, Waku, and several related frameworks.
  • Impacted: Any organization running affected versions in production.
  • Exploits: Proof-of-concept code is publicly available and active scanning is underway.
  • Remediation: Upgrade to patched versions now to prevent remote code execution.

Real-world scenario:

Imagine a production server running an unpatched version of Next.js. An attacker sends a crafted payload, triggering remote code execution, and gaining unauthorized access to your infrastructure. The window between disclosure and exploitation is shrinking—don’t wait to act.

Immediate steps:

What is React2Shell (CVE-2025-55182)?

A critical vulnerability called React2Shell has been discovered in React’s Flight protocol that could allow attackers to execute arbitrary code on servers running React Server Components. CVE-2025-55182 affects multiple popular frameworks, including Next.js, React Router, and Waku, with exploitation possible under default configurations. While no verified public exploits exist yet, the severity and widespread nature of this vulnerability make immediate patching essential. Organizations using React Server Components should prioritize upgrading to patched versions to protect their applications from potential remote code execution attacks.

How to fix React2Shell vulnerability (CVE-2025-55182): patching guide

To address this vulnerability, it is recommended to upgrade to the patched versions of the affected packages.

Upgrade react-server-dom-* packages to one of the following versions, or higher:

  • 19.0.1
  • 19.1.2
  • 19.2.1

Upgrade Next.js to one of the following versions, or higher:

  • 15.0.5
  • 15.1.9
  • 15.2.6
  • 15.3.6
  • 15.4.8
  • 15.5.7
  • 16.0.7
Two additional vulnerabilities have been found in React Server Components (RSC). They affect packages that have been patched for the original React2Shell vulnerability (CVE-2025-55182), which are listed above. None of the additional vulnerabilities allows Remote Code Execution. Upgrade again to the latest patched versions listed below.

Technical details of the React2Shell vulnerability

CVE-2025-55182 is an unsafe deserialization vulnerability in React’s Flight protocol, affecting server component payloads. This flaw allows attackers to craft malicious payloads that, when processed by the server, can lead to unauthenticated remote code execution. Exploitation is possible under the default configuration of several popular frameworks, making the vulnerability critical and widely exploitable.

Which React and Next.js versions are vulnerable?

The following packages are vulnerable to CVE-2025-55182 because they implement parts of React’s Flight protocol, which handles server component payloads and is the source of the unsafe deserialization flaw:

Package Affected Versions
react-server-dom-parcel (npm) 19.0, 19.1.0, 19.1.1, 19.2.0
react-server-dom-turbopack (npm) 19.0, 19.1.0, 19.1.1, 19.2.0
react-server-dom-webpack (npm) 19.0, 19.1.0, 19.1.1, 19.2.0

Frameworks that implement React Server Components and rely on these packages are also affected. These include: Next.js, React Router, Waku, @parcel/rsc, @vitejs/plugin-rsc, and rwsdk.

The react and react-dom libraries are not impacted because they do not include the Flight protocol or any server-side component handling. Environments that render React exclusively on the client, or that do not integrate frameworks, bundlers, or plugins supporting React Server Components, remain outside the scope of this vulnerability.

The related vulnerability, CVE-2025-66478, was initially published for Next.js and marked as critical. It was later rejected and classified as a duplicate of CVE-2025-55182, because the root cause lies in Next.js depending on vulnerable React packages that implement the Flight protocol.

While the dependency link is correct, Next.js does not rely on the npm ecosystem to resolve these React Server Component packages. Instead, Next.js includes compiled versions of the react-server-dom-* packages directly in its repository. This means that upgrading React in isolation will not remediate the vulnerability for Next.js users because the vulnerable code is embedded within Next.js itself.

The following Next.js versions are affected:

Package Affected Versions
next (npm) >= 14.3.0-canary.77, < 15.0.5
>= 15.2.0-canary.0, < 15.2.6
>= 15.3.0-canary.0, < 15.3.6
>= 15.4.0-canary.0, < 15.4.8
>= 16.0.0-canary.0, < 16.0.7
>= 15.1.0-canary.0, < 15.1.9
>= 15.5.0-canary.0, < 15.5.7

On December 11, 2025, two additional vulnerabilities were discovered in React Server Components, affecting the react-server-dom-* and Next.js packages:

For the Denial of Service vulnerability, there are two CVE numbers due to an incomplete fix for the first CVE.

We recommend updating the affected packages to the latest patch version, as outlined below:

Package Affected versions Fixed in
next (npm) >=13.3 Upgrade to 14.2.35
14.x 14.2.35
15.0.x 15.0.7
15.1.x 15.1.11
15.2.x 15.2.8
15.3.x 15.3.8
15.4.x 15.4.10
15.5.x 15.5.9
15.x canary 15.6.0-canary.60
16.0.x 16.0.10
16.x canary 16.1.0-canary.19
react-server-dom-webpack (npm)
react-server-dom-turbopack (npm)
react-server-dom-webpack (npm)
19.0.x 19.0.3
19.1.x 19.1.4
19.2.x 19.2.3

Are there working exploits for React2Shell vulnerability?

Proof-of-concept exploits for React2Shell (CVE-2025-55182) have been developed and made publicly available. The vulnerability has also been added to the CISA Known Exploited Vulnerabilities (KEV) catalog, confirming active exploitation. Additionally, the vulnerability reporter has published several exploit variants on GitHub:

lachlan2k/React2Shell-CVE-2025-55182-original-poc.

const payload = { 
    '0': '$1', 
    '1': { 
        'status':'resolved_model', 
        'reason':0, 
        '_response':'$4', 
        'value':'{"then":"$3:map","0":{"then":"$B3"},"length":1}', 
        'then':'$2:then' 
    }, 
    '2': '$@3', 
    '3': [], 
    '4': { 
        '_prefix':'console.log(7*7+1)//', 
        '_formData':{ 
            'get':'$3:constructor:constructor' 
        }, 
        '_chunks':'$2:_response:_chunks', 
    } 
} 
  

The root cause of this vulnerability lies in how React’s Flight protocol processes incoming data. The data is processed as chunks, as seen above, which can reference each other, denoted by the $ symbols. The exploit takes advantage of this behavior along with a bug caused by missing attribute checks, which allows access to properties such as constructor. The fix for the attribute check can be seen in the patch here.

The crafted payload chains internal gadgets to create a Promise-like object with an attacker-controlled “.then” property. During deserialization, these Promise-like objects are automatically resolved, which results in code execution.

The vulnerability is actively being scanned in the wild, significantly increasing the risk for organizations running vulnerable versions of affected packages. Given the critical nature of React2Shell and the existence of working exploits, immediate remediation is strongly advised.

Detecting React2Shell (CVE-2025-55182) with Runtime Vulnerability Analytics

You can use Dynatrace Runtime Vulnerability Analytics to detect if vulnerable React Server Component packages or Next.js packages are present by filtering for CVE-2025-55182 in the app.

Dynatrace Runtime Vulnerability Analytics

Bottom Line: If you’re running React Server Components or Next.js in production, review your dependencies immediately and upgrade to patched versions.

Searching for React2Shell vulnerable components (CVE-2025-55182) with DQL

You can also use Smartscape to manually search for vulnerable software components.

fetch dt.entity.software_component
  | fieldsAdd vulnerable =  if(in(entity.name, {
      "react-server-dom-parcel:19.0",
      "react-server-dom-parcel:19.1.0",
      "react-server-dom-parcel:19.1.1",
      "react-server-dom-parcel:19.2.0",
      "react-server-dom-webpack:19.0",
      "react-server-dom-webpack:19.1.0",
      "react-server-dom-webpack:19.1.1",
      "react-server-dom-webpack:19.2.0",
      "react-server-dom-turbopack:19.0",
      "react-server-dom-turbopack:19.1.0",
      "react-server-dom-turbopack:19.1.1",
      "react-server-dom-turbopack:19.2.0"
      }), true)

  // Make sure to check if the found next version is vulnerable   
  | fieldsAdd potentially_vulnerable = 
      startsWith(entity.name, "next:14.3.0") or
      startsWith(entity.name, "next:15") or
      startsWith(entity.name, "next:16")
 
  | filter
      vulnerable == true or
      potentially_vulnerable == true

Important note: When using this manual search method (as opposed to Runtime Vulnerability Analytics), you’ll need to:

  • Manually and reactively search for affected versions whenever an incident occurs
  • Work without the additional context and guidance that RVA provides, such as:
    • Davis Security Score
    • Public internet exposure analysis
    • Exploit availability information

How to detect React2Shell (CVE-2025-55182) exploitation activity

If you have logs containing process execution events, you can detect the common attack patterns (tactics, techniques, and procedures or TTPs) that adversaries use when exploiting vulnerabilities like CVE-2025-55182.

The Dynatrace platform can ingest data from any source that provides this information. The following example (with an alternate for Windows systems) uses Tetragon as the data source. By combining these logs with Smartscape attributes, you get full context for detecting exploitation activity—which helps reduce false positives and speeds up investigations.

// Adjust timeframe accordingly
fetch logs, 
  from: -14d,
  scanLimitGBytes: -1

// We use Tetragon as an example, any source for process execution could be used
| filter log.source == "Container Output"
| filter k8s.workload.name == "tetragon"
| parse content, "JSON:content"

// Filter on process start events
| filter isNotNull(content[process_exec])

// Add fields for further processing
| fieldsAdd k8s.pod.uid = content[process_exec][process][pod][uid]
| fieldsAdd process.parent.executable.path = content[process_exec][parent][binary]
| fieldsAdd process.parent.executable.name = splitString(process.parent.executable.path, "/")[-1]
| fieldsAdd process.executable.path = content[process_exec][process][binary]
| fieldsAdd process.executable.name = splitString(process.executable.path, "/")[-1]
| fieldsAdd process.cmd_line = concat(process.executable.path, " ", content[process_exec][process][arguments])
| fieldsRemove k8s.deployment.name

// Filter on node instances
| filter in(lower(process.parent.executable.name), {
    "node",
    "bun"
  })

// Filter for common shell processes
| filter in(lower(process.executable.name), {
    "ash",
    "bash",
    "bash-static",
    "busybox",
    "csh",
    "dash",
    "fish",
    "ksh",
    "lksh",
    "mksh",
    "mksh-static",
    "posh",
    "rksh",
    "rksh93",
    "sash",
    "static-sh",
    "sh",
    "tcsh",
    "yash",
    "zsh" 
  }) and iAny(contains(lower(process.cmd_line), array(
    "cat",
    "curl",
    "dig",
    "env",
    "head",
    "hostid",
    "hostname",
    "id",
    "ifconfig",
    "ip",
    "install",
    "less",
    "mkfifo",
    "more",
    "nc",
    "ncat",
    "netcat",
    "netstat",
    "nslookup",
    "perl",
    "ping",
    "pwd",
    "route",
    "socat",
    "shred",
    "ss",
    "stat",
    "tail",
    "tee",
    "uname",
    "wget",
    "who",
    "whoami",
    "/dev/tcp",
    "/dev/udp",
    "/etc/passwd",
    "/etc/shadow"
  )[], caseSensitive: false)) or in(lower(process.executable.name), {
    "cat",
    "curl",
    "dig",
    "env",
    "head",
    "hostid",
    "hostname",
    "id",
    "ifconfig",
    "ip",
    "install",
    "less",
    "mkfifo",
    "more",
    "nc",
    "ncat",
    "netcat",
    "netstat",
    "nslookup",
    "perl",
    "ping",
    "pwd",
    "route",
    "socat",
    "shred",
    "ss",
    "stat",
    "tail",
    "tee",
    "uname",
    "wget",
    "who",
    "whoami"
  })

// Get smartscape data for affected entity
| join [
    smartscapeNodes "K8S_POD"
],
on: { k8s.pod.uid },
kind: leftOuter,
fields: {
  k8s.node.name,
  k8s.namespace.name,
  k8s.workload.name,
  k8s.workload.kind,
  k8s.pod.name,
  id_classic
}
fetch logs
| filter winlog.eventid == "1"
| parse content, """
    LD CR LF
    'RuleName: 'LD:RuleName CR LF
    'UtcTime: 'LD:UtcTime CR LF
    'ProcessGuid:' LD:ProcessId CR LF
    'ProcessId: 'LD:PorcessId CR LF
    'Image: 'LD:Image CR LF
    'FileVersion: 'LD:FileVersion CR LF
    'Description: 'LD:Description CR LF
    'Product: ' LD:Product CR LF
    'Company: ' LD:Company CR LF
    'OriginalFileName: ' LD:OriginalFileName CR LF
    'CommandLine: ' LD:CommandLine CR LF
    'CurrentDirectory: ' LD:CurrentDirectory CR LF
    'User: ' LD:User CR LF
    'LogonGuid: ' LD:LogonGuid CR LF
    'LogonId: ' LD:LoginId CR LF
    'TerminalSessionId: ' LD:TerminalSessionId CR LF
    'IntegrityLevel: ' LD:IntegrityLevel CR LF
    'Hashes: ' LD:Hashes CR LF
    'ParentProcessGuid: ' LD:ParentProcessGuid CR LF
    'ParentProcessId: ' LD:ParentProcessId CR LF
    'ParentImage: ' LD:ParentImage CR LF
    'ParentCommandLine: ' LD:ParentCommandLine CR LF
    'ParentUser: ' LD:ParentUser
    """

| filter iAny(endsWith(ParentImage, array(
    "node.exe",
    "bun.exe")[], caseSensitive: false))
| filter iAny(contains(CommandLine, array(
    "-enc",
    "-EncodedCommand",
    "-w hidden",
    "-windowstyle hidden",
    "Test-NetConnection"
  )[], caseSensitive: false)) or in(lower(OriginalFileName), {
    "cmd.exe",
    "powershell.exe",
    "pwsh.exe",
    "arp.exe",
    "at.exe",
    "bash.exe",
    "bitsadmin.exe",
    "certutil.exe",
    "csript.exe",
    "dsget.exe",
    "dsquery.exe",
    "find.exe",
    "findstr.exe",
    "hostname.exe",
    "ipconfig.exe",
    "nbtstat.exe",
    "net.exe",
    "net1.exe",
    "netsh.exe",
    "netstat.exe",
    "nslookup.exe",
    "ntdsutil.exe",
    "reg.exe",
    "rundll32.exe",
    "sc.exe",
    "schtasks.exe",
    "systeminfo.exe",
    "tasklist.exe",
    "tracert.exe",
    "ver.exe",
    "wevtutil.exe",
    "whoami.exe",
    "wmic.exe",
    "wscript.exe"
  })

How to detect suspicious React2Shell (CVE-2025-55182) requests

Most React2Shell exploits work by sending special HTTP headers. 

  • In Next.js apps, this header is next-action. 
  • In other apps, it may be rsc-action-id. 

Some public exploit PoCs also exfiltrate data using query parameters during redirects. In Next.js, these values appear in the x-action-redirect response header. 

Capturing these headers with Dynatrace OneAgent

Dynatrace OneAgent can record these headers as custom request attributes. For setup and configuration instructions, go to Capture request attributes based on web request data.

Use the following settings: 

  1. For next-action or rsc-action-id 
    1. Data source: HTTP request header 
    2. Capture on: Server side 
  2. For x-action-redirect 
    1. Data source: HTTP response header 

We recommend setting multi-value capture to “All distinct values.” 

If real-time updates are disabled in Dynatrace, make sure to restart all affected processes so the changes can take effect. 

Capturing headers with OpenTelemetry

If you’re using OpenTelemetry instead of OneAgent, you can also capture the same request and response headers. (See: https://opentelemetry.io/docs/zero-code/java/agent/instrumentation/http/) 

Detect suspicious requests using DQL

In both cases, you can use the following DQL queries to fetch all the requests that use one of the relevant headers. 

fetch spans

// Filter for relevant spans coming from a nodejs agent or via OpenTelemetry,
// which are a server span for a POST request
| filter (dt.openpipeline.source == "oneagent" AND dt.agent.module.type == "nodejs") OR
    dt.openpipeline.source == "/api/v2/otlp/v1/traces"
| filter span.kind == "server"
| filter http.request.method == "POST"

// update the values on the right hand side to use the name of the request attribute configured
| fieldsRename request_attribute.next_action_header = `request_attribute.next-action header`
| fieldsRename request_attribute.rsc_action_id_header = `request_attribute.rsc-action-id header`
| fieldsRename request_attribute.x_action_redirect_header = `request_attribute.x-action-redirect header`

// Collect all spans with one of the relevant headers set
| filter
    isNotNull(`http.request.header.next-action`) OR
    isNotNull(request_attribute.next_action_header) OR
    isNotNull(`http.request.header.rsc-action-id`) OR
    isNotNull(request_attribute.rsc_action_id_header)

// Collect all unique action IDs from each request into a single field
| fieldsAdd action_id = arrayDistinct(
    arrayRemoveNulls(
      arrayConcat(
        array(
          `http.request.header.next-action`,
          `http.request.header.rsc-action-id`
        ),
        arrayFlatten(array(request_attribute.next_action_header)),
        arrayFlatten(array(request_attribute.rsc_action_id_header))
      )
    )
  )
| expand action_id

// Collect action redirect response header values
| fieldsAdd action_redirect = arrayDistinct(
    arrayRemoveNulls(
      arrayConcat(
        array(`http.response.header.x-action-redirect`),
        arrayFlatten(array(request_attribute.x_action_redirect_header))
      )
    )
  )

// Count usage for each action ID per process group
| summarize {
    count = count(),
    actor.ips = arrayDistinct(arrayRemoveNulls(collectDistinct(client.ip))),
    traces = collectDistinct(trace.id),
    action_redirects = arrayDistinct(arrayRemoveNulls(arrayFlatten(collectDistinct(action_redirect))))
  },
  by: {
    action_id,
    dt.entity.process_group
  }

| fieldsAdd dt.process_group.name = entityName(dt.entity.process_group)

Review the results for requests that use suspicious action IDs. Many public exploit PoCs set the next-action header to a static value, such as “x”.

You can also review the x-action-redirect header values for suspicious values.

Detecting Crypto Miners After React2Shell Exploitation

Attackers exploiting the React2Shell vulnerability commonly deploy cryptocurrency miners on compromised systems. These miners consume significant CPU resources, meaning an affected application or service will often show abnormally high CPU usage shortly after exploitation. 

To proactively hunt for this activity, you can correlate observability data (such as CPU metrics) with vulnerability data in a single DQL query. This approach helps identify workloads that are both: 

  1. Vulnerable to React2Shell, and 
  2. Exhibiting sudden or sustained CPU spikes consistent with crypto-mining behavior. 

Below is an example query pattern you can use. Adjust the metrics, thresholds, and entity types to fit your environment and detection strategy. 

timeseries sum(dt.kubernetes.container.cpu_usage, default: 0, rollup: sum, rate: 1m), nonempty: true, by:{dt.entity.container_group_instance}

| join [
    fetch dt.entity.software_component
      | fieldsAdd vulnerable =  if(in(entity.name, {
          "react-server-dom-parcel:19.0",
          "react-server-dom-parcel:19.1.0",
          "react-server-dom-parcel:19.1.1",
          "react-server-dom-parcel:19.2.0",
          "react-server-dom-webpack:19.0",
          "react-server-dom-webpack:19.1.0",
          "react-server-dom-webpack:19.1.1",
          "react-server-dom-webpack:19.2.0",
          "react-server-dom-turbopack:19.0",
          "react-server-dom-turbopack:19.1.0",
          "react-server-dom-turbopack:19.1.1",
          "react-server-dom-turbopack:19.2.0"
          }), true)
    
    // Make sure to check if the found next version is vulnerable   
    | fieldsAdd potentially_vulnerable = 
        startsWith(entity.name, "next:14.3.0") or
        startsWith(entity.name, "next:15") or
        startsWith(entity.name, "next:16")
    
    | filter
        vulnerable == true or
        potentially_vulnerable == true
    
    | fieldsAdd dt.entity.process_group_instance = belongs_to[dt.entity.process_group_instance]
    | expand dt.entity.process_group_instance

    | join [
       fetch dt.entity.process_group_instance
      | fieldsAdd dt.entity.container_group_instance = belongs_to[dt.entity.container_group_instance]   
    ],
    on: { left[dt.entity.process_group_instance] == right[id]},
    fields: { dt.entity.container_group_instance }
], 
on: { dt.entity.container_group_instance }

Take action now

CVE-2025-55182 poses a critical threat to organizations using React Server Components in production, as public exploits are already available and actively being used.

Here’s what you should do immediately:

  1. Audit your environment. Identify all applications using React Server Components, Next.js, or related frameworks.
  2. Upgrade dependencies. Apply the patched versions listed in the mitigation section above.
  3. Verify remediation. Use Dynatrace Runtime Vulnerability Analytics or similar tools to confirm vulnerable packages have been eliminated.
  4. Monitor continuously. Implement ongoing vulnerability scanning to catch issues before they become incidents.

The combination of critical severity, default exploitability, and widespread framework adoption makes this vulnerability a top priority for security and development teams. Take action today to protect your applications and infrastructure.

Need help assessing your exposure?

Learn more about Dynatrace Runtime Vulnerability Analytics and how it can help you identify and prioritize vulnerabilities across your entire application portfolio.

The post CVE-2025-55182: React2Shell Critical Vulnerability — what it is and what to do appeared first on Dynatrace news.

]]>
https://www.dynatrace.com/news/blog/cve-2025-55182-react2shell-critical-vulnerability-what-it-is-and-what-to-do/feed/ 0
Supply chain security: How to detect malicious software packages with Dynatrace https://www.dynatrace.com/news/blog/supply-chain-security-how-to-detect-malicious-software-packages-with-dynatrace/ https://www.dynatrace.com/news/blog/supply-chain-security-how-to-detect-malicious-software-packages-with-dynatrace/#respond Tue, 21 Oct 2025 14:11:10 +0000 https://www.dynatrace.com/news/?p=71476 Driving AI-powered observability to action with Deloitte and Dynatrace

Open source supply chains face a growing number of security threats, from CI/CD pipeline vulnerabilities to malicious pull requests to phishing attacks to self-propagating malware. To stay ahead, teams need clear visibility into which components are actually running in production. That’s the key to spotting compromised packages before they cause damage. When you combine that […]

The post Supply chain security: How to detect malicious software packages with Dynatrace appeared first on Dynatrace news.

]]>
Driving AI-powered observability to action with Deloitte and Dynatrace

Open source supply chains face a growing number of security threats, from CI/CD pipeline vulnerabilities to malicious pull requests to phishing attacks to self-propagating malware. To stay ahead, teams need clear visibility into which components are actually running in production. That’s the key to spotting compromised packages before they cause damage. When you combine that visibility with automated alerts for malicious code, you empower your organization to react quickly to major threats like the recent NPM supply chain compromises (s1ingularityQixShai Hulud).

When supply chain incidents occur within the open-source ecosystem, organizations must immediately determine their exposure. The critical question becomes: “How can we determine whether a malicious package has been incorporated into our applications?” And, more fundamentally: “Do we even know what is actually deployed and executing in our runtime environments?”

Dynatrace provides powerful capabilities to help you not only answer those questions, but respond rapidly to security threats.

  • Smartscape entities provide real-time representation of your complete environment, including all deployed software components and their versions. By using the Dynatrace Query Language (DQL) you can retrieve the software components in use and cross-reference them with a list of known malicious packages. This allows you to manually check for specific packages and quickly shows you where these are used.
  • Runtime Vulnerability Analytics (RVA) does all of this automatically and continuously for you. Additionally, it uses data about network and code reachability, risk scoring metrics, and other properties to enable environment specific risk prioritization for vulnerable or malicious components.
  • Automated workflows enable you to respond to findings created in the context of RVA, notify responsible teams, open tickets, and orchestrate response actions.

This automated and integrated approach can deliver the following measurable outcomes:

  • Reduced Mean Time to Detect (MTTD) through continuously updated threat intelligence combined with automated monitoring.
  • Reduced Mean Time to Acknowledge (MTTA) by directly engaging responsible stakeholders using established ownership data.
  • Reduced Mean Time to Investigate (MTTI) by providing comprehensive details on malicious package deployment locations, supplemented with logs and traces that enable observation of potential post-compromise activity.
  • Minimized risk of successful adversary persistence by intercepting and disrupting attack chains at the initial compromise stage.

Get started with RVA and automated workflows

First, we have a look at the manual approach and then we’ll dive into what RVA and workflows can do for you.

Searching for malicious packages you’ve read about is as easy as executing a DQL query like the following:

fetch dt.entity.software_component 
| filter contains(softwareComponentShortName, "debug") 
| fieldsAdd softwareComponentType, packageName, softwareComponentVersion

Security Investigator app in Dynatrace screenshot

The ability to manually search software components and filter for potentially malicious packages represents a valuable capability that can accelerate incident response. However, this approach requires maintaining extensive lists of suspicious packages and continuously updating search queries, making it well-suited for exploratory or investigative work but suboptimal for automated supply chain compromise detection.

RVA eliminates this operational burden by delivering a comprehensive, ready-to-use inventory of security issues within your environment. Its runtime-based approach inherently generates minimal false positives, leveraging the same characteristic that enhances vulnerability management to detect malicious package infiltration. RVA surfaces vulnerabilities only when packages are actively loaded into memory and therefore represent genuine threats, ensuring high-fidelity detection with actionable results.

Security Investigator details in Dynatrace screenshot

To improve performance as described earlier, we need to link the detection of harmful packages with fast and efficient ways to fix them. This means using automated systems that alert the right teams as soon as a harmful component is found in their clusters or namespaces, so they can take action quickly.

You can implement an event trigger using the Dynatrace Workflow app such as the following to automatically initiate the workflow whenever a new finding based on a malicious package is created:

Security Investigator event trigger

CWE-506 refers to the Common Weakness Enumeration ID 506: Embedded Malicious Code. Also, we filter in our trigger on new findings so people don’t get notified over and over again on already acknowledged events.

Now you can use the full extent of workflows to retrieve ownership information and notify teams using Slack, Teams, Jira or other methods. You could also automatically start collecting forensic evidence or deploy resources like network policies to mitigate the ongoing threat.

Quarantine workload screenshot

What’s next?

To be able to further investigate supply chain security incidents, Dynatrace recommends ingesting audit logs of cloud service providers like Amazon CloudTrail, Google Cloud Audit Logs, etc. as well as audit logs from your SCM platforms of choice like GitHub, GitLab, etc. Check out the Security Investigator app to collaboratively resolve incidents fast.

The post Supply chain security: How to detect malicious software packages with Dynatrace appeared first on Dynatrace news.

]]>
https://www.dynatrace.com/news/blog/supply-chain-security-how-to-detect-malicious-software-packages-with-dynatrace/feed/ 0
Threat detection in cloud native environments (part 2): How to automate threat management using workflows https://www.dynatrace.com/news/blog/threat-detection-automate-using-workflows/ https://www.dynatrace.com/news/blog/threat-detection-automate-using-workflows/#respond Mon, 02 Jun 2025 15:35:25 +0000 https://www.dynatrace.com/news/?p=69330 Technology predictions for 2024; finding third party vulnerabilities

In our previous blog post, we developed queries to uncover suspicious behavior in our Kubernetes clusters. This time, we're going to run these queries regularly to ensure we catch that behavior as soon as it appears in our environment. We’ll also invoke the right people who know the ins and outs of the attacked workload, and have a look at how we can stop the adversary in their tracks.

The post Threat detection in cloud native environments (part 2): How to automate threat management using workflows appeared first on Dynatrace news.

]]>
Technology predictions for 2024; finding third party vulnerabilities

Modern SecOps practices imply an engineering approach to handling threats. This involves not only treating threat detection as code but also using automation to reduce toil and support faster response to ongoing attacks. When detecting an attack, we don’t want to lose valuable time. Instead, we want to start our investigation quickly and remediate the issue as fast as possible.

This blog will cover the following three important building blocks of handling detected threats:

  1. Leave no gaps: By executing our queries steadily and regularly we can make sure not to miss signs of suspicious behavior. In case we detect something, we want to create an event that represents the found activity.
  2. Get the right eyes on it: Cloud-native environments can be complex, and only responsible teams may know the ins and outs of their applications.
  3. Respond quickly: By using automation we can trigger evidence collection or even disrupt the adversary’s actions.
Missed part 1 of this blog series?

Leave no gaps

To access the Dynatrace AutomationEngine, start by creating a new workflow. We’ll give it a descriptive name and create a trigger to execute it every 10 minutes.

Next, we’re going to add a workflow action that executes DQL queries for us. We’re then pasting the query we examined in the previous blog post that aims to detect possibly compromised service accounts. Before we schedule the query, let’s add a few additional fields to make it better usable going forward:


| fieldsAdd object.name = k8s.pod.name
| fieldsAdd object.type = "k8spod"
| fieldsAdd finding.title = "Access Denied for Service Account Accessing Secret(s) or Configmap(s)"
| fieldsAdd finding.severity = "MEDIUM"
| fieldsAdd finding.time.created = toTimestamp(now())
| fieldsAdd finding.id = hashSha256(concat(toString(finding.time.created), toString(random())))
| fieldsAdd event.description = concat("Access denied for service account ", `user.name`, " accessing secret(s) or configmap(s)")
| fieldsAdd event.id = finding.id
| fieldsAdd actor.ips = array(sourceIP)

These additional fields allow the event to later be properly displayed in the Threats & Exploits app. If you choose another query to be scheduled, feel free to adjust the values accordingly. Stay tuned for part three of this series to learn more about T&E.

Rapid threat management with Dynatrace: Scheduling a query

This query is now executed every 10 minutes. Let’s add another action to it to further process the query results. Based on the technique Tiit Hallas, principal product manager at Dynatrace, described in his blog post, Generate security events from Dynatrace Security Investigator via OpenPipeline, we’re going to add an action that creates a custom detection finding. Combining this with the OpenPipeline configuration allows us to create detection findings every time our query finds something suspicious.

Make sure to add the following fields in OpenPipeline to create a proper detection finding event:

  • kind: SECURITY_EVENT
  • type: DETECTION_FINDING
  • provider: Dynatrace

Get the right eyes on it

SecOps teams often have two problems: there are never enough people, and they can’t know everything about the environment. Both shortcomings can be addressed by democratizing threat detection and response, including collaborating on investigations.

After successfully creating an event that represents our finding, it’s now time to involve the right people. The Dynatrace platform can make use of ownership information being set using native techniques, such as labels in Kubernetes. This flexible and scalable way to measure who is responsible for a certain workload, namespace, or cluster helps ensure we can programmatically find the right people and notify them immediately, such as via Slack. In my cluster, I’ve set a pod label named dt.owner on the deployment to the corresponding team name. Check out the docs to learn more about ownership.


template:
    metadata:
      labels:
        app.kubernetes.io/name: proxy-service
        app.kubernetes.io/part-of: unguard
        dt.owner: unguard-team

The resulting part of the workflow then looks something like this:

Rapid threat management with Dynatrace: Setting a pod label named dt.owner on the deployment to the corresponding team name.

Respond quickly

The third pillar of our workflow will be all about automated response. Maybe we want to deploy a workload that collects forensic evidence. Maybe we want to deploy a network policy quarantining a workload, or maybe we want to get rid of a possibly compromised pod completely. The latter obviously doesn’t solve our problem, but it may stop the bleeding for a while and set the attacker back to square one, gaining us some valuable time for investigating the detection finding and discussing possible remediation options.

Using the Kubernetes automation capabilities combined with the Dynatrace operator, we can apply, delete, or modify any resource we’d like to. In this example, we’re deleting the pod right away to get rid of a possible foothold established by an adversary. This also completes our workflow for handling possibly compromised Kubernetes service accounts (or any other threat detection scenario you’d like to handle that way).

Rapid threat management with Dynatrace: Completing the workflow for handling possibly compromised Kubernetes accounts.

Threat detection with Dynatrace: What’s next?

Now that we have configured our initial set of actions, we can investigate the origins and the impact of the suspicious activity.

Stay tuned for part three of this blog series to learn about how we can do triage and investigation of this and other detection findings in Dynatrace.

The post Threat detection in cloud native environments (part 2): How to automate threat management using workflows appeared first on Dynatrace news.

]]>
https://www.dynatrace.com/news/blog/threat-detection-automate-using-workflows/feed/ 0
Threat detection in cloud native environments: Detecting suspicious Kubernetes service account behavior https://www.dynatrace.com/news/blog/threat-detection-cloud-native-kubernetes/ https://www.dynatrace.com/news/blog/threat-detection-cloud-native-kubernetes/#respond Thu, 08 May 2025 20:32:35 +0000 https://www.dynatrace.com/news/?p=69068 Technology predictions for 2024; finding third party vulnerabilities

With the current threat landscape, attackers are often targeting cloud-native environments. The inherent nature of these environments means they are often spun up very quickly and are distributed, leading to monitoring and security challenges. Attackers leverage this fact, which is clearly demonstrated by the increasingly short time to exploit. On top of that, while the […]

The post Threat detection in cloud native environments: Detecting suspicious Kubernetes service account behavior appeared first on Dynatrace news.

]]>
Technology predictions for 2024; finding third party vulnerabilities

With the current threat landscape, attackers are often targeting cloud-native environments. The inherent nature of these environments means they are often spun up very quickly and are distributed, leading to monitoring and security challenges. Attackers leverage this fact, which is clearly demonstrated by the increasingly short time to exploit. On top of that, while the increasing use of AI in security can certainly benefit organizations, AI can also lead to an explosion of security findings that can overwhelm security teams. With these considerations, threat detection and runtime visibility are critical to maintaining secure environments.

In this blog, we will look at how teams can use Dynatrace’s capabilities to detect and respond to threats quickly and automatically, improving mean time to respond (MTTR) and efficacy.

Dynatrace Query Language (DQL) enables you to develop detections that uncover active threats in your cloud-native environment. By combining different data sources like logs and runtime context, Dynatrace helps improve threat detection accuracy and create actionable findings.

What would an adversary do?

Before creating a detection, there has to be a threat to protect against. Valuable inputs can be threat intelligence, penetration testing reports, or an insightful blog post, just to name a few.

Let’s take the recent ingress-nginx vulnerability (CVE-2025-1974). By creating a malicious ingress object, an adversary can execute arbitrary code in the context of the ingress-nginx service account. Because the service account has permissions to access all secrets within the entire cluster this was categorized as a critical vulnerability. If a threat actor would successfully exploit such a vulnerability, what would they do next and what would be a good method to detect such suspicious behavior?

Threat detection engineering

A common thing attackers do after establishing a foothold is use their newly gained permissions and look for sensitive data (such as credentials) to further escalate their privileges. In the case of Kubernetes, this can be done by asking the kube-api to return all available secrets and configmaps. This uses the permissions of the compromised pod’s service account.

Since the service account may be allowed to access some of those resources but not all of them, this will inevitably result in responses from the kube-api server signaling the requester (the attacker sitting in one of our pods) access has been denied, including an HTTP status code of 403: “Forbidden”. This should rarely happen in a cluster under normal circumstances and is thus a good starting point for building a detection.

Before we start working on our query, let’s talk about the right tool for the job: Security Investigator. Developing detections is an iterative process. You may have to jump back and forth, search other data sources for relevant information, drill down, zoom out again, etc. When using other tools, you may end up with either a huge list of queries in some form (and needing to copy/paste them all the time) or dozens of browser tabs open with all the different snippets and versions of your query. By using Security Investigator’s query tree, your queries are automatically saved. You can start another branch or go back to a previous version of your query.

Query tree within Security Investigator
The query tree can be used to comfortably move forth and back between versions of the query.

Now, back to the adversary and our compromised pod: how can we detect this behavior? By using the ability to search through all the data Dynatrace has about the environment, we can make this indicator visible.

Note: For readability, the query snippets mentioned have been shortened. To get the full query and others, check out the appendix.

fetch logs, 
  from: -15m,
  scanLimitGBytes: -1

| parse content, "JSON{JSON{STRING+:log}(flat=true):properties}(flat=true)",
  parsingPrerequisite: (
    azure.resource.type == "MICROSOFT.CONTAINERSERVICE/MANAGEDCLUSTERS" and 
    log.source == "kube-audit"
  )
| fieldsAdd content=coalesce(properties, content)
| parse content, "JSON{
  STRING+:kind,
  STRING+:apiVersion,
  STRING+:level,
  STRING+:auditID,
  STRING+:stage,
  STRING+:requestURI,
  STRING:verb,
  JSON:user,
  JSON_ARRAY{ipaddr}(typed=true):sourceIPs,
  STRING+:userAgent,
  JSON:objectRef,
  JSON:responseStatus,
  TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):requestReceivedTimestamp,
  TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):stageTimestamp,
  JSON:annotations
  }(flat=true)"

| filter 
  apiVersion == "audit.k8s.io/v1" and
  startsWith(user[username], "system:serviceaccount:") and
  in(verb, {"list", "get"}) and
  in(objectRef[resource], {"configmaps", "secrets"}) and
  responseStatus[reason] == "Forbidden"

This query fetches all the logs and parses the fields of the Kubernetes audit log. It then filters only on those records, including failed requests by service accounts trying to access configmaps or secrets. I’ve executed the suspicious behavior in my environment and ran this query. Let’s see what we get:

Threat detection query results

So far, our query is working perfectly. A few things can be observed by looking at the result:

👍 We see the name of the service account acting suspiciously. In our case, we see “unguard-proxy” in a namespace called “unguard”.

👍 We gain additional information about the pod this request originated from, including its name and uid.

👍 We also get the user agent used to execute the requests. In this case, it’s “kubectl”, which is also a bit telling, since it’s a CLI tool mostly used by humans and rarely by service accounts.

👍 Additionally, we get the source IP of the requester, which seems to be a private IP.

👍 Because Dynatrace is enriching the logs automatically with some metadata, we have fields like cloud.account.id, cloud.provider and cloud.region included, as well.

When we encounter such a suspicious event, we may want to know a few additional things to be able to better assess the situation:

🤔 If there are any vulnerabilities affecting this pod. This may lead us to a possible exploitation of one of those vulnerabilities.

🤔 If there are any critical compliance findings affecting this pod. This may tell us, for example, if a pod is running with elevated privileges.

🤔 Pod labels might tell us more about ownership or other relevant metadata.

If this query finds something malicious down the road, we will definitely want to know more about the security-related context of the originating pod (more on that in a future post of this series). In the end, this could lead us directly to a compromised pod, and we want to avoid requesting access to the cluster or cloud environment in the heat of a possible security incident.

Enriching logs with runtime information

By using what we already know about our cloud-native environment (including all the clusters, namespaces, and pods) with Dynatrace, we can enrich the bare Kubernetes audit log with runtime context based on the entity model. To get the pod name and its namespace from the IP address, we could add the following snippet to our query:

// enrich with smartscape data
| join [
    fetch dt.entity.cloud_application_instance, from:-24h
    | fieldsAdd resourceUid
    | fieldsAdd clustered_by
    | fieldsAdd dt.entity.cloud_application = instance_of[dt.entity.cloud_application]
    | fieldsAdd dt.entity.kubernetes_cluster = clustered_by[dt.entity.kubernetes_cluster]
    | fieldsAdd clusterName = entityName(dt.entity.kubernetes_cluster)
    | fieldsAdd cloudApplicationLabels
  ],
  kind: leftOuter,
  on: { left[k8s.pod.uid] == right[resourceUid] },
  fields: {
    k8s.cluster.name = clusterName,
    k8s.namespace.name = namespaceName,
    dt.entity.cloud_application,
    k8s.pod.labels = cloudApplicationLabels
  }

This gives us not only the cluster name of where this activity is happening but also the unique identifier of the pod in the entity model, along with all of its labels. Immediately, we know which team owns the workload and who to contact in the event of a confirmed true positive.

Threat detection in cloud native environments

Using the unique entity ID, we can now enrich the event even further with vulnerability data. If the pod we’re looking at is known to be vulnerable, we want to know if it may be affected by a vulnerability that could explain the suspicious behavior of its service account.

// enrich with vulnerability data 
| join [ 
fetch events 
| filter  
  event.kind == "SECURITY_EVENT" and 
  event.category == "VULNERABILITY_MANAGEMENT" and 
  event.type == "VULNERABILITY_STATE_REPORT_EVENT" and 
  event.status == "OPEN"  
| expand related_entities.kubernetes_workloads.id = related_entities.kubernetes_workloads.ids
| summarize {
  vulnerability.risk.level = takeLast(vulnerability.risk.level),
  vulnerability.davis_assessment.exploit_status = takeLast(vulnerability.davis_assessment.exploit_status)
  },
  by: { 
    vulnerability.id,
    related_entities.kubernetes_workloads.id
    }
| summarize { 
  vulnerability.risk.level.high_count = countIf(vulnerability.risk.level == "HIGH"), 
  vulnerability.risk.level.medium_count = countIf(vulnerability.risk.level == "MEDIUM"), 
  vulnerability.risk.level.low_count = countIf(vulnerability.risk.level == "LOW"), 
  vulnerability.davis_assessment.exploit_status = countIf(vulnerability.davis_assessment.exploit_status == "AVAILABLE") 
  }, 
  by: { related_entities.kubernetes_workloads.id }
  ], 
on: {left[dt.entity.cloud_application]==right[related_entities.kubernetes_workloads.id]}, 
fields: { 
  vulnerability.risk.level.high_count, 
  vulnerability.risk.level.medium_count, 
  vulnerability.risk.level.low_count, 
  vulnerability.davis_assessment.exploit_status 
}, 
kind:leftOuter

This gives us additional fields that indicate if there are vulnerabilities affecting the pod based on their severity, as well as the exposure of the vulnerability and if an exploit is available.

Threat detection in cloud native environments

Lastly, we may even want to enrich the event with information from Kubernetes security posture management (KSPM) findings:

// enrich with compliance data
| join [
  fetch events, from:-2h
  | filter event.kind == "SECURITY_EVENT"
  | filter event.type == "COMPLIANCE_FINDING"
  | filter compliance.result.object.type == "k8spod"
  | filter compliance.result.status.level == "FAILED"
  | summarize {
      compliance.rule.severity.level = takeLast(compliance.rule.severity.level)
    },
    by: {
      k8s.cluster.name,
      object.name,
      compliance.rule.id
    }

  | summarize {
      compliance.rule.severity.level.high_count = countIf(compliance.rule.severity.level == "HIGH"),
      compliance.rule.severity.level.medium_count = countIf(compliance.rule.severity.level == "MEDIUM"),
      compliance.rule.severity.level.low_count = countIf(compliance.rule.severity.level == "LOW")
  }, 
  by: {
    k8s.cluster.name,
    object.name
  }
], 
on: {
  k8s.cluster.name,
  left[k8s.pod.name]==right[object.name]
}, 
kind:leftOuter,
fields: {
  compliance.rule.severity.level.high_count,
  compliance.rule.severity.level.medium_count,
  compliance.rule.severity.level.low_count
}

Threat detection in cloud native environments

Whatever runtime context you like your finding to include, the chances are high that Dynatrace already knows about it. With DQL, Grail, and Smartscape, you’re able to create meaningful high-fidelity alerts to protect your cloud-native environment.

Lastly, we can add some metadata based on MITRE ATT&CK. This will allow us to track some metrics and maybe even create some meta-detections later.

| fieldsAdd mitre.attack.enterprise.tactic.ids = array("TA0006")
| fieldsAdd mitre.attack.enterprise.technique.ids = array("T1552.007")

Adding those two fields tells us in case this event fires, the tactic and the corresponding technique. This results in the following rich event, that allows to establish situational awareness quickly and confidently:

Threat detection with Dynatrace

Sample queries

In the appendix, you will find this query and others addressing the following techniques:

  • Kubernetes API Permission Enumeration
  • Kubernetes Admission Controller Modification
  • Kubernetes Events Deletion

Feel free to execute them in your environment and adjust them to your needs as the best queries are the ones that are tightly tuned to the environment they’re running in.

Threat detection with Dynatrace: What’s next

Creating a detection query is one of the first steps to successfully handling a threat, but not the last one. By combining multiple capabilities of the Dynatrace platform, teams can continuously check for signs of an ongoing attack, create a detection finding in case we uncover an active adversary, and provide investigative guidance on how to deal with such a finding after it has been created. Future articles will go into detail about these topics to be able to not only successfully detect malicious activity, but also adequately respond to it.

Appendix

Access Denied for Service Account Accessing Secret(s) or Configmap(s)

fetch logs, 
  from: -15m, 
  to: -5m, 
  scanLimitGBytes: -1

// MS AKS
| parse content, "JSON{JSON{STRING+:log}(flat=true):properties}(flat=true)",
  parsingPrerequisite: (
    azure.resource.type == "MICROSOFT.CONTAINERSERVICE/MANAGEDCLUSTERS" and 
    log.source == "kube-audit"
  )
| fieldsAdd content=coalesce(properties, content)

| parse content, "JSON{
  STRING+:kind,
  STRING+:apiVersion,
  STRING+:level,
  STRING+:auditID,
  STRING+:stage,
  STRING+:requestURI,
  STRING:verb,
  JSON:user,
  JSON_ARRAY{ipaddr}(typed=true):sourceIPs,
  STRING+:userAgent,
  JSON:objectRef,
  JSON:responseStatus,
  TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):requestReceivedTimestamp,
  TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):stageTimestamp,
  JSON:annotations
  }(flat=true)"

// filter on denied requests of service accounts trying to access configmaps and/or secrets 
| filter 
  apiVersion == "audit.k8s.io/v1" and
  startsWith(user[username], "system:serviceaccount:") and
  in(verb, {"list", "get"}) and
  in(objectRef[resource], {"configmaps", "secrets"}) and
  responseStatus[reason] == "Forbidden"

| fieldsAdd 
  k8s.pod.uid = user[extra][`authentication.kubernetes.io/pod-uid`],
  k8s.pod.name = user[extra][`authentication.kubernetes.io/pod-name`],
  user.name = user[username]

| expand k8s.pod.uid
| expand k8s.pod.name
| expand sourceIP = sourceIPs

// enrich with smartscape data
| join [
    fetch dt.entity.cloud_application_instance, from:-24h
    | fieldsAdd resourceUid
    | fieldsAdd clustered_by
    | fieldsAdd dt.entity.cloud_application = instance_of[dt.entity.cloud_application]
    | fieldsAdd dt.entity.kubernetes_cluster = clustered_by[dt.entity.kubernetes_cluster]
    | fieldsAdd clusterName = entityName(dt.entity.kubernetes_cluster)
  ],
  kind: leftOuter,
  on: { left[k8s.pod.uid] == right[resourceUid] },
  fields: {
    k8s.cluster.name = clusterName,
    k8s.namespace.name = namespaceName,
    dt.entity.cloud_application
  }

// enrich with vulnerability data 
| join [ 
fetch events 
| filter  
  event.kind == "SECURITY_EVENT" and 
  event.category == "VULNERABILITY_MANAGEMENT" and 
  event.type == "VULNERABILITY_STATE_REPORT_EVENT" and 
  event.status == "OPEN"  
| expand related_entities.kubernetes_workloads.id = related_entities.kubernetes_workloads.ids
| summarize {
  vulnerability.risk.level = takeLast(vulnerability.risk.level),
  vulnerability.davis_assessment.exploit_status = takeLast(vulnerability.davis_assessment.exploit_status)
  },
  by: { 
    vulnerability.id,
    related_entities.kubernetes_workloads.id
    }
| summarize { 
  vulnerability.risk.level.high_count = countIf(vulnerability.risk.level == "HIGH"), 
  vulnerability.risk.level.medium_count = countIf(vulnerability.risk.level == "MEDIUM"), 
  vulnerability.risk.level.low_count = countIf(vulnerability.risk.level == "LOW"), 
  vulnerability.davis_assessment.exploit_status = countIf(vulnerability.davis_assessment.exploit_status == "AVAILABLE") 
  }, 
  by: { related_entities.kubernetes_workloads.id }
  ], 
on: {left[dt.entity.cloud_application]==right[related_entities.kubernetes_workloads.id]}, 
fields: { 
  vulnerability.risk.level.high_count, 
  vulnerability.risk.level.medium_count, 
  vulnerability.risk.level.low_count, 
  vulnerability.davis_assessment.exploit_status 
}, 
kind:leftOuter

// enrich with compliance data
| join [
  fetch events, from:-1h
  | filter event.kind == "SECURITY_EVENT"
  | filter event.type == "COMPLIANCE_FINDING"
  | filter compliance.result.object.type == "k8spod"
  | filter compliance.result.status.level == "FAILED"
  | summarize {
      compliance.rule.severity.level = takeLast(compliance.rule.severity.level)
    },
    by: {
      k8s.cluster.name,
      object.name,
      compliance.rule.id
    }
  
  | summarize {
      compliance.rule.severity.level.high_count = countIf(compliance.rule.severity.level == "HIGH"),
      compliance.rule.severity.level.medium_count = countIf(compliance.rule.severity.level == "MEDIUM"),
      compliance.rule.severity.level.low_count = countIf(compliance.rule.severity.level == "LOW")
  }, 
  by: {
    k8s.cluster.name,
    object.name
  }
], 
on: {
  k8s.cluster.name,
  left[k8s.pod.name]==right[object.name]
}, 
kind:leftOuter,
fields: {
  compliance.rule.severity.level.high_count,
  compliance.rule.severity.level.medium_count,
  compliance.rule.severity.level.low_count
}

| fieldsAdd mitre.attack.enterprise.tactic.id = array("TA0006")
| fieldsAdd mitre.attack.enterprise.technique.id = array("T1552.007")

Kubernetes API Permission Enumeration

fetch logs, 
  from: -15m, 
  to: -5m, 
  scanLimitGBytes: -1

// MS AKS
| parse content, "JSON{JSON{STRING+:log}(flat=true):properties}(flat=true)",
  parsingPrerequisite: (
    azure.resource.type == "MICROSOFT.CONTAINERSERVICE/MANAGEDCLUSTERS" and 
    log.source == "kube-audit")
| fieldsAdd content=coalesce(properties, content)

| parse content, "JSON{
    STRING+:kind,
    STRING+:apiVersion,
    STRING+:level,
    STRING+:auditID,
    STRING+:stage,
    STRING+:requestURI,
    STRING:verb,
    JSON:user,
    JSON_ARRAY{ipaddr}(typed=true):sourceIPs,
    STRING+:userAgent,
    JSON:objectRef,
    JSON:responseStatus,
    TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):requestReceivedTimestamp,
    TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):stageTimestamp,
    JSON:annotations
  }(flat=true)"
| filter 
  apiVersion == "audit.k8s.io/v1" and 
  verb == "create" and
  in (objectRef[resource], {"selfsubjectrulesreviews", "selfsubjectaccessreviews"}) and
  objectRef[apiGroup] == "authorization.k8s.io" and
  startsWith(user[username], "system:serviceaccount:")
  
| fieldsAdd 
  k8s.pod.uid = user[extra][`authentication.kubernetes.io/pod-uid`],
  k8s.pod.name = user[extra][`authentication.kubernetes.io/pod-name`],
  user.name = user[username]

| expand k8s.pod.uid
| expand k8s.pod.name
| expand sourceIP = sourceIPs

// enrich with smartscape data
| join [
    fetch dt.entity.cloud_application_instance, from:-24h
    | fieldsAdd resourceUid
    | fieldsAdd clustered_by
    | fieldsAdd dt.entity.cloud_application = instance_of[dt.entity.cloud_application]
    | fieldsAdd dt.entity.kubernetes_cluster = clustered_by[dt.entity.kubernetes_cluster]
    | fieldsAdd clusterName = entityName(dt.entity.kubernetes_cluster)
  ],
  kind: leftOuter,
  on: { left[k8s.pod.uid] == right[resourceUid] },
  fields: {
    k8s.cluster.name = clusterName,
    k8s.namespace.name = namespaceName,
    dt.entity.cloud_application
  }

// enrich with vulnerability data 
| join [ 
fetch events 
| filter  
  event.kind == "SECURITY_EVENT" and 
  event.category == "VULNERABILITY_MANAGEMENT" and 
  event.type == "VULNERABILITY_STATE_REPORT_EVENT" and 
  event.status == "OPEN"  
| expand related_entities.kubernetes_workloads.id = related_entities.kubernetes_workloads.ids
| summarize {
  vulnerability.risk.level = takeLast(vulnerability.risk.level),
  vulnerability.davis_assessment.exploit_status = takeLast(vulnerability.davis_assessment.exploit_status)
  },
  by: { 
    vulnerability.id,
    related_entities.kubernetes_workloads.id
    }
| summarize { 
  vulnerability.risk.level.high_count = countIf(vulnerability.risk.level == "HIGH"), 
  vulnerability.risk.level.medium_count = countIf(vulnerability.risk.level == "MEDIUM"), 
  vulnerability.risk.level.low_count = countIf(vulnerability.risk.level == "LOW"), 
  vulnerability.davis_assessment.exploit_status = countIf(vulnerability.davis_assessment.exploit_status == "AVAILABLE") 
  }, 
  by: { related_entities.kubernetes_workloads.id }
  ], 
on: {left[dt.entity.cloud_application]==right[related_entities.kubernetes_workloads.id]}, 
fields: { 
  vulnerability.risk.level.high_count, 
  vulnerability.risk.level.medium_count, 
  vulnerability.risk.level.low_count, 
  vulnerability.davis_assessment.exploit_status 
}, 
kind:leftOuter

// enrich with compliance data
| join [
  fetch events, from:-20m
  | filter event.kind == "SECURITY_EVENT"
  | filter event.type == "COMPLIANCE_FINDING"
  | filter compliance.result.object.type == "k8spod"
  | filter compliance.result.status.level == "FAILED"
  | sort timestamp desc
  | summarize {
      compliance.rule.severity.level = takeFirst(compliance.rule.severity.level)
    },
    by: {
      k8s.cluster.name,
      object.name,
      compliance.rule.id
    }
  
  | summarize {
      compliance.rule.severity.level.high_count = countIf(compliance.rule.severity.level == "HIGH"),
      compliance.rule.severity.level.medium_count = countIf(compliance.rule.severity.level == "MEDIUM"),
      compliance.rule.severity.level.low_count = countIf(compliance.rule.severity.level == "LOW")
  }, 
  by: {
    k8s.cluster.name,
    object.name
  }
], 
on: {
  k8s.cluster.name,
  left[k8s.pod.name]==right[object.name]
}, 
kind:leftOuter,
fields: {
  compliance.rule.severity.level.high_count,
  compliance.rule.severity.level.medium_count,
  compliance.rule.severity.level.low_count
}

| fieldsAdd mitre.attack.enterprise.tactic.id = "TA0007"
| fieldsAdd mitre.attack.enterprise.technique.id = "T1069"

Kubernetes Admission Controller Modification

fetch logs, 
  from: -15m, 
  to: -5m, 
  scanLimitGBytes: -1

// MS AKS
| parse content, "JSON{JSON{STRING+:log}(flat=true):properties}(flat=true)",
  parsingPrerequisite: (
    azure.resource.type == "MICROSOFT.CONTAINERSERVICE/MANAGEDCLUSTERS" and 
    log.source == "kube-audit")
| fieldsAdd content=coalesce(properties, content)

| parse content, "JSON{
    STRING+:kind,
    STRING+:apiVersion,
    STRING+:level,
    STRING+:auditID,
    STRING+:stage,
    STRING+:requestURI,
    STRING:verb,
    JSON:user,
    JSON_ARRAY{ipaddr}(typed=true):sourceIPs,
    STRING+:userAgent,
    JSON:objectRef,
    JSON:responseStatus,
    TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):requestReceivedTimestamp,
    TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):stageTimestamp,
    JSON:annotations
  }(flat=true)"

| filter
    apiVersion == "audit.k8s.io/v1" and
    objectRef[apiGroup] == "admissionregistration.k8s.io" and
    in(objectRef[resource], { "mutatingwebhookconfigurations", "validatingwebhookconfigurations" }) and
    in(verb, { "create", "patch", "replace", "update" })

| fieldsAdd mitre.attack.enterprise.tactic.ids = array("TA0003", "TA0004")
| fieldsAdd mitre.attack.enterprise.technique.ids = array("T1078", "T1552", "T1552.007")

Kubernetes Events Deleted

fetch logs, 
  from: -15m, 
  to: -5m, 
  scanLimitGBytes: -1

// MS AKS
| parse content, "JSON{JSON{STRING+:log}(flat=true):properties}(flat=true)",
  parsingPrerequisite: (
    azure.resource.type == "MICROSOFT.CONTAINERSERVICE/MANAGEDCLUSTERS" and 
    log.source == "kube-audit")
| fieldsAdd content=coalesce(properties, content)

| parse content, "JSON{
    STRING+:kind,
    STRING+:apiVersion,
    STRING+:level,
    STRING+:auditID,
    STRING+:stage,
    STRING+:requestURI,
    STRING:verb,
    JSON:user,
    JSON_ARRAY{ipaddr}(typed=true):sourceIPs,
    STRING+:userAgent,
    JSON:objectRef,
    JSON:responseStatus,
    TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):requestReceivedTimestamp,
    TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):stageTimestamp,
    JSON:annotations
  }(flat=true)"

// filter for deleted events
| filter
    apiVersion == "audit.k8s.io/v1" and
    objectRef[resource] == "events" and
    verb == "delete"

| fieldsAdd mitre.attack.enterprise.tactic.id = "TA0005"
| fieldsAdd mitre.attack.enterprise.technique.id = "T1070"

The post Threat detection in cloud native environments: Detecting suspicious Kubernetes service account behavior appeared first on Dynatrace news.

]]>
https://www.dynatrace.com/news/blog/threat-detection-cloud-native-kubernetes/feed/ 0
NGINX vulnerability: Quickly detect and mitigate IngressNightmare vulnerabilities with Dynatrace https://www.dynatrace.com/news/blog/nginx-vulnerability-mitigate-ingressnightmare-with-dynatrace/ https://www.dynatrace.com/news/blog/nginx-vulnerability-mitigate-ingressnightmare-with-dynatrace/#respond Thu, 27 Mar 2025 19:30:12 +0000 https://www.dynatrace.com/news/?p=68482 abstract image of a globe on a dark background representing NGINX vulnerability IngressNightmare and secure user identity and sign-in logs

On March 24, 2025, researchers disclosed multiple vulnerabilities affecting Ingress NGINX Controller for Kubernetes. The highest scored vulnerability, CVE-2025-1974, has a CVSS v3.1 base score of 9.8. Successful exploitation requires attackers reaching the admission webhook over the network which is only possible if the webhook has been exposed externally or an attacker is already able to reach the webhook from within the cluster (for example, by having control over a pod). Any publicly exposed deployment of the ingress-nginx controller in version v1.12.0 or less than 1.11.5 could potentially be affected by these vulnerabilities. You can use Dynatrace to find these vulnerable components and search for indicators of compromise.

The post NGINX vulnerability: Quickly detect and mitigate IngressNightmare vulnerabilities with Dynatrace appeared first on Dynatrace news.

]]>
abstract image of a globe on a dark background representing NGINX vulnerability IngressNightmare and secure user identity and sign-in logs

What is the NGINX vulnerability IngressNightmare?

Recently, researchers discovered a series of vulnerabilities in the Ingress NGINX Controller for Kubernetes, referred to as #IngressNightmare. These vulnerabilities, identified as CVE-2025-1097, CVE-2025-1098, CVE-2025-24514, and CVE-2025-1974, allow unauthenticated remote code execution (RCE) and unauthorized access to secrets stored across all namespaces in a Kubernetes cluster. This could be further exploited to result in a complete cluster takeover due to the privileged nature of such controllers. The highest-scored vulnerability, CVE-2025-1974, carries a critical CVSS v 3.1 base score of 9.8.

The Ingress NGINX Controller is widely used to expose Kubernetes applications externally, making it a critical component for many organizations. Based on the researcher’s analysis, 43% of cloud environments could be affected by this combination of vulnerabilities.

How does an exploit of the IngressNightmare vulnerabilities work?

An attacker can achieve remote code execution (RCE) by chaining multiple flaws in the NGINX implementation if the admission webhook of the ingress-nginx controller is accessible to the attacker without authentication.

  1. First, an attacker can upload a file to the NGINX instance itself, which stores large files in a temporary directory. To prevent immediate clean-up, the Content-Length header is manipulated to make the process think the file upload is not completed yet. This allows an attacker to upload any file to the filesystem and to keep it around for long enough for the next steps to execute.
  2. The second flaw that is being exploited is the process of the ingress controller to test arbitrary admission templates via the nginx NGINX -t command. This command is vulnerable to injections in multiple variations, which allows an attacker to invoke a set of directives. One of these directives is the ssl_engine directive that allows the loading of a shared library into the running process.

Putting one and two together, with the ability to upload any file to a temporary directory and keeping it around for long enough to invoke a directive to load the file as a shared library, an attacker can inject arbitrary code and take over the deployment. From there it is only a matter of time for them to find additional secrets mounted in this usually highly privileged controller and take over the whole Kubernetes cluster.

What is affected by the NGINX vulnerability?

Any publicly exposed deployment of the ingress-nginx controller in version v1.12.0 or <1.11.5 could potentially be affected by these vulnerabilities. Kubernetes has released patches for version 1.11.6 and 1.12.1 that remediate all found vulnerabilities.

Detecting vulnerable instances of ingress-nginx

Using DQL you can quickly generate a list of ingress-nginx instances including versions being used, cluster and namespace information, and IP addresses being used by the service. Please see the sample queries appendix for an example query to get started.

Furthermore, using the DQL function ipIsPublic, it’s possible to filter directly on services having public IPs, which can be an indicator of attackers’ reachability. Check out the Network functions topic in the Dynatrace docs to learn more about the command.

Dynatrace dashboard showing instances of ingress-nginx affected by the NGINX vulnerability IngressNightmare
Figure 1. Dynatrace quickly finds instances of ingress-nginx affected by the NGINX vulnerability IngressNightmare

Detecting post-exploitation activity using Kubernetes audit logs

One reason the severity of this vulnerability is so critical is because of the comprehensive permissions granted to the service account used by ingress-nginx. A ClusterRole called ingress-nginx is configured along with other components. As you can see in the following example, the ClusterRole grants permissions to list, secrets, configmaps, and other resources:

<...> 
rules: 
- apiGroups: 
 - "" 
 resources: 
 - configmaps 
 - endpoints 
 - nodes 
 - pods 
 - secrets 
 - namespaces 
 verbs: 
 - list 
 - watch 
<...>

An attacker that successfully triggers a remote code execution could use these permissions to access possibly sensitive data. Using DQL it’s possible to query Kubernetes audit logs about recent activities of the service account. You can find an example query in the sample queries appendix.

This can potentially surface signs of compromise, like:

  • Abnormal user agents like curl, kubectl and others
  • Requests to get or list all secrets or configmaps of the entire cluster (for example, no namespace is defined in the requests)
Example of suspicious and regular access pattern by the service account in the IngressNightmare vulnerability scenario
Figure 2. Example of suspicious and regular access pattern by the service account.

Sample queries appendix: Identify affected instances and analyze access patterns

Use the following queries to find affected instances of Ingress NGINX Controller for Kubernetes.

Sample query to list instances of ingress-nginx in the environment

fetch dt.entity.cloud_application 
| fieldsFlatten cloudApplicationLabels 
| fieldsFlatten kubernetesAnnotations 
| fieldsFlatten balanced_by 
| filter matchesValue(cloudApplicationLabels[`app.kubernetes.io/name`], "*ingress-nginx*") 
| expand balanced_by.dt.entity.kubernetes_service 
 
| join [ 
  fetch dt.entity.kubernetes_service 
  | fieldsFlatten kubernetesAnnotations 
  | fieldsAdd cloudNetworkServiceType 
  | fieldsAdd ipAddress 
  | expand ipAddress 
  | fieldsFlatten kubernetesLabels 
 ], 
  kind:leftOuter,  
  on:{left[balanced_by.dt.entity.kubernetes_service] == right[id]} 
 
| fieldsFlatten clustered_by 
 
| join [ 
  fetch dt.entity.kubernetes_cluster 
 ],  
  kind:leftOuter,  
  prefix: "k8scluster.",  
  on:{left[clustered_by.dt.entity.kubernetes_cluster] == right[id]} 
 
| summarize  
  {count = count(),  
  ipAddresses=collectDistinct(right.ipAddress)},  
 by: { 
  version = `cloudApplicationLabels.app.kubernetes.io/version`,  
  workload.name = `cloudApplicationLabels.app.kubernetes.io/name`,  
  namespace.name = `right.kubernetesAnnotations.meta.helm.sh/release-namespace`,  
  cluster.name = `k8scluster.entity.name`} 
 
| sort version desc

Sample query to analyze access patterns of the service account

fetch logs, from: -7d 
 
| parse content, "JSON{JSON{STRING+:log}(flat=true):properties}(flat=true)", 
 parsingPrerequisite: ( 
  azure.resource.type == "MICROSOFT.CONTAINERSERVICE/MANAGEDCLUSTERS" and  
  log.source == "kube-audit") 
| fieldsAdd content=coalesce(properties, content) 
 
| parse content, "JSON{ 
  STRING+:kind, 
  STRING+:apiVersion, 
  STRING+:level, 
  STRING+:auditID, 
  STRING+:stage, 
  STRING+:requestURI, 
  STRING:verb, 
  JSON:user, 
  JSON_ARRAY{ipaddr}(typed=true):sourceIPs, 
  STRING+:userAgent, 
  JSON:objectRef, 
  JSON:responseStatus, 
  TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):requestReceivedTimestamp, 
  TIMESTAMP('yyyy-MM-ddTHH:mm:ss.SZ'):stageTimestamp, 
  JSON:annotations 
 }(flat=true)" 
 
| filter  
  apiVersion == "audit.k8s.io/v1" and 
  user[username] == "system:serviceaccount:ingress-nginx:ingress-nginx" and 
  in(verb, {"list", "get"}) and 
  in(objectRef[resource], {"configmaps", "secrets"}) 
 
| summarize {  
  count = count(),  
  start_time = takeMin(timestamp), 
  end_time = takeMax(timestamp), 
  resources = collectDistinct(objectRef[resource]), 
  verbs = collectDistinct(verb) 
 }, by: {  
  user[username], 
  user[uid], 
  userAgent 
 }

How to remediate clusters affected by the NGINX vulnerability

If your Kubernetes cluster is impacted, it’s recommended to upgrade the ingress-nginx controller to a patched version to mitigate the vulnerability. Follow these links to upgrade to one of the following secure releases:

  • v1.12.1 or later (Helm chart version 4.12.1 or later)
  • v1.11.5 or later (Helm chart version 4.11.5 or later)

If upgrading isn’t immediately possible, make sure the admission webhook is not exposed to the public internet. At a minimum, it should be restricted to private access—ideally limited solely to the control plane (API server).

Next steps for mitigating IngressNightmare

The IngressNightmare vulnerabilities—especially CVE-2025-1974 with its critical CVSS score of 9.8—highlight the high stakes of Kubernetes security. This vulnerability enables unauthenticated remote code execution via a trusted component, making even default configurations risky, as any pod can access the vulnerable webhook internally.

To mitigate the threat, teams should immediately upgrade ingress-nginx to a patched version or enforce strict network access controls.

Given Kubernetes is a backbone in many production environments, ingress components should be treated as critical, high-value assets, with continuous monitoring through a platform like Dynatrace that can detect it in runtime environments and help promptly respond to potential exploitation.

The post NGINX vulnerability: Quickly detect and mitigate IngressNightmare vulnerabilities with Dynatrace appeared first on Dynatrace news.

]]>
https://www.dynatrace.com/news/blog/nginx-vulnerability-mitigate-ingressnightmare-with-dynatrace/feed/ 0