VAITP Dataset

← Back to the dataset

CVE-2025-11157

Insecure YAML deserialization in Feast Kubernetes materializer allows RCE.

  • CVSS 7.8
  • CWE-502
  • Input Validation and Sanitization
  • Local

A high-severity remote code execution vulnerability exists in feast-dev/feast version 0.53.0, specifically in the Kubernetes materializer job located at `feast/sdk/python/feast/infra/compute_engines/kubernetes/main.py`. The vulnerability arises from the use of `yaml.load(…, Loader=yaml.Loader)` to deserialize `/var/feast/feature_store.yaml` and `/var/feast/materialization_config.yaml`. This method allows for the instantiation of arbitrary Python objects, enabling an attacker with the ability to modify these YAML files to execute OS commands on the worker pod. This vulnerability can be exploited before the configuration is validated, potentially leading to cluster takeover, data poisoning, and supply-chain sabotage.

CVSS base score
7.8
Published
2026-01-01
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Timing/Serialization
Code defect classification
Serialization Issues
Category
Input Validation and Sanitization
Subcategory
Insecure Parsing or Deserialization
Accessibility scope
Local
Impact
Arbitrary Code Execution
Affected component
feast
Fixed by upgrading
Yes

Solution

Upgrade Feast to version 0.35.1 or later.

Vulnerable code sample

import os
import yaml
import logging

# Set up basic logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def apply_total_feature_set(
    feature_store_yaml_path: str, materialization_config_yaml_path: str
):
    """
    Simulates the vulnerable process of loading configurations and applying them.
    The vulnerability lies in the unsafe loading of YAML files.
    """
    logger.info("Starting materialization job.")

    # Load the feature store configuration from a path mounted into the pod.
    # An attacker who can write to this path can control the content of the YAML.
    try:
        with open(feature_store_yaml_path, "r") as f:
            # VULNERABLE LINE: yaml.load with the default (unsafe) Loader is used.
            # This allows for arbitrary Python object instantiation and code execution.
            # The prompt mentions `Loader=yaml.Loader`, which is the default and unsafe.
            logger.info(f"Deserializing feature store config from {feature_store_yaml_path}...")
            feature_store_config = yaml.load(f, Loader=yaml.Loader)
            logger.info("Successfully deserialized feature store config.")
            # In a real scenario, this config object would be used further.
            # However, the exploit has already occurred during the load process.

    except Exception as e:
        logger.error(f"Failed to load feature store config: {e}", exc_info=True)
        # The script might exit here, but the damage could already be done.
        return

    # Load the materialization configuration, also from a mounted path.
    # This is a second potential injection point.
    try:
        with open(materialization_config_yaml_path, "r") as f:
            # VULNERABLE LINE: Another instance of using the unsafe yaml.load.
            logger.info(f"Deserializing materialization config from {materialization_config_yaml_path}...")
            materialization_config = yaml.load(f, Loader=yaml.Loader)
            logger.info("Successfully deserialized materialization config.")

    except Exception as e:
        logger.error(f"Failed to load materialization config: {e}", exc_info=True)
        return

    # In the actual Feast application, the script would proceed to use these
    # configuration objects to run the materialization job.
    logger.info("Configuration loaded. Proceeding with materialization logic...")
    # ... business logic would follow here ...
    logger.info("Materialization job finished.")


if __name__ == "__main__":
    # In the Kubernetes job, these paths would point to files mounted via a ConfigMap or volume.
    # For this demonstration, we assume an attacker has placed a malicious file at one of these locations.
    # Example malicious feature_store.yaml:
    # ---
    # !!python/object/apply:os.system
    # - "touch /tmp/pwned_by_cve"
    # ---
    FEATURE_STORE_YAML = "/var/feast/feature_store.yaml"
    MATERIALIZATION_CONFIG_YAML = "/var/feast/materialization_config.yaml"

    # To simulate a realistic environment, we check if the files exist.
    if os.path.exists(FEATURE_STORE_YAML) and os.path.exists(MATERIALIZATION_CONFIG_YAML):
        apply_total_feature_set(FEATURE_STORE_YAML, MATERIALIZATION_CONFIG_YAML)
    else:
        logger.warning(
            "Mock config files not found. To test the vulnerability, create a malicious YAML at "
            f"{FEATURE_STORE_YAML} and a placeholder at {MATERIALIZATION_CONFIG_YAML}."
        )

Patched code sample

import os
import yaml
from pathlib import Path

# The CVE describes the vulnerability in a file like this, located at:
# `feast/sdk/python/feast/infra/compute_engines/kubernetes/main.py`
#
# For demonstration, we assume these paths are mounted into the pod.
FEAST_CONFIG_DIR = Path("/tmp/feast_demo/")  # Using /tmp for a runnable example
FEATURE_STORE_YAML_PATH = FEAST_CONFIG_DIR / "feature_store.yaml"
MATERIALIZATION_CONFIG_YAML_PATH = FEAST_CONFIG_DIR / "materialization_config.yaml"


def _load_and_apply_configuration():
    """
    Loads configuration from YAML files. This function demonstrates the fix
    for CVE-2025-11157 by using a safe YAML loader.

    The vulnerability existed because the original code used `yaml.load(..., Loader=yaml.Loader)`,
    which allows for arbitrary Python object instantiation and code execution.
    """
    # VULNERABLE CODE (for reference, this is what was fixed):
    #
    # with open(FEATURE_STORE_YAML_PATH, "r") as f:
    #     # Unsafe deserialization allows an attacker to run OS commands.
    #     feature_store_config = yaml.load(f, Loader=yaml.Loader)
    #
    # with open(MATERIALIZATION_CONFIG_YAML_PATH, "r") as f:
    #     # This was also vulnerable.
    #     materialization_config = yaml.load(f, Loader=yaml.Loader)

    # --- FIXED CODE ---
    # The fix is to replace the unsafe `yaml.load` with `yaml.safe_load`.
    # `yaml.safe_load()` is equivalent to `yaml.load(..., Loader=yaml.SafeLoader)`.
    # The `SafeLoader` only parses standard YAML tags and prevents the
    # instantiation of arbitrary Python objects, mitigating the RCE vulnerability.
    try:
        print(f"Safely loading configuration from {FEATURE_STORE_YAML_PATH}...")
        with open(FEATURE_STORE_YAML_PATH, "r") as f:
            feature_store_config = yaml.safe_load(f)

        print(f"Safely loading configuration from {MATERIALIZATION_CONFIG_YAML_PATH}...")
        with open(MATERIALIZATION_CONFIG_YAML_PATH, "r") as f:
            materialization_config = yaml.safe_load(f)

        print("\nSuccessfully and safely loaded configuration.")
        # The `safe_load` function would have raised an error if it encountered a
        # malicious tag like `!!python/object/apply`, preventing code execution.

    except yaml.YAMLError as e:
        print(f"\n[SUCCESS] The fix worked! Caught a potentially malicious YAML tag.")
        print(f"Error details: {e}")
        print("The unsafe object was NOT instantiated, and no command was executed.")


def main():
    """
    Main entry point to simulate the environment and demonstrate the fix.
    """
    print("--- Demonstrating fix for CVE-2025-11157 ---")

    # 1. Simulate the environment by creating the config directory.
    os.makedirs(FEAST_CONFIG_DIR, exist_ok=True)

    # 2. Create a legitimate feature_store.yaml file.
    legit_fs_yaml = """
    project: my_feast_project
    registry: data/registry.db
    provider: gcp
    """
    with open(FEATURE_STORE_YAML_PATH, "w") as f:
        f.write(legit_fs_yaml)

    # 3. Create a malicious materialization_config.yaml.
    # An attacker with write access to this file could inject this payload.
    # The vulnerable code would execute `os.system("touch /tmp/pwned")`.
    malicious_yaml_payload = """
    !!python/object/apply:os.system
    - "touch /tmp/pwned_by_cve"
    """
    with open(MATERIALIZATION_CONFIG_YAML_PATH, "w") as f:
        f.write(malicious_yaml_payload)

    print(f"Created a malicious payload in {MATERIALIZATION_CONFIG_YAML_PATH}")
    print("Payload tries to execute: os.system('touch /tmp/pwned_by_cve')\n")

    # 4. Run the fixed configuration loader.
    _load_and_apply_configuration()

    # 5. Verify that the malicious command was NOT executed.
    pwned_file = Path("/tmp/pwned_by_cve")
    if not pwned_file.exists():
        print("\n[VERIFICATION PASSED] The file /tmp/pwned_by_cve was not created.")
        print("The remote code execution was successfully prevented.")
    else:
        print("\n[VERIFICATION FAILED] The file /tmp/pwned_by_cve was created.")
        os.remove(pwned_file)

    # --- Cleanup ---
    os.remove(FEATURE_STORE_YAML_PATH)
    os.remove(MATERIALIZATION_CONFIG_YAML_PATH)
    os.rmdir(FEAST_CONFIG_DIR)


if __name__ == "__main__":
    main()

Payload

!!python/object/apply:os.system
- 'touch /tmp/pwned'

Cite this entry

@misc{vaitp:cve202511157,
  title        = {{Insecure YAML deserialization in Feast Kubernetes materializer allows RCE.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2025-11157},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-11157/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::