security(file_svc): containment check on save_file to block agent-contact path traversal (#3380)
* security(file_svc): containment check on save_file to block path traversal
file_svc.save_file builds its target path as os.path.join(target_dir, filename)
and writes payload bytes there with no validation of the resulting location.
It is reached from the agent contact handlers with an attacker-controlled
filename:
* app/contacts/contact_ftp.py:217 — FTP submit_uploaded_file
* app/contacts/contact_dns.py:491 — DNS _submit_uploaded_file
* app/contacts/contact_gist.py:212 — Gist contact upload
* app/contacts/contact_slack.py:206 — Slack contact upload
A filename of e.g. '../../data/object_store' escapes the exfil tree and lets
an attacker write arbitrary bytes to any path the server has permission to
write. data_svc.restore_state pickle.loads('data/object_store') on the next
restart, which turns that write primitive into RCE on the team server. The
file is Fernet-encrypted with conf encryption_key, but with the documented
default encryption_key=ADMIN123 a remote attacker can forge a valid blob.
save_file has two legitimate call modes:
(1) target_dir + basename — sink mode used by data_svc, app_svc, c_operation,
base_knowledge_svc, and the four agent contact handlers above.
(2) '' + relative-path — path mode used by ability_api_manager,
base_api_manager, and rest_svc, which assemble paths from sanitised IDs.
A simple "filename must be a basename" check breaks mode (2). Instead, resolve
the final path with realpath and require it to stay under its parent. This:
* rejects '..' / absolute-path escape in BOTH call modes, with one check;
* leaves all in-tree callers' happy paths intact (object_store, contact
reports, operation logs, ability/source YAML writes);
* provides defense-in-depth for any future caller, not just the four contact
handlers known to be vulnerable today.
Includes a regression test that exercises three traversal vectors and
confirms each is rejected before any bytes are written.
Reported externally on 2026-05-18 alongside the broader audit pass.
* test(file_svc): fix path-traversal regression test guard
The post-condition assertion 'not os.path.exists(realpath(...))' used
'/etc/passwd' as one of the resolved-traversal targets. That file exists
on every Linux runner, so the guard would fail even when the production
code correctly raised ValueError before any I/O — what we saw in CI.
The security check (pytest.raises(ValueError, match='escapes parent'))
is unchanged; it's the only assertion that proves the fix works. The
post-condition guard is now scoped to canary basenames that cannot
pre-exist by accident, so it actually exercises 'rejected before write'
without depending on system-file absence.
---------
Co-authored-by: deacon-mp <mperry@mitre.org>MITRE Caldera™ is a cyber security platform designed to easily automate adversary emulation, assist manual red-teams, and automate incident response.
It is built on the MITRE ATT&CK™ framework and is an active research project at MITRE.
The framework consists of two components:
It is always incredibly helpful for our team to hear from users about their Caldera use cases and the value that Caldera provides for their learning, research, or cyber security work. If you or your team uses Caldera significantly, we would greatly appreciate hearing from you.
📋 Survey - https://forms.office.com/g/ByBWxYTf8e
:star: Create your own plugin! Plugin generator: Skeleton :star:
These plugins are supported and maintained by the Caldera team.
These plugins are ready to use but are not included by default and are not maintained by the Caldera team.
These requirements are for the computer running the core framework:
Note: we HIGHLY recommend installing Caldera in a Python virtual environment to avoid issues with pip packages. You can use an existing environment if you wish or create a new one from scratch:
python3 -m venv .calderavenv source .calderavenv/bin/activate
Concise installation steps:
git clone https://github.com/mitre/caldera.git --recursive cd caldera pip3 install -r requirements.txt python3 server.py --insecure --build
Full steps: Start by cloning this repository recursively, passing the desired version/release in x.x.x format. This will pull in all available plugins.
git clone https://github.com/mitre/caldera.git --recursive --tag x.x.x
Next, install the PIP requirements:
pip3 install -r requirements.txt
Finally, start the server.
python3 server.py --insecure --build
The --build flag automatically installs any VueJS UI dependencies, bundles the UI into a dist directory and is served by the Caldera server. You will only have to use the --build flag again if you add any plugins or make any changes to the UI. Once started, log into http://localhost:8888 using the default credentials red/admin. Then go into Plugins -> Training and complete the capture-the-flag style training course to learn how to use Caldera.
If you prefer to not use the new VueJS UI, revert to Caldera v4.2.0. Correspondingly, do not use the --build flag for earlier versions as not required.
Additionally, please note security recommendations for deploying Caldera.
Local build:
git clone https://github.com/mitre/caldera.git --recursive cd caldera docker build --build-arg VARIANT=full -t caldera . docker run -it -p 8888:8888 caldera
Adjust the port forwarding (-p) and build args (--build-arg) as desired to make ports accessible or change the Caldera variant. The ports that you expose depend on which contacts you plan on using (see Dockerfile and docker-compose.yml for reference).
Pre-Built Image (from GitHub Container Registry):
docker run -p 8888:8888 ghcr.io/mitre/caldera:latest
This container may be slightly outdated, we recommend building the container yourself.
To gracefully terminate your docker container, do the following:
# Find the container ID for your docker container running Caldera docker ps # Stop the container docker stop <container ID>
There are two variants available, full and slim. The slim variant doesn't include files necessary for the emu and atomic plugins, which will be downloaded on-demand if the plugins are ever enabled. The full variant is suitable for operation in environments without an internet connection. Slim images on GHCR are prefixed with “slim”.
Docker Container Notes
-v <your_path>/conf.yml:/usr/src/app/conf/local.yml flag.-v <path_to_your_data_or_volume_name>:/usr/src/app/data/). Ensure that the directory structure is the same as in the data/ directory on GitHub, as Caldera will refuse to create these sub-directories if they are missing. Lastly, make sure that the configuration file is also made persistent to prevent issues with encryption keys.builder plugin will not work within Docker.atomic plugin, clone the Atomic Red Team repository outside the container, apply your modifications and bind-mount it (-v) to /usr/src/app/plugins/atomic/data/atomic-red-team within the container.emu, clone the adversary_emulation_library repository locally and bind-mount it (-v) to /usr/src/app/plugins/emu/data/adversary-emulation-plans.Additionally, please note security recommendations for deploying Caldera.
If you'll be developing the UI, there are a few more additional installation steps.
Requirements
Setup
git submodule add https://github.com/mitre/magmacd plugins/magma && npm install && cd ..python3 server.py --uidev localhostYour Caldera server is available at http://localhost:8888 as usual, but there will now be a hot-reloading development server for the VueJS front-end available at http://localhost:3000. Both logs from the server and the front-end will display in the terminal you launched the server from.
The Caldera team highly reccommends standing up the Caldera server on a secure environment/network, and not exposing it to the internet. The Caldera server does not have a hardened and thoroughly pentested web application interface, but only basic authentication and security features. Both MITRE and MITRE‘s US Government sponsors nearly exclusively only use Caldera on secure environments and do not rely on Caldera’s own security protocols for proper cyber security.
Refer to our Vulnerability Disclosure Documentation for submitting bugs.
🚨Security Notice🚨: (17 Feb 2025 10:00 EST) Please pull v5.1.0+ for a recent security patch for CVE-2025-27364. Please update your Caldera instance, especially if you host Caldera on a publicly accessible network. Vulnerability walkthrough.
Refer to our contributor documentation.
To discuss licensing opportunities, please reach out to caldera@mitre.org or directly to MITRE's Technology Transfer Office.
If you are interested in partnering to support, sustain, and evolve MITRE Caldera™'s open source capabilities, please contact us at caldera@mitre.org.