VAITP Dataset

← Back to the dataset

CVE-2026-47731

Path traversal in AIT's BSC allows an unauthenticated remote file append.

  • CVSS 9.1
  • CWE-22
  • Input Validation and Sanitization
  • Remote

The AMMOS Instrument Toolkit (Formerly the Bespoke Links to Instruments for Surface and Space (BLISS)) is a Python-based software suite developed to handle Ground Data System (GDS), Electronic Ground Support Equipment (EGSE), commanding, telemetry uplink/downlink, and sequencing for instrument and CubeSat Missions. In versions prior to 2.6.1 and in version 3.1.0, the Binary Stream Capture (BSC) component exposes an unauthenticated HTTP API for dynamically creating packet capture "handlers." Because the code blindly trusts path‑related form fields, a remote client can bypass the configured log root and direct BSC to log to arbitrary filesystem paths (path traversal / directory escape), and append attacker‑controlled data to those files, using the privileges of the`ait-bsc` process. There are two ways for a remote attacker to trigger this. First, if the attacker has access to the network where `ait-bsc` is deployed (a reason for that could be that the ports are publicly accessible), the payloads can be directly sent to the server to trigger the arbitrary file append. This type of attack is demonstrated in `python_poc.py`. Second, even if the attacker does not have direct access to the network because the software is running in a local network, it is possible to exploit this if a bad actor in that network opens an attacker-controlled website (which might be a website created by an attacker, or a third-party website compromised by the attacker). The browser javascript can automatically send the requests necessary to exploit this into the local network. This is even possible if the server is only accessible on `localhost`. This type of attack is demonstrated by `attacker_tcp.py` and `test1.html` (first launch the attacker TCP server, then start a webserver to host `test1.html`, for example using `python3 -m http.server 7000`, and open `test1.html`).This issue affects BSC (Binary Stream Capture) and usage of the ait-bsc server. This impacts AIT-Core versions before 3.1.1, from 2.x before 2.6.1. Users are recommended to upgrade to version 3.1.1 or 2.6.1.

CVSS base score
9.1
Published
2026-07-21
OWASP
A03 Injection
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Input Validation and Sanitization
Subcategory
Path Traversal
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
AIT-Core
Fixed by upgrading
Yes

Solution

Upgrade to AIT-Core version 2.6.1 or 3.1.1.

Vulnerable code sample

import os
from flask import Flask, request

# This is a simplified representation of the AIT-BSC server.
# The actual AIT-BSC is more complex, but this captures the essence
# of the path traversal vulnerability.

# In a real AIT-BSC deployment, this might be something like '/var/log/ait/'
LOG_ROOT = 'bsc_logs'

app = Flask(__name__)

@app.route('/create_handler', methods=['POST'])
def create_handler():
    """
    This endpoint is intended to create a log handler that writes data
    to a specified file within the LOG_ROOT directory.
    VULNERABILITY: It does not sanitize the 'filename' input, allowing
    a client to use path traversal characters like '../' to write
    outside of the intended LOG_ROOT directory.
    """
    filename = request.form.get('filename')
    data_to_log = request.form.get('data')

    if not filename or not data_to_log:
        return "Missing 'filename' or 'data' in form submission.", 400

    # VULNERABLE CODE: The user-provided 'filename' is directly joined
    # with the base log path without any validation or sanitization.
    # An attacker can provide a filename like '../../../../tmp/pwned'
    # to escape the LOG_ROOT directory.
    full_path = os.path.join(LOG_ROOT, filename)

    try:
        # The code attempts to append to the constructed file path.
        # This allows an attacker to append arbitrary data to existing files.
        with open(full_path, 'a') as f:
            f.write(data_to_log + '\n')
        
        # In a real application, this might return a handler ID or status.
        return f"Successfully appended data to {full_path}", 200
    except IOError as e:
        return f"Error writing to file: {e}", 500
    except Exception as e:
        return f"An unexpected error occurred: {e}", 500

if __name__ == '__main__':
    # Create the intended log directory if it doesn't exist
    if not os.path.exists(LOG_ROOT):
        os.makedirs(LOG_ROOT)
        print(f"Created log directory: {LOG_ROOT}")

    print("Vulnerable AIT-BSC server starting...")
    print(f"Intended log root: {os.path.abspath(LOG_ROOT)}")
    print("Send a POST request to /create_handler with 'filename' and 'data' fields.")
    print("Example benign payload: curl -X POST -d 'filename=test.log&data=hello'")
    print("Example malicious payload: curl -X POST -d 'filename=../../pwned.txt&data=arbitrary_file_write'")
    
    # The server binds to 0.0.0.0 to be accessible on the network,
    # as described in the CVE.
    app.run(host='0.0.0.0', port=8080, debug=False)

Patched code sample

import os
import http.server
import socketserver
from urllib.parse import urlparse, parse_qs

# In a real application, this would be a configurable, secure directory.
# For this example, we create a temporary one.
LOG_ROOT = "/tmp/safe_log_root"

def create_safe_log_handler(user_provided_path):
    """
    Safely creates a log file handler, preventing path traversal.

    This function represents the fix for the path traversal vulnerability.
    The vulnerability was caused by directly using a user-provided path
    without validation. The fix involves the following steps:

    1.  Join the base log directory with the user-provided path.
    2.  Resolve the absolute, canonical path of the resulting target path.
        This collapses any directory traversal sequences (e.g., '../').
    3.  Verify that this resolved path is still located within the
        configured LOG_ROOT directory.
    4.  Only proceed with file operations if the path is confirmed to be safe.
    """
    # Ensure the base log directory exists
    os.makedirs(LOG_ROOT, exist_ok=True)

    # Resolve the absolute, canonical path of the safe base directory
    real_log_root = os.path.abspath(LOG_ROOT)

    # Combine the base directory with user input and resolve its absolute path
    # This step is crucial as os.path.abspath resolves '..' components.
    intended_path = os.path.join(real_log_root, user_provided_path)
    real_intended_path = os.path.abspath(intended_path)

    # --- THE FIX ---
    # Check if the resolved intended path is a sub-path of the resolved
    # safe base directory. `os.path.commonpath` is a robust way to verify
    # this. If the common path of the two is not the base directory itself,
    # it means the intended path has "escaped" the allowed directory.
    if os.path.commonpath([real_log_root, real_intended_path]) != real_log_root:
        # Path traversal detected, abort the operation.
        print(
            f"SECURITY ALERT: Path traversal attempt blocked.\n"
            f"  - Attacker input: '{user_provided_path}'\n"
            f"  - Attempted to write to: '{real_intended_path}'\n"
            f"  - Operation confined to: '{real_log_root}'"
        )
        return False

    # If the check passes, it is safe to proceed.
    try:
        os.makedirs(os.path.dirname(real_intended_path), exist_ok=True)
        with open(real_intended_path, "a") as f:
            f.write("Log data from a safe handler.\n")
        print(f"Success: Logged safely to '{real_intended_path}'")
        return True
    except OSError as e:
        print(f"Error: Could not write to file. {e}")
        return False

# --- Example Usage Demonstration ---
if __name__ == "__main__":
    print("--- Demonstrating Fix for Path Traversal ---")
    print(f"Configured log root: {LOG_ROOT}\n")

    # 1. Legitimate use case: creates a file within the allowed directory.
    print("Test 1: Legitimate filename")
    create_safe_log_handler("device1/telemetry.log")
    print("-" * 20)

    # 2. Malicious use case: attempts to write outside the log root.
    #    This attempt will be blocked by the security check.
    print("Test 2: Malicious path traversal input")
    # This path would resolve to /tmp/pwned.txt, which is outside /tmp/safe_log_root
    create_safe_log_handler("../../pwned.txt")
    print("-" * 20)
    
    # 3. Another legitimate but nested use case
    print("Test 3: Legitimate nested filename")
    create_safe_log_handler("mission_alpha/payload/stream.bin")
    print("-" * 20)

Payload

import requests

# This payload targets a running 'ait-bsc' server.
# It sends a POST request to create a new log handler.
# The 'path' parameter contains the path traversal sequence to write a file
# outside of the intended directory, demonstrating the vulnerability.

requests.post(
    "http://127.0.0.1:1500/",  # Assumes default port and localhost access
    data={
        "path": "../../../../../../tmp/pwned_by_cve",
        "name": "malicious_handler"
    }
)

Cite this entry

@misc{vaitp:cve202647731,
  title        = {{Path traversal in AIT's BSC allows an unauthenticated remote file append.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-47731},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-47731/}}
}
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 ::