Incorrect Resource Transfer Between Spheres

Description

Incorrect Resource Transfer Between Spheres occurs when a product transfers a resource to another sphere in a way that violates the intended security boundaries. This includes transferring sensitive data to untrusted contexts, importing malicious content into trusted contexts, or crossing trust boundaries without proper validation. Examples include passing user input to system commands, deserializing untrusted data, and embedding user content in privileged contexts.

Risk

Untrusted data executed in privileged context. Sensitive information leaked to unauthorized spheres. Malicious code imported through deserialization. Cross-domain data theft via improper transfers. Command injection from user input in system calls. SQL injection from untrusted data in queries.

Solution

Validate and sanitize data crossing trust boundaries. Use safe APIs that don't mix data and control. Implement proper encoding when transferring data. Avoid deserializing untrusted data. Use parameterized interfaces. Apply principle of least privilege to transferred resources.

Common Consequences

ImpactDetails
IntegrityScope: Code Execution

Malicious data executed in trusted context.
ConfidentialityScope: Information Disclosure

Sensitive data transferred to untrusted sphere.
AuthorizationScope: Privilege Escalation

User-controlled data gains privileged access.

Example Code + Solution Code

Vulnerable Code

// VULNERABLE: Incorrect resource transfer between spheres
import java.io.*;

// VULNERABLE: User input transferred to command execution sphere
public class VulnerableTransfer {

    public void executeCommand(String userInput) {
        // VULNERABLE: User data transferred to OS command sphere
        Runtime.getRuntime().exec("ls " + userInput);
    }

    // VULNERABLE: Deserializing untrusted data
    public Object deserializeFromNetwork(InputStream networkInput) throws Exception {
        ObjectInputStream ois = new ObjectInputStream(networkInput);
        // VULNERABLE: Untrusted data transferred to object sphere
        return ois.readObject();  // Remote code execution possible
    }

    // VULNERABLE: User input transferred to SQL sphere
    public void queryDatabase(String userInput, Connection conn) throws SQLException {
        Statement stmt = conn.createStatement();
        // VULNERABLE: User data mixed with SQL commands
        stmt.executeQuery("SELECT * FROM users WHERE name = '" + userInput + "'");
    }

    // VULNERABLE: User data transferred to logging sphere
    public void logUserAction(String username) {
        // VULNERABLE: CRLF injection possible - user data in log
        logger.info("User logged in: " + username);
        // Could inject fake log entries
    }

    // VULNERABLE: Sensitive data transferred to client sphere
    public void sendResponse(HttpServletResponse response, User user) throws IOException {
        // VULNERABLE: Internal data transferred to client
        response.getWriter().write(user.toJson());  // Includes password hash!
    }
}

// VULNERABLE: File path transfer from untrusted source
public class VulnerableFileTransfer {

    public void copyUserFile(String userFilePath, String destination) throws IOException {
        // VULNERABLE: User-controlled path transferred to file system sphere
        Files.copy(Paths.get(userFilePath), Paths.get(destination));
        // Path traversal: "../../../etc/passwd"
    }
}
# VULNERABLE: Python incorrect resource transfers
import pickle
import subprocess
import os

# VULNERABLE: User input to subprocess sphere
def process_file_vulnerable(filename):
    # VULNERABLE: User data transferred to shell
    os.system(f"cat {filename}")  # Command injection

# VULNERABLE: Pickle deserialization of untrusted data
def load_data_vulnerable(network_data):
    # VULNERABLE: Network data transferred to object sphere
    return pickle.loads(network_data)  # Remote code execution

# VULNERABLE: User input transferred to eval sphere
def calculate_vulnerable(expression):
    # VULNERABLE: User math transferred to code execution
    return eval(expression)  # Any Python code executed

# VULNERABLE: Sensitive data transferred to template sphere
from jinja2 import Template

def render_vulnerable(user_content):
    # VULNERABLE: User content transferred to template execution sphere
    template = Template(user_content)
    return template.render()  # SSTI - server-side template injection

# VULNERABLE: Database credentials transferred to error message
def connect_vulnerable():
    try:
        db = connect(f"postgresql://admin:secret@localhost/mydb")
    except Exception as e:
        # VULNERABLE: Sensitive data transferred to error sphere
        raise Exception(f"Connection failed: {e}")  # Exposes credentials

# VULNERABLE: User data transferred to file path sphere
def read_file_vulnerable(user_path):
    # VULNERABLE: User path directly used
    with open(f"/var/data/{user_path}", 'r') as f:
        return f.read()  # Path traversal possible
// VULNERABLE: JavaScript incorrect resource transfers
const { exec } = require('child_process');

// VULNERABLE: User input transferred to shell sphere
function runCommand(userInput) {
    // VULNERABLE: User data mixed with command
    exec(`grep ${userInput} /var/log/app.log`, (err, stdout) => {
        console.log(stdout);
    });
}

// VULNERABLE: User input transferred to eval sphere
function calculate(expression) {
    // VULNERABLE: User math executed as code
    return eval(expression);
}

// VULNERABLE: Untrusted HTML transferred to DOM sphere
function displayMessage(userContent) {
    // VULNERABLE: User content transferred to DOM (XSS)
    document.getElementById('message').innerHTML = userContent;
}

// VULNERABLE: Sensitive data transferred to client sphere
app.get('/api/user/:id', (req, res) => {
    const user = getUser(req.params.id);
    // VULNERABLE: Internal user object sent to client
    res.json(user);  // Includes passwordHash, internalNotes, etc.
});

// VULNERABLE: User data transferred to database query sphere
app.get('/api/search', (req, res) => {
    const query = req.query.q;
    // VULNERABLE: User input in MongoDB query
    db.collection('users').find({ $where: `this.name == '${query}'` });
    // NoSQL injection
});

// VULNERABLE: User path transferred to file system sphere
app.get('/files/:filename', (req, res) => {
    const filename = req.params.filename;
    // VULNERABLE: User path used directly
    res.sendFile(`/var/uploads/${filename}`);
});

// VULNERABLE: Cross-origin data transfer
app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    // VULNERABLE: Any origin can access sensitive data
    next();
});
// VULNERABLE: C incorrect resource transfers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// VULNERABLE: User input transferred to system command sphere
void process_input_vulnerable(const char* user_input) {
    char command[256];
    // VULNERABLE: User data mixed with command
    sprintf(command, "echo %s", user_input);
    system(command);  // Command injection
}

// VULNERABLE: Network data transferred to format string sphere
void log_message_vulnerable(const char* network_data) {
    // VULNERABLE: Network data used as format string
    printf(network_data);  // Format string vulnerability
}

// VULNERABLE: User buffer transferred to fixed buffer
void copy_data_vulnerable(const char* user_data) {
    char buffer[64];
    // VULNERABLE: Unbounded copy from user sphere
    strcpy(buffer, user_data);  // Buffer overflow
}

// VULNERABLE: Network data transferred to memory operations
void process_packet_vulnerable(const char* packet, int user_length) {
    char buffer[1024];
    // VULNERABLE: User-controlled length in memory operation
    memcpy(buffer, packet, user_length);  // Overflow if length > 1024
}

// VULNERABLE: User index transferred to array access sphere
int get_item_vulnerable(int* array, int user_index) {
    // VULNERABLE: User index used directly
    return array[user_index];  // Out-of-bounds access
}

Fixed Code

// SAFE: Proper resource transfer between spheres
import java.io.*;
import java.util.*;

public class SafeTransfer {

    // SAFE: Don't transfer user input to command sphere directly
    public void executeCommand(String userInput) {
        // Option 1: Whitelist allowed commands
        String[] allowed = {"list", "status", "help"};
        if (Arrays.asList(allowed).contains(userInput)) {
            ProcessBuilder pb = new ProcessBuilder("myapp", userInput);
            pb.start();
        }

        // Option 2: Use ProcessBuilder with arguments
        ProcessBuilder pb = new ProcessBuilder("ls", "-la");
        pb.directory(new File("/safe/directory"));
        pb.start();
    }

    // SAFE: Use safe deserialization
    public Object deserializeFromNetwork(InputStream networkInput) {
        // Option 1: Use JSON/XML with schema validation
        ObjectMapper mapper = new ObjectMapper();
        // Enable safe defaults
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
        return mapper.readValue(networkInput, SafeDTO.class);

        // Option 2: If Java serialization required, use filter
        // ObjectInputFilter filter = ...
        // ois.setObjectInputFilter(filter);
    }

    // SAFE: Parameterized query
    public void queryDatabase(String userInput, Connection conn) throws SQLException {
        // SAFE: Parameters never transferred to SQL sphere
        PreparedStatement stmt = conn.prepareStatement(
            "SELECT * FROM users WHERE name = ?");
        stmt.setString(1, userInput);
        stmt.executeQuery();
    }

    // SAFE: Sanitize before logging
    public void logUserAction(String username) {
        // SAFE: Remove control characters before transfer to log sphere
        String sanitized = username.replaceAll("[\\r\\n]", "_");
        logger.info("User logged in: {}", sanitized);  // Parameterized logging
    }

    // SAFE: Filter before transferring to client sphere
    public void sendResponse(HttpServletResponse response, User user) throws IOException {
        // SAFE: Create DTO with only public fields
        UserDTO dto = new UserDTO(user.getId(), user.getUsername(), user.getEmail());
        // No password hash, no internal data
        response.getWriter().write(objectMapper.writeValueAsString(dto));
    }
}

// SAFE: Validate before file operations
public class SafeFileTransfer {

    private static final Path SAFE_BASE = Paths.get("/var/uploads").toRealPath();

    public void copyUserFile(String userFilePath, String destination) throws IOException {
        // SAFE: Validate path doesn't escape base directory
        Path sourcePath = SAFE_BASE.resolve(userFilePath).normalize();
        Path destPath = SAFE_BASE.resolve(destination).normalize();

        if (!sourcePath.startsWith(SAFE_BASE) || !destPath.startsWith(SAFE_BASE)) {
            throw new SecurityException("Path traversal attempted");
        }

        Files.copy(sourcePath, destPath);
    }
}
# SAFE: Python proper resource transfers
import subprocess
import json
import os
from pathlib import Path

# SAFE: Use list arguments, not shell string
def process_file_safe(filename):
    # SAFE: Arguments separated, not transferred to shell
    allowed_chars = set('abcdefghijklmnopqrstuvwxyz0123456789._-')
    if not all(c in allowed_chars for c in filename.lower()):
        raise ValueError("Invalid filename")

    # Use list form - no shell interpolation
    result = subprocess.run(['cat', filename], capture_output=True, text=True)
    return result.stdout

# SAFE: Use JSON instead of pickle
def load_data_safe(network_data):
    # SAFE: JSON can't execute code
    return json.loads(network_data)

# SAFE: Use safe expression evaluation
import ast
import operator

SAFE_OPERATORS = {
    ast.Add: operator.add,
    ast.Sub: operator.sub,
    ast.Mult: operator.mul,
    ast.Div: operator.truediv,
}

def calculate_safe(expression):
    # SAFE: Parse and evaluate only math operations
    tree = ast.parse(expression, mode='eval')

    def eval_node(node):
        if isinstance(node, ast.Num):
            return node.n
        elif isinstance(node, ast.BinOp):
            op = SAFE_OPERATORS.get(type(node.op))
            if not op:
                raise ValueError("Unsupported operation")
            return op(eval_node(node.left), eval_node(node.right))
        else:
            raise ValueError("Unsupported expression")

    return eval_node(tree.body)

# SAFE: Use autoescape for templates
from jinja2 import Environment, select_autoescape

env = Environment(autoescape=select_autoescape())

def render_safe(template_name, **context):
    # SAFE: Load predefined template, escape user data
    template = env.get_template(template_name)
    return template.render(**context)

# SAFE: Don't expose sensitive data in errors
def connect_safe(connection_string):
    try:
        return connect(connection_string)
    except Exception as e:
        # SAFE: Generic error, no sensitive data
        raise Exception("Database connection failed") from None

# SAFE: Validate file paths
UPLOAD_DIR = Path('/var/data').resolve()

def read_file_safe(user_path):
    # SAFE: Validate path stays within allowed directory
    full_path = (UPLOAD_DIR / user_path).resolve()
    if not str(full_path).startswith(str(UPLOAD_DIR)):
        raise ValueError("Invalid path")
    with open(full_path, 'r') as f:
        return f.read()
// SAFE: JavaScript proper resource transfers
const { spawn } = require('child_process');
const path = require('path');

// SAFE: Use spawn with array arguments
function runCommand(userInput) {
    // Whitelist allowed search terms
    const sanitized = userInput.replace(/[^a-zA-Z0-9]/g, '');

    // SAFE: Use spawn with arguments as array
    const grep = spawn('grep', [sanitized, '/var/log/app.log']);
    grep.stdout.on('data', (data) => {
        console.log(data.toString());
    });
}

// SAFE: Use safe expression parser
const mathjs = require('mathjs');

function calculate(expression) {
    // SAFE: mathjs doesn't execute arbitrary code
    return mathjs.evaluate(expression);
}

// SAFE: Use textContent or sanitization
function displayMessage(userContent) {
    // SAFE: textContent doesn't execute HTML/JS
    document.getElementById('message').textContent = userContent;

    // Or use DOMPurify for HTML
    const clean = DOMPurify.sanitize(userContent);
    document.getElementById('message').innerHTML = clean;
}

// SAFE: Transfer only needed fields to client
app.get('/api/user/:id', (req, res) => {
    const user = getUser(req.params.id);
    // SAFE: Only transfer public fields
    res.json({
        id: user.id,
        username: user.username,
        email: user.email
        // No passwordHash, no internalNotes
    });
});

// SAFE: Parameterized MongoDB query
app.get('/api/search', (req, res) => {
    const query = req.query.q;
    // SAFE: User input as data, not code
    db.collection('users').find({ name: query });
});

// SAFE: Validate file path
const UPLOAD_DIR = path.resolve('/var/uploads');

app.get('/files/:filename', (req, res) => {
    const filename = req.params.filename;
    const fullPath = path.resolve(UPLOAD_DIR, filename);

    // SAFE: Verify path is within allowed directory
    if (!fullPath.startsWith(UPLOAD_DIR)) {
        return res.status(403).send('Forbidden');
    }

    res.sendFile(fullPath);
});

// SAFE: Restrictive CORS
const corsOptions = {
    origin: ['https://myapp.com'],
    methods: ['GET', 'POST'],
    credentials: true
};
app.use(cors(corsOptions));
// SAFE: C proper resource transfers
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// SAFE: Don't transfer user input to system()
void process_input_safe(const char* user_input) {
    // Option 1: Whitelist
    const char* allowed[] = {"list", "status", NULL};
    int valid = 0;
    for (int i = 0; allowed[i]; i++) {
        if (strcmp(user_input, allowed[i]) == 0) {
            valid = 1;
            break;
        }
    }

    // Option 2: Use execve with arguments
    if (valid) {
        pid_t pid = fork();
        if (pid == 0) {
            char* args[] = {"myapp", (char*)user_input, NULL};
            execve("/usr/bin/myapp", args, NULL);
            exit(1);
        }
    }
}

// SAFE: Don't use network data as format string
void log_message_safe(const char* network_data) {
    // SAFE: Data is argument, not format
    printf("%s", network_data);
}

// SAFE: Bounded copy
void copy_data_safe(const char* user_data, size_t user_len) {
    char buffer[64];
    // SAFE: Limit size
    size_t copy_len = user_len < sizeof(buffer) - 1 ? user_len : sizeof(buffer) - 1;
    memcpy(buffer, user_data, copy_len);
    buffer[copy_len] = '\0';
}

// SAFE: Validate before memory operation
void process_packet_safe(const char* packet, int user_length) {
    char buffer[1024];
    // SAFE: Validate length before transfer
    if (user_length > 0 && user_length <= sizeof(buffer)) {
        memcpy(buffer, packet, user_length);
    }
}

// SAFE: Bounds check before array access
int get_item_safe(int* array, size_t array_size, int user_index) {
    // SAFE: Validate index before transfer to array access
    if (user_index >= 0 && (size_t)user_index < array_size) {
        return array[user_index];
    }
    return -1;  // Error value
}

Exploited in the Wild

Deserialization Attacks

Java/Python pickle RCE via untrusted deserialization.

Command Injection

User input transferred to shell causing system compromise.

SQL/NoSQL Injection

User data improperly transferred to database queries.


Tools to test/exploit

  • Burp Suite for injection testing.

  • ysoserial for Java deserialization.

  • SQLMap for database injection.


CVE Examples

  • CVE-2015-4852: Java deserialization (WebLogic).

  • CVE-2017-5638: Struts2 OGNL injection.


References

  1. MITRE. "CWE-669: Incorrect Resource Transfer Between Spheres." https://cwe.mitre.org/data/definitions/669.html

  2. OWASP Injection Prevention.