Protect internal folders and files
A Masa CMS installation contains folders and files that are never meant to be requested by a browser: configuration with database credentials, development and test tooling, package manifests and log files. Block them at the web server level.
Why this is needed
Masa CMS places an Application.cfc in folders such as /config, /core, /sites and /themes that stops direct requests to CFML files. This is a useful safety net, but it has limits:
- It only applies to requests that reach the CFML engine. Static files such as
.log,.json,.mdor.sqlfiles, and folders such as.git, are served by the web server directly. - If the connection between the web server and the CFML engine is misconfigured, CFML files such as
/config/settings.ini.cfmcan be served as plain text, including the database password. - Some tooling is intentionally reachable, for example the test runner in
/core/tests.
Remove what you don’t need
The most reliable protection is to not have the files on a production server at all. Depending on how you installed Masa CMS, consider removing:
/core/tests(the test suite and test runner).git,.githuband other dot-files and foldersnode_modules,package.json,package-lock.jsonandgulpfile.js
The ForgeBox package already leaves out the tests. A Git checkout contains everything.
Block what remains
Even when you remove files, add web server rules as a second line of defense. The examples below block:
| What | Why |
|---|---|
/config/ | Contains settings.ini.cfm with datasource and mail credentials |
/WEB-INF/ | CFML engine configuration |
/core/tests/ | Test tooling |
/core/setup/ | The installation wizard. Only block this after installation is complete |
/node_modules/ | Front-end build dependencies |
Hidden files and folders (.git, .env, …) | Source code history and secrets. /.well-known/ stays reachable for certificate validation |
*.log, *.sql, *.bak, *.old, *.swp, *.ini | Logs, database dumps and backup copies |
box.json, package.json, README.md, htaccess.txt, … in the webroot | Reveal versions and setup details |
The configurations below are examples. Review and test them for your own setup. After applying them, check that both the public site and the Masa CMS admin still work.
Apache
Add the following to the <VirtualHost> of your site. Use the virtual host rather than .htaccess: when CFML requests are passed to the CFML engine with ProxyPass or ProxyPassMatch, rules in .htaccess are not applied to those requests.
# Internal folders
<LocationMatch "(?i)^/(config|WEB-INF|core/(tests|setup)|node_modules)(/|$)">
Require all denied
</LocationMatch>
# Hidden files and folders, except /.well-known/
<LocationMatch "/\.(?!well-known/)">
Require all denied
</LocationMatch>
# Logs, dumps, backups and files in the webroot that reveal setup details
<LocationMatch "(?i)(\.(log|sql|bak|old|swp|ini|md)$|^/(box\.json|package(-lock)?\.json|gulpfile\.js|Installation\.txt|htaccess\.txt|web\.config\.txt|license\.txt|COPYING)$)">
Require all denied
</LocationMatch>
IIS
This requires the IIS URL Rewrite module. Add the following rules at the top of <rewrite><rules> in your web.config:
<rule name="Block internal folders" stopProcessing="true">
<match url="^(config|WEB-INF|core/(tests|setup)|node_modules)(/|$)" ignoreCase="true" />
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Access denied" />
</rule>
<rule name="Block hidden files and folders" stopProcessing="true">
<match url="(^|/)\.(?!well-known/)" />
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Access denied" />
</rule>
<rule name="Block internal files" stopProcessing="true">
<match url="(\.(log|sql|bak|old|swp|ini|md)$|^(box\.json|package(-lock)?\.json|gulpfile\.js|Installation\.txt|htaccess\.txt|web\.config\.txt|license\.txt|COPYING)$)" ignoreCase="true" />
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Access denied" />
</rule>
Nginx
Add the following to the server block of your site, before other regex location blocks (such as the one that passes .cfm requests to the CFML engine). Nginx uses the first regex location that matches.
# Internal folders
location ~* ^/(config|WEB-INF|core/(tests|setup)|node_modules)(/|$) {
return 403;
}
# Hidden files and folders, except /.well-known/
location ~ /\.(?!well-known/) {
return 403;
}
# Logs, dumps, backups and files in the webroot that reveal setup details
location ~* (\.(log|sql|bak|old|swp|ini|md)$|^/(box\.json|package(-lock)?\.json|gulpfile\.js|Installation\.txt|htaccess\.txt|web\.config\.txt|license\.txt|COPYING)$) {
return 403;
}
Test your configuration
In a private browser window, or with curl -I, request a few of the blocked paths and check that you get a 403 Forbidden (or 404 Not Found) response:
https://www.example.com/config/settings.ini.cfmhttps://www.example.com/core/tests/runner.cfmhttps://www.example.com/box.jsonhttps://www.example.com/.git/HEAD
Then check that the public site, the admin and the front-end editing tools still work.