Join our Newsletter — 33% off our NHI Course
Home› Guides› Apache Struts Security: Patch, Harden OGNL and Retire…
Guide Application Security

Apache Struts Security: Patch, Harden OGNL and Retire Struts 1

PDF for newsletter subscribers · free to read online

← All guides
By NHI Mgmt Group, edited by Lalit Choda Updated 8 November 2026 13 min read
On this page

Securing an Apache Struts application comes down to three customer-side habits: keep internet-facing actions to a minimum, run a supported framework version with security updates applied, and lock down how request data reaches the OGNL expression language. Long-lived Struts applications need the same patching discipline as new ones. This guide covers how authentication and authorisation actually work around a Struts application, the configuration constants that close off OGNL injection, how to treat the REST, JSON and Config Browser plugins, what to log and detect, and how to plan an exit from end-of-life branches including Struts 1. It is written for Java developers, application security engineers and the operations teams who own legacy Struts estates. For general Java guidance see the Java and Spring Security Guide; this page stays on Struts.

This is an independent guide from NHI Mgmt Group, based on the Apache Struts project's public documentation as of November 2026. It is not sponsored or reviewed by the Apache Struts project. Product features change, so confirm settings against the Apache Struts project's current documentation.

Key takeaways

  • Version is the first control. As of November 2026 the supported lines are Struts 7.x (current 7.4.0, Java 17 and Jakarta EE) and Struts 6.x (current 6.12.0, Java 8); 2.5.x, 2.3.x and 1.x are end of life and get no fixes.
  • OGNL is the recurring attack surface. Most critical Struts bulletins are expression injection or parameter binding flaws, so turn on the allowlist, require @StrutsParameter annotations and keep the excluded class lists intact.
  • Struts does not authenticate users. The servlet container, a filter or a separate framework does, usually by URL pattern, which is why mixing access levels in one namespace and exposing JSPs directly break authorisation.
  • File upload code needs a rewrite, not just an upgrade. Current releases use the Action File Upload mechanism, and moving to it is not backward compatible.
  • Patch speed and detection both failed at Equifax. GAO found an out-of-date notification list, a scan that missed the vulnerable portal and an expired certificate that blinded traffic inspection for about ten months.

How identity and access work in Apache Struts

Struts is an MVC framework, not an identity product. It maps HTTP requests to action classes through an interceptor stack and renders results, usually JSP or FreeMarker templates. Who the user is and what they may reach is decided elsewhere, and the gaps between those layers are where access control fails.

LayerWhat it decidesTypical mechanismStruts-specific risk
Servlet containerAuthentication, coarse authorisation by URLweb.xml <security-constraint>, container realms, SSO agentsURL patterns protect a namespace, so an admin action in a public namespace is public
Servlet filter or security frameworkAuthentication, session, CSRF, role checksSpring Security, Apache Shiro, a corporate SSO filter in front of the Struts filterFilter order: the security filter must run before StrutsPrepareAndExecuteFilter
Interceptor stackPer-action checksRoles interceptor, custom authorisation interceptorsCustom interceptors left out of one package's stack silently skip checks
Action and parameter bindingWhich request values reach Java objectsParameters interceptor, @StrutsParameter, accepted and excluded patternsUnannotated setters and getters let attackers set fields you never meant to expose
ViewsWhat is renderedJSP, FreeMarker, Struts tagsJSPs reachable directly bypass the action and its checks

The Struts security guideline gives two rules that follow from this design:

  • Group actions by security level: because access is commonly enforced by URL pattern (for example /secure/* requiring role admin), never mix actions with different access levels in the same namespace.
  • Never expose JSP files directly: keep JSPs under WEB-INF and add a *.jsp security constraint mapped to a role that no user holds. The project recommends both. Since Struts 7.2.0 the framework logs a security warning when JSP tags are used outside an action scope, which helps find exposed pages.
  • Disable empty namespace fallback: set struts.actionConfig.fallbackToEmptyNamespace=false so actions in the default namespace cannot be reached through other paths.

Admin roles and privileged access

Privileged access to a Struts application comes in three forms: framework features that expose internals, administrative actions inside the application, and the accounts that deploy and run it.

  • devMode: development mode relaxes behaviour and exposes debugging. The guideline is explicit that production struts.xml must set <constant name="struts.devMode" value="false" />. Treat any production build with devMode true as a release blocker.
  • Config Browser Plugin: it exposes the internal configuration and is meant for development only. Remove the jar from production builds; if a team insists, put it behind authentication as the project advises.
  • Dynamic Method Invocation: set struts.enable.DynamicMethodInvocation=false and use Strict Method Invocation so only declared methods can be called on an action.
  • Administrative actions: place them in their own namespace with their own security constraint and interceptor stack, require step-up authentication for destructive operations, and review them separately in penetration tests.
  • Deployment and runtime accounts: the application server should run as a dedicated non-root account with write access only to log and temp directories. A Struts remote code execution flaw runs code with exactly that account's rights, so the account boundary is your blast radius. Manager consoles of the container (Tomcat Manager, WebLogic console) should never be reachable from the internet.

Patching and version support

Struts security is dominated by framework vulnerabilities, so version management deserves its own section. The project publishes security bulletins (S2-nnn) on its wiki and announcements on struts.apache.org, and reports go privately to [email protected].

BranchStatus (checked 8 Nov 2026)PlatformWhat it means for you
7.xSupported, 7.4.0 released 2 October 2026Java 17, Jakarta EETarget line; parameter annotations required and OGNL allowlist enabled by default
6.xSupported, 6.12.0 released 2 October 2026Java 8, Servlet API 3.1Stepping stone; enable annotations and allowlist yourself
2.5.xEnd of life (announced 30 October 2023)javaxNo fixes; migrate
2.3.xEnd of life since 12 September 2019javaxNo fixes; migrate
1.xEnd of life since 5 April 2013; last release 1.3.10 in December 2008javaxNo fixes and no drop-in replacement; a rewrite project

Apply Struts security updates promptly and follow the Apache Struts security bulletins. If you do not accept XML in the REST plugin, remove the XStream handler. See the Emergency Out-of-Band Patching Playbook.

Integrations, API tokens and service accounts

A Struts application is rarely alone. It holds credentials for databases, directories and downstream APIs, and its plugins open extra request formats. An attacker who achieves code execution inherits all of them, which is what turned the Equifax portal into a route to other databases.

  • Datasource and API credentials: keep them out of struts.properties, struts.xml and WAR files. Use container-managed JNDI datasources or a secrets manager, scope each database account to the tables the application needs, and rotate after any suspected compromise. See the Secrets Management Guide.
  • REST plugin: limit content type handlers to what you need; S2-052 showed the risk of an XML handler nobody used. Apply authentication and rate limits as you would for any API.
  • JSON plugin: the 2026 bulletins on unbounded body reads and shared parsing state mean the plugin must be current. Put request size limits in front of it at the proxy.
  • Legacy RESTful action mapper: if configured, upgrade for S2-075 and confirm the allowlist is on.
  • Outbound calls: restrict egress from application servers to known destinations so a compromised action cannot freely reach the internet or cloud metadata endpoints.

Hardening baseline

These constants come from the Struts security guideline. Set them in struts.xml or struts.properties, and extend lists rather than shrinking them: the project warns against reducing the default excluded classes.

SettingRecommended valueWhy
struts.devModefalseNo debug behaviour in production
struts.parameters.requireAnnotationstrue (available from 6.4, default from 7.0)Only fields marked @StrutsParameter accept request values; use depth for nested objects
struts.parameters.requireAnnotations.transitionModetrue only while migratingRequires annotations for nested parameters while leaving public setters exposed
struts.allowlist.enabletrue (with struts.allowlist.classes and struts.allowlist.packageNames as needed)Classes used in OGNL must be allowlisted as well as not excluded
struts.excludedClasses, struts.excludedPackageNames, struts.excludedPackageNamePatternsDefaults, extendedBlock reflection and runtime classes from expressions
struts.ognl.valueStackFallbackToContextfalseStops expressions reaching the ActionContext
struts.ognl.excludedNodeTypesConfigure (OGNL Guard, off by default)Forbids chosen syntax nodes, mitigating string concatenation tricks
struts.ognl.expressionMaxLengthDefault 256 or lowerLong injected expressions are refused
struts.ognl.allowStaticFieldAccessfalseNon-primitive static fields can reach dangerous objects
struts.disallowProxyObjectAccess, struts.disallowDefaultPackageAccess, struts.ognl.disallowCustomOgnlMaptrueClose known bypass routes
struts.enable.DynamicMethodInvocationfalseOnly declared methods are callable
struts.actionConfig.fallbackToEmptyNamespacefalseNo cross-namespace action resolution

Code-level rules from the same guideline: do not define setters that are not needed; never feed incoming values into localisation logic or forced OGNL evaluation (%{...}); prefer Struts tags to raw EL; define custom error pages so stack traces do not leak; and use the FetchMetadata, COOP and COEP interceptors for browser-side isolation. Validate input with the validation framework, but remember validation does not fix an injectable expression.

Rolling out hardening and upgrades

  1. Inventory: find every Struts application, including vendor products that embed it. Look for struts2-core and struts-core (Struts 1) jars in WAR files and SBOMs, and record version, internet exposure and owner. See the SBOM Guide.
  2. Triage by exposure: internet-facing applications on 2.x or 1.x come first; put them behind authentication or a WAF virtual patch while you work, accepting that a WAF is a delay, not a fix.
  3. Upgrade within supported lines: move 6.x to the latest 6.x release, then plan 7.x (Java 17 and the jakarta.* namespace are the real effort).
  4. Enable annotations in transition mode: on 6.4 or later turn on requireAnnotations with transitionMode, add @StrutsParameter to legitimate fields, then switch transition mode off.
  5. Enable the allowlist in a test environment: run the regression suite and watch logs for blocked class warnings, adding only what the application genuinely needs.
  6. Rewrite file upload actions to the Action File Upload mechanism and test traversal cases explicitly.
  7. Roll back safely: deploy as a new versioned artefact behind a load balancer so you can revert the artefact, but do not roll back to a version missing security updates; revert configuration constants one at a time instead.
  8. Struts 1 and 2.3/2.5: treat as a migration project with a dated plan and an interim compensating control set (isolation, WAF, authentication in front, aggressive monitoring). Extended commercial support exists for EOL branches; the Apache Software Foundation does not endorse any offering.

Logging and detection

Exploitation of Struts usually looks like T1190 Exploit Public-Facing Application followed by command execution or a web shell (T1505.003). Detection should cover the request, the JVM and the host.

SignalWhereWhat to look for
OGNL syntax in requestsReverse proxy, WAF, access logs%{, ${, #context, @java.lang in headers (especially Content-Type), parameter names or filenames
Framework warningsApplication logExcluded or non-allowlisted class warnings, parameter rejection messages, direct JSP access warnings (7.2.0+)
Child processesEDR or process auditing on app serversThe Java process spawning shells, curl, wget or scripting interpreters
New files in web rootsFile integrity monitoringJSP or class files appearing outside deployments
Unusual egressFirewall, proxy, DNSApp servers contacting new hosts; large outbound transfers from database tiers

Equifax's own detection failed because an expired certificate stopped encrypted traffic inspection for about ten months, according to GAO. Monitor the health of your monitoring: certificate expiry on inspection devices, log source silence and agent coverage. See the Web Shell Response Playbook.

Metrics that show it is working:

  • Percentage of Struts applications on a supported branch and its latest release.
  • Median days from a Struts bulletin to production deployment, tracked separately for Critical bulletins.
  • Number of applications with requireAnnotations and allowlist.enable on.
  • Count of Struts 1, 2.3 and 2.5 applications still running, trending to zero against a dated plan.
  • Coverage of app servers by process monitoring and file integrity monitoring.

Common misconfigurations

  • Notification that reaches nobody: GAO found that Equifax circulated the March 2017 US-CERT notice using an out-of-date recipient list, so the people who would have patched never received it. Map every Struts application to a current owner.
  • Scanning that misses the asset: a scan about a week later did not detect the vulnerable portal. Pair network scanning with software composition analysis of the deployed artefacts.
  • Upgrading but keeping the deprecated upload interceptor: S2-067 stays exploitable on a patched version if actions still use FileUploadInterceptor.
  • Shrinking the excluded class lists to make a feature work, reopening the classes that OGNL exploits rely on.
  • Admin actions in a public namespace or JSPs reachable directly, bypassing URL-based security constraints.
  • devMode or the Config Browser Plugin shipped to production because the build profile was never split.

Framework mapping

Control areaNIST SP 800-53 Rev 5NIST CSF 2.0Other
Patch Struts and dependenciesSI-2 Flaw Remediation, RA-5ID.RA-01, PR.PS-02CIS Control 7; ISO/IEC 27001:2022 A.8.8
Retire EOL branchesSA-22 Unsupported System ComponentsPR.PS-02CIS Control 2
Hardening constants and plugin removalCM-6, CM-7PR.PS-01ISO/IEC 27001:2022 A.8.9
Parameter binding and input handlingSI-10PR.PS-01CIS Control 16; ISO/IEC 27001:2022 A.8.28
Namespace and JSP access controlAC-3, AC-6PR.AA-05OWASP ASVS 5.0
Exploit and web shell detectionAU-6DE.CM-09ATT&CK T1190, T1505.003

Practitioner checklist

  • Inventory every Struts application and embedded copy with version, owner and exposure.
  • Move all applications to the latest 7.x or 6.x release; set a dated plan for every 2.x and 1.x application.
  • Set struts.devMode=false and remove the Config Browser Plugin from production builds.
  • Enable struts.parameters.requireAnnotations and struts.allowlist.enable, and keep excluded class lists at defaults or larger.
  • Disable Dynamic Method Invocation, empty namespace fallback and static field access.
  • Rewrite file uploads to the Action File Upload mechanism and remove unused REST handlers.
  • Keep JSPs under WEB-INF, add a *.jsp deny constraint and group actions by access level.
  • Move datasource and API credentials into a secrets manager with least-privilege database accounts.
  • Alert on Java processes spawning shells, new JSP files in web roots and OGNL syntax in requests.
  • Subscribe owners to Struts announcements and track bulletin-to-deploy time, prioritising Critical bulletins.

Standards and references

Related NHI Mgmt Group resources: Java and Spring Security Guide · Patch Management Guide · Web Application Firewall Guide · Secure Software Development Lifecycle (SSDLC) Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Researched and written by the NHI Mgmt Group editorial team using AI tools, under the editorial direction of Lalit Choda. Facts are drawn from the sources listed on this page and checked by our automated quality process. Last updated 8 November 2026. Spotted an error? Use our contact page.
NHI Mgmt Group, the independent authority on Non-Human Identity, IAM and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.