Scope Injection in CFML
By Pete Freitag
Here is an interesting vulnerability that I have come across several times in real CFML code during code reviews, I have spoken about it at conferences but have never written about it. Since it doesn't really have a name, I call it Scope Injection, you'll see why in a minute.
We have the following code:
<cfif session.isAdmin> Do something only an admin can do... </cfif>
Now lets suppose that this session.isAdmin
is set upon a successful authentication, but for unauthenticated sessions isAdmin
is undefined in the session
scope (onSessionStart does not initialize it).
Now suppose a request to the above code like this:
/admin/something.cfm?session.isAdmin=1
What happens when the above code example is run:
- CF checks to see if
session.isAdmin
is defined in thesession
scope - The variable
session.isAdmin
was not defined in thesession
scope, so it starts searching other scopes, such as theurl
scope. - CF finds
url.session.isAdmin
defined and uses that value to evaluate the if statement astrue
. - Code that should only be executed by an admin can actually be executed by anyone.
Mitigating Scope Injection in CFML
To mitigate this, you should make sure that variables are initialized properly, a good place to do this is in your Application.cfc event lifecycle methods, onSessionStart
for session scoped variables, onApplicationStart
for application scoped variables, onRequestStart
for request scope variables, etc.
So to mitigate this issue, we simply need this:
<cffunction name="onSessionStart"> <cfset session.isAdmin = false> </cffunction>
If you are extra paranoid you can also use StructKeyExists
to make sure the variable is defined:
<cfif StructKeyExists(session, "isAdmin") AND session.isAdmin> do admin stuff </cfif>
ColdFusion 2016 Enhancement
The ColdFusion 2016 release added a new Application.cfc
level setting this.searchImplicitScopes
which defaults to true
for backwards compatibility. If you set it to false
it will only search the variables
, local
and arguments
scopes when a scope is unspecified on a variable.
Scope Injection in Railo / Lucee
This particular example is not vulnerable in the version of Railo / Lucee I tested, apparently because it does not allow cascading on builtin scopes. You can still have a scope injection issue on variables that are not in a builtin scope, consider this:
<cfif IsUserInRole("admin") OR IsUserInRole("superuser")> <cfset isAdmin = true> </cfif> <cfif isAdmin> do admin stuff </cfif>
There is also a setting in the Railo / Lucee administrator that allows you to turn off cascading (under scopes) by setting it to strict
. You can also do this in your Application.cfc
:
this.scopeCascading = "strict";
When the scopeCascading
setting is set to strict
it removes the possibility of a scope injection vulnerability, and may also improve performance.
How FuseGuard protects from Scope Injection
FuseGuard customers have been enjoying protection from scope injection for the past 3 years. It operates in a strict mode by default which prevents inputs like url.one.two
, with strict mode off it only looks at valid scope names (like session, application, etc).
As of version 2.3 you can also set a prefix to ignore, for example fusebox apps commonly have url's like ?fusebox.action=foo
so you can tell FuseGuard to allow that by adding:
filter.setIgnorePrefixList("fusebox");
You can also ignore a variable a-la-carte like this:
filter.ignoreVariable("url", "one.two");
Scope Injection in CFML was first published on March 03, 2015.
If you like reading about security, cfml, coldfusion, railo, lucee, session, or fuseguard then you might also like:
- Fixinator and Foundeo Security Bundle
- OpenSSL and ColdFusion / Lucee / Tomcat
- Spring4Shell and ColdFusion
- Log4j CVE-2021-44228 Log4Shell Vulnerability on ColdFusion / Lucee
The FuseGuard Web Application Firewall for ColdFusion & CFML is a high performance, customizable engine that blocks various attacks against your ColdFusion applications.
I was skeptical that Adobe ColdFusion would behave in such a flawed manner. So I whipped up a little demonstration:
https://github.com/ecivis/miniapp
Sure enough, ACF 10 is vulnerable, exactly as you wrote above. I tried the miniapp in Railo 4.2.1.008 with strict scope cascading enabled, and it worked as expected.
Thanks for the post.