Status/Resolution/Reason: To Fix//BugReVerified
Reporter/Name(from Bugbase): Aaron Neff / ()
Created: 08/17/2018
Components: Language, Closures
Versions: 2018
Failure Type: Enhancement Request
Found In Build/Fixed In Build: 2018.0.0.310739 /
Priority/Frequency: Normal / Some users will encounter
Locale/System: / Platforms All
Vote Count: 0
Issue: unscopable variables create closure vulnerability
*Example 1:*
-----------
{code:java}
function function set2D(numeric xAxis=0, numeric yAxis=0) {
return function(numeric zAxis=0) {
return "(#xAxis#,#yAxis#,#ARGUMENTS.zAxis#)"
}
}
get3D=set2D(xAxis=1, yAxis=2)
get3D(xAxis=3)//typo: 'x' should be 'z'
{code}
-----------
*Issue 1:* _If innocent user makes a typo and calls `get3D(xAxis=3)`, instead of `get3D(zAxis=3)`, there is silent corruption._
*Example 2* (where isPrivileged() and secretNumberGenerator() were converted to java bytecode via cfcompile's Sourceless Distribution):
-----------
//Begin sourceless distributed code
{code:java}
boolean function isPrivileged() {return false}//pseudo code for illustration
function function secretNumberGenerator() {
var isPrivileged = isPrivileged()
return function() {return isPrivileged ? randRange(1,1000) : 0}
}
//End sourceless distributed code
getSecretNumber=secretNumberGenerator()
writeOutput(getSecretNumber(isPrivileged=true))//hacker discovers and exploits unscoped variable named isPrivileged
{code}
-----------
*Issue 2:* _Hackers can discover unscoped variable names in sourceless-deployed closures by passing arbitrary arguments when calling the closure._
Enhancement Request 1: New function-local scopes 'OWNERARGUMENTS' and 'OWNERLOCAL', allowing child functions to scope references to variables in owner function's scopes. This would also allow callbacks (ex: array.map(callback)) to scope their references to variables in the owner function's scopes without hacky workarounds.
Then both closure return statements could be rewritten:
- Example 1: `return "(#OWNERARGUMENTS.xAxis#,#OWNERARGUMENTS.yAxis#,#ARGUMENTS.zAxis#)"`
- Example 2: `return OWNERLOCAL.isPrivileged ? randRange(1,1000) : 0`
However, hackers could still discover/exploit unscoped variables by passing arbitrary keys in a OWNERLOCAL struct.
- Example 2: `writeOutput(getSecretNumber(OWNERLOCAL={isPrivileged=true}))`
Enhancement Request 2: Per-app setting THIS.enableScopeShadowing=true(default)|false. THIS.enableScopeShadowing=false would disable CF's scope shadowing and, thus, prevent hackers from working around Enhancement Request 1.
Related URL: https://docs.lucee.org/guides/developing-with-lucee-server/language-syntax-differences.html#scope-names-cannot-be-overwritten
Attachments:
Comments: