Function Call with Incorrectly Specified Arguments
Description
Function Call with Incorrectly Specified Arguments occurs when a function is called with arguments that don't match the expected parameters in type, order, or meaning. This includes passing arguments in wrong order, using incorrect units (seconds vs milliseconds), mismatched formats, or semantic misunderstanding of what a parameter expects. Such errors can lead to security vulnerabilities, data corruption, or unexpected behavior.
Risk
Security functions may fail silently when given wrong parameters. Cryptographic operations with incorrect key sizes are weakened. Access control checks may pass when they should fail. Buffer operations with wrong sizes cause overflows. Time-based security (tokens, sessions) fails with wrong units. The application appears to work while security is compromised.
Solution
Use strongly-typed function signatures. Enable strict mode and type checking. Use named parameters where available. Document parameter requirements clearly. Implement parameter validation at function entry. Use code review and static analysis. Write comprehensive unit tests for edge cases.
Common Consequences
| Impact | Details |
|---|---|
| Security | Scope: Weakened Controls Security functions fail to protect properly. |
| Integrity | Scope: Data Corruption Wrong parameters corrupt data or state. |
| Availability | Scope: Crashes Type mismatches cause runtime errors. |
Example Code + Solution Code
Vulnerable Code
// VULNERABLE: Wrong argument order
void copyData(char *dest, const char *src, size_t size);
void vulnerableUsage() {
char buffer[100];
char *data = getData();
// Arguments in wrong order! (src, dest, size)
copyData(data, buffer, sizeof(buffer)); // Wrong!
}
// VULNERABLE: Wrong size parameter
void processBufferVulnerable(char *input) {
char output[256];
// Wrong: strlen vs sizeof
memcpy(output, input, strlen(output)); // Uses uninitialized output!
// Wrong: size of pointer vs size of buffer
char *buf = malloc(1024);
memset(buf, 0, sizeof(buf)); // Only clears 8 bytes (pointer size)!
}
// VULNERABLE: Wrong units (seconds vs milliseconds)
void setTimeoutVulnerable() {
// API expects milliseconds
setTimeout(callback, 60); // Intended 60 seconds, got 60 milliseconds!
// API expects seconds but given milliseconds
setSessionExpiry(3600000); // Intended 1 hour, got 3.6 million seconds!
}
// VULNERABLE: Type coercion issues
void handleUserVulnerable(int userId) {
// Check if user is admin (admin ID is 1)
if (userId = 1) { // Assignment, not comparison!
grantAdminAccess();
}
}
// VULNERABLE: Wrong encryption parameters
public class VulnerableCrypto {
public byte[] encrypt(byte[] data, byte[] key) throws Exception {
// Wrong: key and IV swapped
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Using key as IV - security weakness!
IvParameterSpec iv = new IvParameterSpec(key); // Should be random IV!
cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
return cipher.doFinal(data);
}
// VULNERABLE: Wrong argument meanings
public void setPermissions(String resource, String user, int level) {
// Caller confused argument order
}
public void usePermissions() {
// Wrong order: passed level, user, resource
setPermissions("admin", "document.txt", 5); // Swapped user and resource!
}
}
// VULNERABLE: Substring with wrong indices
public class StringHandler {
public String extractVulnerable(String input, int start, int end) {
// Wrong: end is exclusive in substring but caller thinks inclusive
return input.substring(start, end);
}
public void usage() {
String data = "SECRET_VALUE";
// Wants characters 0-5 inclusive, but gets 0-4
String result = extractVulnerable(data, 0, 5); // Gets "SECRE" not "SECRET"
}
}
# VULNERABLE: Mutable default argument
def append_item_vulnerable(item, target_list=[]):
# Mutable default is shared across calls!
target_list.append(item)
return target_list
result1 = append_item_vulnerable(1) # [1]
result2 = append_item_vulnerable(2) # [1, 2] - unexpected!
# VULNERABLE: Wrong positional arguments
def create_user(username, password, is_admin=False):
# Create user with given properties
pass
# Caller swapped arguments
create_user("admin123", "john_doe") # password used as username!
# VULNERABLE: Format string issues
def log_message_vulnerable(message, level):
# Format string expects (level, message)
print(f"[{message}] {level}") # Swapped!
# VULNERABLE: Time units confusion
import time
def rate_limit_vulnerable(requests_per_second):
# Sleep expects seconds, but caller might pass milliseconds
time.sleep(1 / requests_per_second)
rate_limit_vulnerable(1000) # Intended 1000 req/sec, sleeps 0.001 seconds
# VULNERABLE: Boolean argument confusion
def search_users(query, case_sensitive, include_deleted):
pass
# What does True, False mean without context?
search_users("admin", True, False)
// VULNERABLE: Callback argument order
function fetchData(url, errorCallback, successCallback) {
// Common pattern has success first, error second
}
// Caller expects (url, success, error)
fetchData('/api/data',
(data) => console.log(data), // This is actually errorCallback!
(err) => console.error(err) // This is actually successCallback!
);
// VULNERABLE: setTimeout units
setTimeout(() => {
refreshToken();
}, 60); // 60 milliseconds, not 60 seconds!
// VULNERABLE: Array method confusion
const users = ['admin', 'user', 'guest'];
// splice vs slice confusion
const removed = users.slice(1, 1); // Returns empty array, doesn't remove
// Wanted: users.splice(1, 1) to remove element at index 1
// VULNERABLE: Comparison vs assignment
function checkAdmin(user) {
if (user.role = 'admin') { // Assignment!
return true;
}
return false;
}
Fixed Code
// SAFE: Clear parameter names and validation
typedef struct {
char *dest;
const char *src;
size_t dest_size;
size_t src_size;
} CopyParams;
int copyDataSafe(CopyParams *params) {
if (!params || !params->dest || !params->src) {
return -1;
}
size_t copy_size = params->src_size < params->dest_size
? params->src_size
: params->dest_size - 1;
memcpy(params->dest, params->src, copy_size);
params->dest[copy_size] = '\0';
return 0;
}
// SAFE: Proper size calculations
void processBufferSafe(const char *input, size_t input_len) {
if (input_len > 255) {
input_len = 255;
}
char output[256];
memset(output, 0, sizeof(output)); // sizeof(output) is 256
memcpy(output, input, input_len);
}
// SAFE: Clear time units in naming
void setTimeoutSeconds(void (*callback)(void), int seconds) {
setTimeoutMillis(callback, seconds * 1000);
}
void setTimeoutMillis(void (*callback)(void), int millis) {
// Implementation
}
// SAFE: Comparison, not assignment
void handleUserSafe(int userId) {
if (userId == 1) { // Correct comparison
grantAdminAccess();
}
}
// SAFE: Builder pattern for complex parameters
public class SafeCrypto {
public static class EncryptionParams {
private final byte[] data;
private final byte[] key;
private final byte[] iv;
private EncryptionParams(Builder builder) {
this.data = builder.data;
this.key = builder.key;
this.iv = builder.iv;
}
public static class Builder {
private byte[] data;
private byte[] key;
private byte[] iv;
public Builder data(byte[] data) {
this.data = data;
return this;
}
public Builder key(byte[] key) {
if (key.length != 16 && key.length != 24 && key.length != 32) {
throw new IllegalArgumentException("Invalid key size");
}
this.key = key;
return this;
}
public Builder iv(byte[] iv) {
if (iv.length != 16) {
throw new IllegalArgumentException("IV must be 16 bytes");
}
this.iv = iv;
return this;
}
public EncryptionParams build() {
if (data == null || key == null || iv == null) {
throw new IllegalStateException("Missing required parameters");
}
return new EncryptionParams(this);
}
}
}
public byte[] encrypt(EncryptionParams params) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(params.key, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(params.iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
return cipher.doFinal(params.data);
}
}
// Usage - clear and type-safe
byte[] encrypted = crypto.encrypt(
new SafeCrypto.EncryptionParams.Builder()
.data(plaintext)
.key(secretKey)
.iv(secureRandom.generateSeed(16))
.build()
);
from typing import Optional, List
from dataclasses import dataclass
from enum import Enum
# SAFE: Immutable default, type hints
def append_item_safe(item: str, target_list: Optional[List[str]] = None) -> List[str]:
if target_list is None:
target_list = []
target_list.append(item)
return target_list
# SAFE: Named parameters and dataclass
@dataclass
class UserCreationParams:
username: str
password: str
is_admin: bool = False
def create_user_safe(params: UserCreationParams) -> None:
# Clear what each field means
pass
# Usage
create_user_safe(UserCreationParams(
username="john_doe",
password="secure123",
is_admin=False
))
# SAFE: Explicit time units
class TimeUnit(Enum):
SECONDS = 1
MILLISECONDS = 1000
MINUTES = 1/60
def rate_limit_safe(requests_per: int, unit: TimeUnit) -> None:
seconds = 1 / (requests_per * unit.value)
time.sleep(seconds)
rate_limit_safe(1000, TimeUnit.SECONDS) # Clear: 1000 per second
# SAFE: Boolean arguments with clear names
def search_users_safe(
query: str,
*, # Force keyword arguments
case_sensitive: bool = True,
include_deleted: bool = False
) -> List[str]:
pass
# Must use named arguments - much clearer
search_users_safe("admin", case_sensitive=True, include_deleted=False)
// SAFE: Options object pattern
function fetchDataSafe(url, options) {
const {
onSuccess = () => {},
onError = () => {},
timeout = 30000
} = options;
// Clear which callback is which
fetch(url)
.then(onSuccess)
.catch(onError);
}
// Usage - clear naming
fetchDataSafe('/api/data', {
onSuccess: (data) => console.log(data),
onError: (err) => console.error(err)
});
// SAFE: Constants for time values
const SECONDS = 1000;
const MINUTES = 60 * SECONDS;
setTimeout(() => {
refreshToken();
}, 60 * SECONDS); // Clear: 60 seconds
// SAFE: Explicit comparison
function checkAdminSafe(user) {
if (user.role === 'admin') { // Strict equality
return true;
}
return false;
}
// SAFE: TypeScript for type safety
interface SearchOptions {
query: string;
caseSensitive?: boolean;
includeDeleted?: boolean;
}
function searchUsersSafe(options: SearchOptions): User[] {
const { query, caseSensitive = true, includeDeleted = false } = options;
// Implementation
}
Exploited in the Wild
Cryptographic Weaknesses
Wrong IV/key parameters weakened encryption.
Buffer Overflows
Incorrect size arguments caused memory corruption.
Authentication Bypass
Swapped credential parameters allowed unauthorized access.
Tools to test/exploit
-
Static analysis (ESLint, Pylint, clang-tidy).
-
Type checkers (TypeScript, mypy, flow).
-
Unit testing with edge cases.
CVE Examples
-
Buffer overflows from incorrect size parameters.
-
Crypto weaknesses from parameter confusion.
References
-
MITRE. "CWE-628: Function Call with Incorrectly Specified Arguments." https://cwe.mitre.org/data/definitions/628.html
-
Code review best practices documentation.