diff --git a/src/main/java/org/nrg/xapi/rest/settings/AutomationApi.java b/src/main/java/org/nrg/xapi/rest/settings/AutomationApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..f44c50c0b8ce440868217d71de0de1f360207e9b
--- /dev/null
+++ b/src/main/java/org/nrg/xapi/rest/settings/AutomationApi.java
@@ -0,0 +1,129 @@
+package org.nrg.xapi.rest.settings;
+
+import io.swagger.annotations.*;
+import org.nrg.framework.annotations.XapiRestController;
+import org.nrg.prefs.exceptions.InvalidPreferenceName;
+import org.nrg.xdat.rest.AbstractXapiRestController;
+import org.nrg.xdat.security.services.RoleHolder;
+import org.nrg.xdat.security.services.UserManagementServiceI;
+import org.nrg.xnat.preferences.AutomationPreferences;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+import java.util.Map;
+
+@Api(description = "Automation Service API")
+@XapiRestController
+@RequestMapping(value = "/automation")
+public class AutomationApi extends AbstractXapiRestController {
+    @Autowired
+    public AutomationApi(final AutomationPreferences preferences, final UserManagementServiceI userManagementService, final RoleHolder roleHolder) {
+        super(userManagementService, roleHolder);
+        _preferences = preferences;
+    }
+
+    @ApiOperation(value = "Returns the full map of automation settings for this XNAT application.", notes = "Complex objects may be returned as encapsulated JSON strings.", response = String.class, responseContainer = "Map")
+    @ApiResponses({@ApiResponse(code = 200, message = "Automation settings successfully retrieved."),
+                   @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
+                   @ApiResponse(code = 403, message = "Insufficient privileges to retrieve the requested setting."),
+                   @ApiResponse(code = 500, message = "An unexpected error occurred.")})
+    @RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
+    public ResponseEntity<Map<String, Object>> getAllAutomationPreferences() {
+        if (_log.isDebugEnabled()) {
+            _log.info("User " + getSessionUser().getUsername() + " requested the system automation settings.");
+        }
+
+        final HttpStatus status = isPermitted();
+        if (status != null) {
+            return new ResponseEntity<>(status);
+        }
+
+        return new ResponseEntity<>(_preferences.getPreferenceMap(), HttpStatus.OK);
+    }
+
+    @ApiOperation(value = "Sets a map of automation properties.", notes = "Sets the automation properties specified in the map.", response = Void.class)
+    @ApiResponses({@ApiResponse(code = 200, message = "Automation properties successfully set."),
+                   @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
+                   @ApiResponse(code = 403, message = "Not authorized to set automation properties."),
+                   @ApiResponse(code = 500, message = "An unexpected error occurred.")})
+    @RequestMapping(consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE}, method = RequestMethod.POST)
+    public ResponseEntity<Void> setBatchAutomationPreferences(@ApiParam(value = "The map of automation preferences to be set.", required = true) @RequestBody final Map<String, String> properties) {
+        if (_log.isDebugEnabled()) {
+            _log.info("User " + getSessionUser().getUsername() + " requested to set a batch of automation preferences.");
+        }
+
+        final HttpStatus status = isPermitted();
+        if (status != null) {
+            return new ResponseEntity<>(status);
+        }
+
+        // Is this call initializing the system?
+        for (final String name : properties.keySet()) {
+            try {
+                _preferences.set(properties.get(name), name);
+                if (_log.isInfoEnabled()) {
+                    _log.info("Set property {} to value: {}", name, properties.get(name));
+                }
+            } catch (InvalidPreferenceName invalidPreferenceName) {
+                _log.error("Got an invalid preference name error for the preference: {}, failed to set value to: {}", name, properties.get(name));
+            }
+        }
+
+        return new ResponseEntity<>(HttpStatus.OK);
+    }
+
+    @ApiOperation(value = "Returns whether internal scripting is enabled for this XNAT application.", notes = "Internal scripting may be used by XNAT itself even when disabled, but this setting indicates whether users and administrators can configure and execute scripts internally to the application process. Access to this setting is restricted to site administrators.", response = Boolean.class)
+    @ApiResponses({@ApiResponse(code = 200, message = "Internal scripting setting successfully retrieved."),
+                   @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
+                   @ApiResponse(code = 403, message = "Insufficient privileges to retrieve the requested setting."),
+                   @ApiResponse(code = 500, message = "An unexpected error occurred.")})
+    @RequestMapping(value = "enabled", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
+    public ResponseEntity<Boolean> isInternalScriptingEnabled() {
+        if (_log.isDebugEnabled()) {
+            _log.debug("User " + getSessionUser().getUsername() + " requested the internal scripting enabled setting.");
+        }
+
+        final HttpStatus status = isPermitted();
+        if (status != null) {
+            return new ResponseEntity<>(status);
+        }
+
+        return new ResponseEntity<>(_preferences.isInternalScriptingEnabled(), HttpStatus.OK);
+    }
+
+    @ApiOperation(value = "Sets the internal scripting enabled flag for this XNAT application to the submitted value.", notes = "Internal scripting may be used by XNAT itself even when disabled, but this setting indicates whether users and administrators can configure and execute scripts internally to the application process. Access to this setting is restricted to site administrators.", response = Boolean.class)
+    @ApiResponses({@ApiResponse(code = 200, message = "Internal scripting setting successfully set."),
+                   @ApiResponse(code = 401, message = "Must be authenticated to access the XNAT REST API."),
+                   @ApiResponse(code = 403, message = "Insufficient privileges to change the requested setting."),
+                   @ApiResponse(code = 500, message = "An unexpected error occurred.")})
+    @RequestMapping(value = "enabled/{setting}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.PUT)
+    public ResponseEntity<Boolean> setInternalScriptingEnabled(@PathVariable("setting") final boolean setting) {
+        if (_log.isDebugEnabled()) {
+            _log.warn("User {} requested to change the internal scripting enabled setting to {}.", getSessionUser().getUsername(), setting);
+        }
+
+        final HttpStatus status = isPermitted();
+        if (status != null) {
+            return new ResponseEntity<>(status);
+        }
+
+        // Only change the setting if they're different.
+        if (_preferences.isInternalScriptingEnabled() != setting) {
+            _preferences.setInternalScriptingEnabled(setting);
+        }
+
+        return new ResponseEntity<>(_preferences.isInternalScriptingEnabled(), HttpStatus.OK);
+    }
+
+    private static final Logger _log = LoggerFactory.getLogger(AutomationApi.class);
+
+    private final AutomationPreferences _preferences;
+}
diff --git a/src/main/java/org/nrg/xnat/configuration/ApplicationConfig.java b/src/main/java/org/nrg/xnat/configuration/ApplicationConfig.java
index 8d3a1e5d8a952bc9144164497ca0b17b53f709de..e20b4195d38352a945081d1d87722da608b7ea24 100644
--- a/src/main/java/org/nrg/xnat/configuration/ApplicationConfig.java
+++ b/src/main/java/org/nrg/xnat/configuration/ApplicationConfig.java
@@ -14,7 +14,7 @@ import org.nrg.xdat.services.ThemeService;
 import org.nrg.xdat.services.impl.ThemeServiceImpl;
 import org.nrg.xnat.initialization.InitializingTask;
 import org.nrg.xnat.initialization.InitializingTasksExecutor;
-import org.nrg.xnat.restlet.XnatRestlet;
+import org.nrg.xnat.preferences.AutomationPreferences;
 import org.nrg.xnat.restlet.XnatRestletExtensions;
 import org.nrg.xnat.restlet.XnatRestletExtensionsBean;
 import org.nrg.xnat.restlet.actions.importer.ImporterHandlerPackages;
@@ -28,12 +28,14 @@ import java.util.HashSet;
 import java.util.List;
 
 @Configuration
-@ComponentScan({"org.nrg.automation.repositories", "org.nrg.config.daos", "org.nrg.dcm.xnat", "org.nrg.dicomtools.filters",
-                "org.nrg.framework.datacache.impl.hibernate", "org.nrg.framework.services.impl", "org.nrg.notify.daos",
-                "org.nrg.prefs.repositories", "org.nrg.xdat.daos", "org.nrg.xdat.services.impl.hibernate", "org.nrg.xft.daos",
-                "org.nrg.xft.event.listeners", "org.nrg.xft.services", "org.nrg.xnat.configuration", "org.nrg.xnat.daos",
-                "org.nrg.xnat.event.listeners", "org.nrg.xnat.helpers.merge", "org.nrg.xnat.initialization.tasks",
-                "org.nrg.xnat.services.impl.hibernate", "org.nrg.xnat.spawner.repositories", "org.nrg.automation.daos"})
+@ComponentScan({"org.nrg.automation.daos", "org.nrg.automation.repositories", "org.nrg.config.daos", "org.nrg.dcm.xnat",
+                "org.nrg.dicomtools.filters", "org.nrg.framework.datacache.impl.hibernate",
+                "org.nrg.framework.services.impl", "org.nrg.notify.daos", "org.nrg.prefs.repositories",
+                "org.nrg.xdat.daos", "org.nrg.xdat.services.impl.hibernate", "org.nrg.xft.daos",
+                "org.nrg.xft.event.listeners", "org.nrg.xft.services", "org.nrg.xnat.configuration",
+                "org.nrg.xnat.daos", "org.nrg.xnat.event.listeners", "org.nrg.xnat.helpers.merge",
+                "org.nrg.xnat.initialization.tasks", "org.nrg.xnat.services.impl.hibernate",
+                "org.nrg.xnat.spawner.repositories"})
 @Import({FeaturesConfig.class, ReactorConfig.class})
 @ImportResource("WEB-INF/conf/mq-context.xml")
 public class ApplicationConfig {
@@ -57,6 +59,11 @@ public class ApplicationConfig {
         return new NotificationsPreferences(service);
     }
 
+    @Bean
+    public AutomationPreferences automationPreferences(final NrgEventService service) {
+        return new AutomationPreferences(service);
+    }
+
     @Bean
     public PETTracerUtils petTracerUtils(final ConfigService configService) throws Exception {
         return new PETTracerUtils(configService);
diff --git a/src/main/java/org/nrg/xnat/preferences/AutomationPreferences.java b/src/main/java/org/nrg/xnat/preferences/AutomationPreferences.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e1f88846ef049f1e2aeb7fdbe083220059b90bd
--- /dev/null
+++ b/src/main/java/org/nrg/xnat/preferences/AutomationPreferences.java
@@ -0,0 +1,39 @@
+package org.nrg.xnat.preferences;
+
+import org.nrg.framework.services.NrgEventService;
+import org.nrg.prefs.annotations.NrgPreference;
+import org.nrg.prefs.annotations.NrgPreferenceBean;
+import org.nrg.prefs.exceptions.InvalidPreferenceName;
+import org.nrg.xdat.preferences.EventTriggeringAbstractPreferenceBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+@NrgPreferenceBean(toolId = AutomationPreferences.AUTOMATION_TOOL_ID,
+                   toolName = "XNAT Automation Preferences",
+                   description = "Manages preferences and settings for the XNAT automation services.",
+                   properties = "META-INF/xnat/preferences/automation.properties",
+                   strict = false)
+public class AutomationPreferences extends EventTriggeringAbstractPreferenceBean {
+    public static final String AUTOMATION_TOOL_ID = "automation";
+
+    @Autowired
+    public AutomationPreferences(final NrgEventService eventService) {
+        super(eventService);
+    }
+
+    @NrgPreference(defaultValue = "true")
+    public boolean isInternalScriptingEnabled() {
+        return getBooleanValue("internalScriptingEnabled");
+    }
+
+    public void setInternalScriptingEnabled(final boolean internalScriptingEnabled) {
+        try {
+            setBooleanValue(internalScriptingEnabled, "internalScriptingEnabled");
+        } catch (InvalidPreferenceName e) {
+            _log.error("Invalid preference name internalScriptingEnabled: something is very wrong here.", e);
+        }
+    }
+
+    private static final Logger _log = LoggerFactory.getLogger(AutomationPreferences.class);
+}
diff --git a/src/main/java/org/nrg/xnat/restlet/resources/SecureResource.java b/src/main/java/org/nrg/xnat/restlet/resources/SecureResource.java
index ab66f40b14bd3c90299eb2d8c2444b57f2b41f8e..8d2adf27114af9da1f4999fac872bba6e96b65b6 100644
--- a/src/main/java/org/nrg/xnat/restlet/resources/SecureResource.java
+++ b/src/main/java/org/nrg/xnat/restlet/resources/SecureResource.java
@@ -1544,7 +1544,7 @@ public abstract class SecureResource extends Resource {
 
     protected final static TypeReference<ArrayList<String>> TYPE_REFERENCE_LIST_STRING = new TypeReference<ArrayList<String>>() {};
 
-    private static Map<String, List<FilteredResourceHandlerI>> handlers = Maps.newConcurrentMap();
+    private static final Map<String, List<FilteredResourceHandlerI>> handlers = Maps.newConcurrentMap();
 
     /**
      * Get a list of the possible handlers.  This allows additional handlers to be injected at a later date or via a module.
@@ -1555,19 +1555,21 @@ public abstract class SecureResource extends Resource {
      */
     public static List<FilteredResourceHandlerI> getHandlers(String _package, List<FilteredResourceHandlerI> _defaultHandlers) throws InstantiationException, IllegalAccessException {
         if (handlers.get(_package) == null) {
-            handlers.put(_package, _defaultHandlers);
+            synchronized (handlers) {
+                handlers.put(_package, _defaultHandlers);
 
-            //ordering here is important.  the last match wins
-            List<Class<?>> classes;
-            try {
-                classes = Reflection.getClassesForPackage(_package);
-            } catch (Exception exception) {
-                throw new RuntimeException(exception);
-            }
+                //ordering here is important.  the last match wins
+                List<Class<?>> classes;
+                try {
+                    classes = Reflection.getClassesForPackage(_package);
+                } catch (Exception exception) {
+                    throw new RuntimeException(exception);
+                }
 
-            for (Class<?> clazz : classes) {
-                if (FilteredResourceHandlerI.class.isAssignableFrom(clazz)) {
-                    handlers.get(_package).add((FilteredResourceHandlerI) clazz.newInstance());
+                for (Class<?> clazz : classes) {
+                    if (FilteredResourceHandlerI.class.isAssignableFrom(clazz)) {
+                        handlers.get(_package).add((FilteredResourceHandlerI) clazz.newInstance());
+                    }
                 }
             }
         }
diff --git a/src/main/resources/META-INF/xnat/preferences/automation.properties b/src/main/resources/META-INF/xnat/preferences/automation.properties
new file mode 100644
index 0000000000000000000000000000000000000000..1724138ee1372818dba1f457c6d3d2a8984b5229
--- /dev/null
+++ b/src/main/resources/META-INF/xnat/preferences/automation.properties
@@ -0,0 +1,2 @@
+# Declares default values for the automation service.
+internalScriptingEnabled=true
diff --git a/src/main/resources/config/site/siteConfiguration.properties b/src/main/resources/META-INF/xnat/preferences/site-config.properties
similarity index 100%
rename from src/main/resources/config/site/siteConfiguration.properties
rename to src/main/resources/META-INF/xnat/preferences/site-config.properties
diff --git a/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml b/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml
index 56ad7ec8e379bf0737d05d7749e1013419594728..3005662d87379ced5542292deed0693d2fba8f46 100644
--- a/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml
+++ b/src/main/resources/META-INF/xnat/spawner/site-admin-elements.yaml
@@ -1170,6 +1170,21 @@ fileSystem:
         ${checksums}
 #        ${checksumsPropertyChangedListener}
 
+automationSettings:
+    kind: panel.form
+    name: automationSettings
+    label: Automation
+    method: POST
+    contentType: json
+    action: /xapi/automation
+    load: /xapi/automation
+    contents:
+        internalScriptingEnabled:
+            kind: panel.input.checkbox
+            name: internalScriptingEnabled
+            label: Internal Scripting Enabled
+            description: "When enabled, administrators can create and edit scripts that run internally to the XNAT process. This can be a powerful feature, but also can pose security hazards that may be unacceptable for certain deployments. For these situations, configurable internal scripting can be disabled (XNAT itself may still use some scripting for feature implementation, but these scripts can not be modified or updated by users)."
+
 misc:
     kind: panel.form
     name: misc
@@ -1327,6 +1342,13 @@ adminPage:
             group: advanced
             contents:
                 ${fileSystem}
+        automationTab:
+            kind: tab
+            name: automationTab
+            label: Automation
+            group: advanced
+            contents:
+                ${automationSettings}
         misc:
             kind: tab
             name: misc