anchor.diff:  		<cfargument required="true" name="codec" hint="org.owasp.esapi.codecs.Codec"/>
   
   		<cfscript>
  +			// CF8 requires 'var' at the top
  +			var i = "";
  +			var param = "";
  +			var command = "";
  +			var process = "";
  +			var output = "";
  +			var errors = "";
  +
   			try {
  -				if (this.ESAPI4JVERSION == 2) {
  -					return variables.executor.executeSystemCommand(arguments.executable, arguments.params, arguments.workdir, arguments.codec, false, false);
  +				variables.logger.warning(getSecurityType("SECURITY_SUCCESS"), true, "Initiating executable: " & arguments.executable & " " & arrayToList(arguments.params, " ") & " in " & arguments.workdir);
  +
  +				// command must exactly match the canonical path and must actually exist on the file system
  +				// using equalsIgnoreCase for Windows, although this isn't quite as strong as it should be
  +				if(!arguments.executable.getCanonicalPath().equalsIgnoreCase(arguments.executable.getPath())) {
  +					throwException(createObject("component", "org.owasp.esapi.errors.ExecutorException").init(variables.ESAPI, "Execution failure", "Invalid path to executable file: " & arguments.executable));
   				}
  -				else {
  -					return variables.executor.executeSystemCommand(arguments.executable, arguments.params, arguments.workdir, arguments.codec);
  +				if(!arguments.executable.exists()) {
  +					throwException(createObject("component", "org.owasp.esapi.errors.ExecutorException").init(variables.ESAPI, "Execution failure", "No such executable: " & arguments.executable));
   				}
  +
  +				// escape any special characters in the parameters
  +				for(i = 1; i <= arrayLen(arguments.params); i++) {
  +					param = arguments.params[i];
  +					arguments.params[i] = variables.ESAPI.encoder().encodeForOS(arguments.codec, param);
  +				}
  +
  +				// working directory must exist
  +				if(!arguments.workdir.exists()) {
  +					throwException(createObject("component", "org.owasp.esapi.errors.ExecutorException").init(variables.ESAPI, "Execution failure", "No such working directory for running executable: " & arguments.workdir.getPath()));
  +				}
  +
  +				arrayPrepend(arguments.params, arguments.executable.getCanonicalPath());
  +				command = arguments.params;
  +				process = newJava("java.lang.Runtime").getRuntime().exec(javaCast("string[]", command), javaCast("string[]", arrayNew(1)), arguments.workdir);
  +				// Future - this is how to implement this in Java 1.5+
  +				// ProcessBuilder pb = new ProcessBuilder(arguments.params);
  +				// Map env = pb.environment();
  +				// Security check - clear environment variables!
  +				// env.clear();
  +				// pb.directory(arguments.workdir);
  +				// pb.redirectErrorStream(true);
  +				// Process process = pb.start();
  +				output = readStream(process.getInputStream());
  +				errors = readStream(process.getErrorStream());
  +				if(errors != "" && errors.length() > 0) {
  +					variables.logger.warning(getSecurityType("SECURITY_FAILURE"), false, "Error during system command: " & errors);
  +				}
  +				variables.logger.warning(getSecurityType("SECURITY_SUCCESS"), true, "System command complete: " & arrayToList(arguments.params, " "));
  +				return output;
   			}
  -			catch (org.owasp.esapi.errors.ExecutorException e) {
  -				throwException(createObject("component", "org.owasp.esapi.errors.ExecutorException").init(variables.ESAPI, e.getUserMessage(), e.getLogMessage(), e));
  +			catch(java.lang.Exception e) {
  +				throwException(createObject("component", "org.owasp.esapi.errors.ExecutorException").init(variables.ESAPI, "Execution failure", "Exception thrown during execution of system command: " & e.getMessage(), e));
   			}
   		</cfscript>
   
   	</cffunction>
   
  +	<cffunction access="private" returntype="String" name="readStream" output="false"
  +	            hint="readStream reads lines from an input stream and returns all of them in a single string">
  +		<cfargument required="true" name="is" hint="input stream to read from"/>
  +
  +		<cfscript>
  +			var isr = newJava("java.io.InputStreamReader").init(arguments.is);
  +			var br = newJava("java.io.BufferedReader").init(isr);
  +			var sb = newJava("java.lang.StringBuffer").init();
  +			var line = br.readLine();
  +			while(isDefined("line") && !isNull(line)) {
  +				sb.append(line & "\n");
  +				line = br.readLine();
  +			}
  +			return sb.toString();
  +		</cfscript>
  +
  +	</cffunction>
  +
   </cfcomponent>
positive.code: 
  	<cfscript>
  		variables.ESAPI = "";
  		variables.executor = "";
  	</cfscript>
  
  	<cffunction access="public" returntype="org.owasp.esapi.Executor" name="init" output="false">
  
negative.code: 
  		<cfscript>
  			variables.ESAPI = arguments.ESAPI;
  			variables.logger = variables.ESAPI.getLogger("Executor");
  
  			return this;
  		</cfscript>
  