On October 8, 2026, CISA added CVE-2016-3081 — a command injection vulnerability in Apache Struts 2 — to the Known Exploited Vulnerabilities (KEV) catalog, confirming that threat actors are actively exploiting it in the wild right now. Let that sink in: a decade-old flaw in a framework that should have been patched or retired years ago is generating enough real-world exploitation telemetry in 2026 to warrant federal action.
This is not a historical footnote. The KEV listing means defenders must treat any internet-facing Struts 2 application with Dynamic Method Invocation (DMI) enabled as an assumed-target asset. CISA's directive under BOD 26-04 requires federal agencies — and should compel every private-sector organization — to apply vendor mitigations, follow CISA's Forensics Triage Requirements, or discontinue use of the product entirely if mitigations cannot be applied.
In my IR casework, legacy Java framework exploitation remains one of the most reliable initial-access vectors we see, precisely because these applications sit forgotten in DMZs while everything around them gets modernized. This post breaks down the vulnerability, how to detect exploitation attempts and successful compromise, and exactly how to remediate.
Technical Analysis
What Is CVE-2016-3081?
CVE-2016-3081 is a command injection vulnerability in Apache Struts 2, the open-source MVC framework used to build Java web applications. The flaw exists in the way Struts handles action names when Dynamic Method Invocation (DMI) is enabled.
Affected products:
- Apache Struts 2 versions 2.0.0 through 2.3.28 (with DMI enabled)
- Fixed in Struts 2.3.20.3, 2.3.24.3, and 2.3.28.1
Exploitation mechanics (defender's view):
When DMI is enabled, Struts allows invoking arbitrary methods on an Action class using the method: prefix in the action name. The vulnerable code path evaluates the portion after method: as an OGNL (Object-Graph Navigation Language) expression rather than a simple method name. An attacker who can reach a Struts action endpoint can submit a crafted request such as:
GET /action!method:{%23_memberAccess%3d@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,...(@java.lang.Runtime@getRuntime().exec('id'))}.action HTTP/1.1
The OGNL payload executes server-side with the privileges of the application server process (typically Tomcat, JBoss, or WebLogic), giving the attacker remote command execution — the classic path to web shell deployment, credential harvesting, and lateral movement.
Exploitation prerequisites:
- The application runs a vulnerable Struts 2 version.
- DMI is enabled (
struts.enable.DynamicMethodInvocation=true, or the application uses wildcard action mappings or the!bang operator in requests). - The endpoint is reachable — and per CISA's guidance, every stakeholder must evaluate each asset's internet exposure.
Exploitation Status
- Confirmed active exploitation — this is the defining fact of the October 8, 2026 KEV addition.
- Public PoCs and weaponized exploit modules have existed for years, which means the barrier to entry for attackers is effectively zero. Scanner noise alone does not explain a KEV listing; CISA's catalog is driven by evidence of real-world exploitation.
- CISA mandated action: Apply vendor mitigations per BOD 26-04 guidance and CISA's Forensics Triage Requirements; for cloud services, follow applicable BOD 26-04 guidance; discontinue use of the product if mitigations are unavailable.
Why Now?
Ten-year-old CVEs land in the KEV for one of two reasons: a new campaign is mass-scanning and exploiting legacy estates, or incident responders are repeatedly finding this flaw as the initial-access vector in active intrusions. Either way, the defensive lesson is identical — your attack surface management program must account for legacy applications, not just the shiny new stack. Attackers are deliberately hunting the long tail of unpatched Struts, Confluence, and ColdFusion servers that organizations forgot they own.
Detection & Response
This is a technical threat with confirmed active exploitation. The detections below target three layers: web request indicators (the method: / OGNL payload), post-exploitation behavior (Java application server spawning shells), and asset identification (finding vulnerable Struts deployments).
Sigma Rules
---
title: Apache Struts DMI OGNL Injection Attempt in Web Request
tid: 9f2c4a71-3b8d-4e1f-a6c9-7d5e2b8a1f34
status: experimental
description: Detects HTTP requests containing Struts Dynamic Method Invocation payloads (method: prefix with OGNL expressions) targeting CVE-2016-3081. Matches web server/proxy access logs ingested as proxy or webserver logsources.
references:
- https://www.cisa.gov/known-exploited-vulnerabilities-catalog?search_api_fulltext=CVE-2016-3081
- https://cwiki.apache.org/confluence/display/WW/S2-032
- https://attack.mitre.org/techniques/T1190/
author: Security Arsenal
date: 2026/10/08
tags:
- attack.initial_access
- attack.t1190
logsource:
category: webserver
detection:
selection_method:
cs-uri|contains:
- 'method:'
- 'method%3a'
- 'method%3A'
selection_ognl:
cs-uri|contains:
- '%23_memberAccess'
- 'ognl.OgnlContext'
- 'getRuntime().exec'
- 'java.lang.Runtime'
- '%28%23'
- 'DEFAULT_MEMBER_ACCESS'
condition: selection_method or selection_ognl
falsepositives:
- Vulnerability scanners and authorized penetration tests
level: high
---
title: Java Application Server Spawning Shell or Command Interpreter
tid: 4e7b1d93-8c2a-4f56-b3d1-2a9e6c4f7b81
status: experimental
description: Detects Tomcat, JBoss, or other Java servlet container processes spawning command shells or scripting interpreters — a strong post-exploitation indicator following Struts OGNL command injection (CVE-2016-3081) on Windows hosts.
references:
- https://www.cisa.gov/known-exploited-vulnerabilities-catalog?search_api_fulltext=CVE-2016-3081
- https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/10/08
tags:
- attack.execution
- attack.t1059
logsource:
category: process_creation
product: windows
detection:
selection_parent:
ParentImage|endswith:
- '\java.exe'
- '\javaw.exe'
- '\tomcat.exe'
- '\tomcat8.exe'
- '\tomcat9.exe'
- '\jboss.exe'
selection_child:
Image|endswith:
- '\cmd.exe'
- '\powershell.exe'
- '\pwsh.exe'
- '\wscript.exe'
- '\cscript.exe'
- '\mshta.exe'
- '\certutil.exe'
- '\bitsadmin.exe'
- '\curl.exe'
- '\whoami.exe'
- '\net.exe'
- '\nltest.exe'
condition: selection_parent and selection_child
falsepositives:
- Rare legitimate application functionality invoking system commands; investigate any hit against Struts-hosted applications
level: critical
---
title: Linux Java Process Spawning Shell Post-Exploitation
tid: 7c3a8f25-1d94-4b67-e2a8-5f6c9d3b8e12
status: experimental
description: Detects java or servlet container processes spawning interactive shells on Linux — consistent with successful Struts DMI OGNL exploitation (CVE-2016-3081) leading to command execution or web shell activity.
references:
- https://www.cisa.gov/known-exploited-vulnerabilities-catalog?search_api_fulltext=CVE-2016-3081
- https://attack.mitre.org/techniques/T1059.004/
author: Security Arsenal
date: 2026/10/08
tags:
- attack.execution
- attack.t1059.004
logsource:
category: process_creation
product: linux
detection:
selection_parent:
ParentImage|endswith:
- '/java'
- '/jsvc'
selection_child:
Image|endswith:
- '/sh'
- '/bash'
- '/dash'
- '/zsh'
- '/curl'
- '/wget'
- '/nc'
- '/ncat'
- '/python'
- '/perl'
- '/id'
- '/whoami'
condition: selection_parent and selection_child
falsepositives:
- Application servers with legitimate scripting hooks; validate against application change windows
level: critical
KQL — Microsoft Sentinel / Defender
The first query hunts web request indicators in proxy/firewall/IIS logs ingested via CEF or W3C formats. The second hunts the post-exploitation process lineage in Defender for Endpoint telemetry.
// Hunt 1: Struts DMI / OGNL injection attempts in web and proxy logs
// Targets CommonSecurityLog (CEF-ingested WAF/proxy) — adjust field names for your W3CIISLog or custom tables
CommonSecurityLog
| where TimeGenerated > ago(30d)
| where RequestURL has_any ("method:", "method%3a", "method%3A",
"%23_memberAccess", "ognl.OgnlContext", "java.lang.Runtime",
"DEFAULT_MEMBER_ACCESS", "getRuntime().exec")
| extend DecodedURL = url_decode(RequestURL)
| project TimeGenerated, SourceIP, DestinationIP, DestinationPort,
RequestMethod, DecodedURL, RequestPayload, DeviceVendor, DeviceProduct
| order by TimeGenerated desc
;
// Hunt 2: Java/Tomcat processes spawning shells or LOLBins (post-exploitation)
DeviceProcessEvents
| where TimeGenerated > ago(30d)
| where InitiatingProcessFileName in~ ("java.exe", "javaw.exe", "tomcat.exe", "tomcat8.exe", "tomcat9.exe")
or InitiatingProcessCommandLine has_any ("catalina", "tomcat", "jboss")
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe", "wscript.exe",
"cscript.exe", "mshta.exe", "certutil.exe", "bitsadmin.exe",
"whoami.exe", "net.exe", "nltest.exe", "curl.exe")
| project TimeGenerated, DeviceName, AccountName,
InitiatingProcessFileName, InitiatingProcessCommandLine,
FileName, ProcessCommandLine, SHA256
| order by TimeGenerated desc
;
// Hunt 3: Linux Syslog ingestion — shells spawned under java/jsvc parents
Syslog
| where TimeGenerated > ago(30d)
| where ProcessName in~ ("sh", "bash", "dash", "curl", "wget", "nc", "ncat", "python", "perl")
| where SyslogMessage has_any ("java", "jsvc", "catalina", "tomcat")
and SyslogMessage has_any ("exec", "child", "fork")
| project TimeGenerated, Computer, ProcessName, SyslogMessage
| order by TimeGenerated desc
Velociraptor VQL
This artifact identifies live compromise indicators: shells or script interpreters running as children of Java application server processes, plus a sweep for dropped web shells in common servlet container deployment directories.
-- Security Arsenal: CVE-2016-3081 post-exploitation hunt
-- Find shells/interpreters spawned under Java app server processes
-- and web shells dropped into Tomcat/JBoss deployment directories.
SELECT Pid, Ppid, Name, Exe, CommandLine, Username, CreateTime
FROM pslist()
WHERE (
Name =~ '(?i)^(cmd|powershell|pwsh|wscript|cscript|mshta|certutil|sh|bash|dash|curl|wget|nc|ncat|python|perl)'
)
AND Ppid IN (
SELECT Pid FROM pslist()
WHERE Name =~ '(?i)(java|javaw|tomcat|jsvc)'
OR CommandLine =~ '(?i)(catalina|tomcat|jboss|struts)'
)
-- Sweep servlet container web roots for recently written JSP web shells
LET webroots = (
'C:/Program Files/Apache Software Foundation/Tomcat*/webapps/**/*.jsp',
'C:/tomcat*/webapps/**/*.jsp',
'/opt/tomcat*/webapps/**/*.jsp',
'/var/lib/tomcat*/webapps/**/*.jsp',
'/usr/share/tomcat*/webapps/**/*.jsp'
)
SELECT FullPath, Size, Mtime, Ctime,
read_file(filename=FullPath, length=4096) AS Head
FROM glob(globs=webroots)
WHERE Mtime > now() - 60*86400
AND (
FullPath =~ '(?i)(cmd|shell|exec|spy|tunnel|godzilla|behinder|antsword)'
OR Head =~ '(?i)(Runtime\.getRuntime|ProcessBuilder|getRuntime\(\)\.exec)'
)
ORDER BY Mtime DESC
Remediation & Verification Script
Use this Bash script to inventory Struts 2 versions across your Linux/Java estate and check whether DMI is explicitly disabled. Run it via your configuration management tooling across all application servers.
#!/usr/bin/env bash
# Security Arsenal — CVE-2016-3081 Struts DMI exposure audit
# Identifies vulnerable struts2-core JARs and DMI configuration
echo "=== [1/3] Locating struts2-core JARs ==="
find / -type f -name 'struts2-core-*.jar' 2>/dev/null | while read -r jar; do
version=$(basename "$jar" | sed -E 's/struts2-core-([0-9.]+)\.jar/\1/')
major=$(echo "$version" | cut -d. -f2)
minor=$(echo "$version" | cut -d. -f3)
patch=$(echo "$version" | cut -d. -f4)
patch=${patch:-0}
vuln="UNKNOWN"
if [ "$major" -le 3 ] && [ "$minor" -le 28 ]; then
# Patched branches: 2.3.20.3, 2.3.24.3, 2.3.28.1
if { [ "$minor" -eq 20 ] && [ "$patch" -ge 3 ]; } || \
{ [ "$minor" -eq 24 ] && [ "$patch" -ge 3 ]; } || \
{ [ "$minor" -eq 28 ] && [ "$patch" -ge 1 ]; }; then
vuln="PATCHED-BRANCH"
else
vuln="VULNERABLE (if DMI enabled)"
fi
fi
echo " $jar -> version $version -> $vuln"
done
echo "=== [2/3] Checking Dynamic Method Invocation configuration ==="
find / -type f \( -name 'struts.properties' -o -name 'struts.xml' \) 2>/dev/null | while read -r cfg; do
if grep -qE 'struts\.enable\.DynamicMethodInvocation\s*=\s*false' "$cfg" 2>/dev/null; then
echo " $cfg -> DMI explicitly DISABLED (good)"
else
echo " $cfg -> DMI not explicitly disabled — REVIEW REQUIRED"
fi
done
echo "=== [3/3] Searching web roots for suspicious JSP artifacts (last 60 days) ==="
find /opt /var/lib /usr/share -path '*webapps*' -name '*.jsp' -mtime -60 2>/dev/null | while read -r jsp; do
if grep -lE 'Runtime\.getRuntime|ProcessBuilder' "$jsp" >/dev/null 2>&1; then
echo " SUSPICIOUS: $jsp"
fi
done
echo "=== Audit complete. Any VULNERABLE or SUSPICIOUS findings require immediate escalation. ==="
For Windows-hosted Tomcat, use this PowerShell equivalent:
# Security Arsenal — CVE-2016-3081 Struts DMI exposure audit (Windows)
$results = @()
# 1) Find struts2-core JARs and flag vulnerable versions
Get-ChildItem -Path 'C:\' -Filter 'struts2-core-*.jar' -Recurse -ErrorAction SilentlyContinue |
ForEach-Object {
if ($_.Name -match 'struts2-core-([0-9.]+)\.jar') {
$v = $Matches[1]
$status = 'REVIEW'
if ($v -match '^2\.3\.(\d+)(?:\.(\d+))?$') {
$minor = [int]$Matches[1]; $patch = if ($Matches[2]) { [int]$Matches[2] } else { 0 }
if (($minor -eq 20 -and $patch -ge 3) -or ($minor -eq 24 -and $patch -ge 3) -or ($minor -eq 28 -and $patch -ge 1)) {
$status = 'PATCHED-BRANCH'
} elseif ($minor -le 28) {
$status = 'VULNERABLE (if DMI enabled)'
}
}
$results += [PSCustomObject]@{ Path = $_.FullName; Version = $v; Status = $status }
}
}
# 2) Check DMI configuration in struts.properties / struts.xml
Get-ChildItem -Path 'C:\' -Include 'struts.properties','struts.xml' -Recurse -ErrorAction SilentlyContinue |
ForEach-Object {
$content = Get-Content $_.FullName -Raw -ErrorAction SilentlyContinue
$dmi = if ($content -match 'struts\.enable\.DynamicMethodInvocation\s*=\s*false') { 'DMI DISABLED (good)' } else { 'DMI not explicitly disabled — REVIEW' }
$results += [PSCustomObject]@{ Path = $_.FullName; Version = '-'; Status = $dmi }
}
$results | Format-Table -AutoSize
$results | Where-Object { $_.Status -match 'VULNERABLE|REVIEW' } | Export-Csv -Path "C:\struts_cve-2016-3081_findings.csv" -NoTypeInformation
Write-Host "Findings exported to C:\struts_cve-2016-3081_findings.csv"
Remediation
1. Patch — the only complete fix
Upgrade struts2-core to a fixed release immediately:
- Struts 2.3.28.1 or later (or the patched maintenance branches 2.3.20.3 / 2.3.24.3 if you are pinned to an older line)
- Reference: Apache Struts security bulletin S2-032 (https://cwiki.apache.org/confluence/display/WW/S2-032)
Frankly, if you are still on the 2.3.x line in 2026, patching this one CVE is triage, not treatment. Plan a migration to a currently supported Struts release or off the framework entirely — 2.3.x has been end-of-life for years and carries a long tail of additional critical RCEs.
2. Immediate mitigation if patching requires a change window
Disable Dynamic Method Invocation in struts.properties or struts.xml:
struts.enable.DynamicMethodInvocation=false
Restart the application after the change and verify with the audit scripts above. Note that if your application relies on wildcard action mappings or the ! operator, regression-test before pushing to production — but treat that test cycle as an emergency change, not a quarterly project.
3. CISA-mandated actions (BOD 26-04)
- Deadline compliance: Follow the remediation due date listed in the KEV entry per BOD 26-04 ("Prioritizing Security Updates Based on Risk").
- Forensics Triage Requirements: Before and during remediation, preserve evidence per CISA's Forensics Triage Requirements — capture memory and disk images of affected application servers before patching, because a decade-exposed internet-facing Struts instance has a non-trivial probability of prior compromise. Do not patch-and-pray; check for web shells, anomalous child processes of the JVM, and unexpected outbound connections first.
- Internet exposure evaluation: CISA explicitly directs stakeholders to evaluate each asset's internet exposure. If the application does not need to be internet-facing, put it behind a VPN or authenticated gateway today.
- Discontinue use if unmitigable: If you cannot patch or disable DMI (vendor-locked appliance, abandoned internal app), CISA's directive is to discontinue use of the product. Isolate or decommission it.
4. Hunt before you close the ticket
For any asset found vulnerable and internet-exposed, assume breach until proven otherwise:
- Review web access logs for
method:/ OGNL indicators going back at least 90 days. - Sweep deployment directories for recently modified or anomalous JSP files.
- Check for JVM-spawned shells, persistence (scheduled tasks, systemd units, SSH authorized_keys additions under the service account), and credential access artifacts.
Conclusion
CVE-2016-3081's addition to the CISA KEV in October 2026 is a case study in why vulnerability management programs fail: not because of exotic zero-days, but because of forgotten legacy assets that attackers can exploit with decade-old public tooling. The organizations that weather this campaign will be the ones with accurate asset inventories, egress visibility from application servers, and the discipline to treat a KEV addition — regardless of CVE vintage — as an emergency, not a backlog item.
Related Resources
Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.