Function Call With Incorrect Order of Arguments

Description

Function Call With Incorrect Order of Arguments is a programming error where a product calls a function with arguments specified in the wrong sequence. This commonly occurs when functions have multiple parameters of the same or compatible types, making it easy to accidentally swap them. While strongly-typed compilers may catch type mismatches, this vulnerability frequently occurs with variadic functions, format strings, or when parameters share the same type (like two strings or two integers). The bug results in the function operating on the wrong data, potentially causing security vulnerabilities or incorrect behavior.

Risk

Incorrect argument order creates significant risks depending on the function's purpose. Authentication functions with swapped username/password parameters may authenticate with wrong credentials or fail inappropriately. Memory functions like memcpy() with swapped source/destination can overwrite critical data. Security-sensitive functions with reversed parameters may grant unauthorized access or apply wrong permissions. Format string functions with mismatched format/argument order can cause crashes or information leakage. The bug is often subtle and may only manifest with specific input combinations, making it difficult to detect through testing.

Solution

Use functions with named parameters when the language supports them. Order function parameters by importance or use patterns that make order obvious (destination before source, or alphabetical). Document parameter order clearly and use meaningful parameter names. Enable compiler warnings for type mismatches and implicit conversions. Use static analysis tools that can detect argument order issues. Consider creating wrapper functions with clearer interfaces for commonly misused functions. Implement thorough unit tests that verify correct behavior with various input combinations.

Common Consequences

ImpactDetails
Access ControlScope: Access Control

Bypass Protection Mechanism - Authentication or authorization functions with swapped parameters may grant unauthorized access.
IntegrityScope: Integrity

Modify Application Data - Operations like copy or move with swapped source/destination corrupt data.
OtherScope: Other

Quality Degradation - Functions produce incorrect results when operating on wrong parameters.

Example Code

Vulnerable Code

<?php
// Vulnerable: Authentication function called with reversed arguments
function authenticate($username, $password) {
    $query = "SELECT * FROM users WHERE username = ? AND password = ?";
    $stmt = $db->prepare($query);
    $stmt->execute([$username, hash_password($password)]);
    return $stmt->fetch() !== false;
}

// Vulnerable: Arguments reversed - username and password swapped!
$username = $_POST['username'];
$password = $_POST['password'];

if (authenticate($password, $username)) {  // WRONG ORDER!
    // Tries to find user named after password, with hashed username
    // May fail to authenticate valid users
    // Or might have unexpected security implications
    login_user($username);
}
// Vulnerable: memcpy with reversed source and destination
#include <string.h>

void vulnerable_copy(char* dest, const char* src, size_t len) {
    // Vulnerable: Source and destination reversed!
    memcpy(src, dest, len);  // Writes to source (const), reads from dest
    // This may crash or corrupt memory
}

// Vulnerable: strncpy arguments reversed
void vulnerable_strncpy(char* buffer, size_t buffer_size, const char* input) {
    // Vulnerable: Arguments in wrong order
    strncpy(input, buffer, buffer_size);  // WRONG!
    // Should be: strncpy(buffer, input, buffer_size);
}

// Vulnerable: Permission check with swapped user and resource
int check_permission(int user_id, int resource_id, int permission) {
    // Checks if user has permission on resource
    return database_check(user_id, resource_id, permission);
}

void vulnerable_access_check() {
    int user = get_current_user();
    int resource = get_requested_resource();

    // Vulnerable: user_id and resource_id swapped!
    if (check_permission(resource, user, PERM_READ)) {  // WRONG ORDER!
        // Checks if 'resource' (as user) has permission on 'user' (as resource)
        // Completely wrong security check!
        grant_access();
    }
}
// Vulnerable: Java file copy with reversed arguments
import java.nio.file.*;

public class VulnerableCopy {

    // Vulnerable: Source and target paths reversed
    public void copyFile(Path source, Path target) throws IOException {
        // Vulnerable: Arguments swapped!
        Files.copy(target, source);  // Copies target to source!
        // Overwrites the source file with target's contents
    }

    // Vulnerable: String replace with swapped old/new
    public String processText(String text) {
        // Vulnerable: oldValue and newValue swapped!
        return text.replace("NewValue", "OldValue");  // WRONG ORDER!
        // Replaces "NewValue" with "OldValue" instead of vice versa
    }
}

// Vulnerable: Logging with swapped message and exception
public class VulnerableLogger {

    public void handleError(String message, Exception e) {
        // Logger expects: log(message, exception)
        // Vulnerable: Arguments reversed
        logger.error(e, message);  // If logger.error(Object, String) exists
        // May not log properly or may expose exception details incorrectly
    }
}
# Vulnerable: Function with same-type parameters
def create_user(username, email, role):
    """Create user with given username, email, and role."""
    db.execute(
        "INSERT INTO users (username, email, role) VALUES (?, ?, ?)",
        [username, email, role]
    )

# Vulnerable: Called with arguments in wrong order
def register_new_user():
    email = request.form['email']
    username = request.form['username']
    role = 'user'

    # Vulnerable: email and username swapped!
    create_user(email, username, role)  # WRONG ORDER!
    # Stores email as username and username as email

Fixed Code

<?php
// Fixed: Use named parameters or wrapper with validation
function authenticate(string $username, string $password): bool {
    // Add validation to catch obvious swaps
    if (filter_var($username, FILTER_VALIDATE_EMAIL)) {
        throw new InvalidArgumentException(
            "Username looks like an email - check argument order");
    }

    $query = "SELECT * FROM users WHERE username = ? AND password = ?";
    $stmt = $db->prepare($query);
    $stmt->execute([$username, hash_password($password)]);
    return $stmt->fetch() !== false;
}

// Fixed: Using named parameters (PHP 8+)
$username = $_POST['username'];
$password = $_POST['password'];

if (authenticate(username: $username, password: $password)) {
    // Named parameters make order explicit
    login_user($username);
}

// Alternative: Use an associative array or DTO
class Credentials {
    public string $username;
    public string $password;
}

function authenticateWithCredentials(Credentials $creds): bool {
    // Cannot swap parameters - single structured argument
    return authenticate($creds->username, $creds->password);
}
// Fixed: Clear parameter naming and documentation
#include <string.h>

/**
 * Copy data safely from source to destination.
 * @param dest Destination buffer (must have at least len bytes)
 * @param src Source data to copy from
 * @param len Number of bytes to copy
 */
void safe_copy(void* dest, const void* src, size_t len) {
    // Parameter order matches standard convention: dest, src, len
    if (dest == NULL || src == NULL) return;
    memcpy(dest, src, len);
}

// Fixed: Wrapper with clearer semantics
void copy_string_to_buffer(
    char* destination_buffer,
    size_t destination_size,
    const char* source_string
) {
    // Names make purpose obvious
    if (destination_buffer == NULL || source_string == NULL) return;
    strncpy(destination_buffer, source_string, destination_size - 1);
    destination_buffer[destination_size - 1] = '\0';
}

// Fixed: Permission check with clear parameter types
typedef struct {
    int id;
} UserId;

typedef struct {
    int id;
} ResourceId;

int check_permission(UserId user, ResourceId resource, int permission) {
    // Different types prevent accidental swapping
    return database_check(user.id, resource.id, permission);
}

void safe_access_check() {
    UserId user = { .id = get_current_user() };
    ResourceId resource = { .id = get_requested_resource() };

    // Compiler would catch if swapped due to type mismatch
    if (check_permission(user, resource, PERM_READ)) {
        grant_access();
    }
}
// Fixed: Java with builder pattern for clarity
import java.nio.file.*;

public class SafeCopy {

    // Fixed: Wrapper with clear naming
    public void copySourceToTarget(Path source, Path target) throws IOException {
        // Method name indicates direction
        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    }

    // Fixed: Builder pattern for complex operations
    public static class FileCopyOperation {
        private Path source;
        private Path target;

        public FileCopyOperation from(Path source) {
            this.source = source;
            return this;
        }

        public FileCopyOperation to(Path target) {
            this.target = target;
            return this;
        }

        public void execute() throws IOException {
            // Names make order absolutely clear
            Files.copy(source, target);
        }
    }

    // Usage: new FileCopyOperation().from(src).to(dest).execute();
}

// Fixed: String operations with clear methods
public class SafeStringOps {

    public String replaceOldWithNew(String text, String oldValue, String newValue) {
        // Method name clarifies which is which
        return text.replace(oldValue, newValue);
    }
}

// Fixed: Structured logging
public class SafeLogger {

    public void logError(String message, Throwable cause) {
        // Use structured approach
        logger.error(message, cause);
    }

    // Or use builder/record pattern
    public record LogEntry(String message, Throwable cause, Map<String, Object> context) {}

    public void log(LogEntry entry) {
        logger.error(entry.message(), entry.cause());
    }
}
# Fixed: Use keyword arguments or dataclasses
from dataclasses import dataclass

@dataclass
class NewUser:
    username: str
    email: str
    role: str = 'user'

def create_user_safe(user: NewUser):
    """Create user from structured data."""
    db.execute(
        "INSERT INTO users (username, email, role) VALUES (?, ?, ?)",
        [user.username, user.email, user.role]
    )

# Fixed: Cannot swap arguments with dataclass
def register_new_user():
    user = NewUser(
        username=request.form['username'],
        email=request.form['email'],
        role='user'
    )
    create_user_safe(user)  # Single argument - no ordering issue

# Alternative: Always use keyword arguments
def create_user_kwargs(*, username: str, email: str, role: str = 'user'):
    """Create user. Keyword-only arguments prevent positional mistakes."""
    db.execute(
        "INSERT INTO users (username, email, role) VALUES (?, ?, ?)",
        [username, email, role]
    )

# Usage - must use keyword arguments
create_user_kwargs(username="john", email="[email protected]", role="user")
# create_user_kwargs("john", "[email protected]")  # Error! Keywords required

CVE Examples

  • CVE-2006-7049: Application calling functions with wrong argument order, allowing attackers to bypass access restrictions.

References

  1. MITRE Corporation. "CWE-683: Function Call With Incorrect Order of Arguments." https://cwe.mitre.org/data/definitions/683.html
  2. CERT C Coding Standard. "EXP37-C. Call functions with the correct number and type of arguments."