Use of Multiple Resources with Duplicate Identifier

Description

Use of Multiple Resources with Duplicate Identifier is a vulnerability where software uses multiple resources that share the same identifier in a context that requires each identifier to be unique. The product assumes that each resource has a unique identifier but fails to enforce this assumption, leading to situations where operations intended for one resource may affect a different resource with the same identifier. This can result in security bypasses, data corruption, or unpredictable application behavior when the system cannot distinguish between resources.

Risk

Duplicate identifiers create significant security and reliability risks. Attackers can exploit this weakness to bypass security controls that assume identifier uniqueness—for example, by creating a malicious resource with the same identifier as a legitimate one, causing the system to use the wrong resource. In validation scenarios, duplicate form names or configuration entries may cause the system to skip validation entirely or apply incorrect rules. File systems with duplicate filenames in archives can lead to files being overwritten or the wrong file being executed. The risk is particularly severe when identifiers are used for access control decisions.

Solution

Validate that identifiers are unique before accepting new resources. Implement uniqueness constraints at the database or storage level. When duplicate identifiers are detected, refuse to operate on any resource with a non-unique identifier and report the error appropriately. Use UUIDs or other guaranteed-unique identifier schemes where possible. Enforce uniqueness during resource creation rather than assuming it exists. Log and alert on duplicate identifier detection as it may indicate an attack attempt.

Common Consequences

ImpactDetails
Access ControlScope: Access Control

Bypass Protection Mechanism - Security checks based on unique identifier assumptions may be circumvented.
IntegrityScope: Integrity

Modify Application Data - Operations may affect unintended resources when identifiers collide.
OtherScope: Other

Quality Degradation - Application behavior becomes unpredictable when resources cannot be uniquely identified.

Example Code

Vulnerable Code

<!-- Vulnerable: Struts configuration with duplicate form names -->
<form-validation>
    <formset>
        <!-- First ProjectForm definition with strict validation -->
        <form name="ProjectForm">
            <field property="name" depends="required,maxlength">
                <arg0 key="form.project.name"/>
                <arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
                <var>
                    <var-name>maxlength</var-name>
                    <var-value>100</var-value>
                </var>
            </field>
            <field property="budget" depends="required,double">
                <arg0 key="form.project.budget"/>
            </field>
        </form>

        <!-- Vulnerable: Duplicate form name with weaker validation -->
        <form name="ProjectForm">
            <!-- This form has no validation rules! -->
            <!-- Struts may use this one instead, bypassing validation -->
        </form>
    </formset>
</form-validation>
// Vulnerable: Java map with duplicate keys
import java.util.*;

public class VulnerableConfig {

    // Vulnerable: Configuration loading doesn't detect duplicates
    public Map<String, String> loadConfig(List<ConfigEntry> entries) {
        Map<String, String> config = new HashMap<>();

        for (ConfigEntry entry : entries) {
            // Vulnerable: Later duplicates silently overwrite earlier values
            config.put(entry.getKey(), entry.getValue());
            // Attacker-controlled last entry for a key wins
        }

        return config;
    }

    // Vulnerable: User lookup with duplicate usernames
    public User findUser(String username) {
        // If multiple users have same username, which one is returned?
        List<User> users = database.query(
            "SELECT * FROM users WHERE username = ?", username);

        // Vulnerable: Just returns first match
        return users.isEmpty() ? null : users.get(0);
        // Attacker might have created duplicate to get different user's data
    }
}
# Vulnerable: Archive extraction with duplicate filenames (CVE-2013-4787 pattern)
import zipfile
import os

def vulnerable_extract_archive(archive_path, dest_dir):
    with zipfile.ZipFile(archive_path, 'r') as zf:
        for info in zf.infolist():
            # Vulnerable: No check for duplicate filenames
            # Second file with same name overwrites first
            zf.extract(info, dest_dir)

# Attack scenario:
# Archive contains:
#   legitimate_app.dll (signed, verified)
#   legitimate_app.dll (unsigned, malicious)
#
# Verification system:
# 1. Verifies first legitimate_app.dll - passes signature check
# 2. Extracts second legitimate_app.dll - overwrites verified one
# 3. Runs malicious unsigned version

def vulnerable_verify_and_install(archive_path):
    # Verify all files in archive
    for filename in get_archive_files(archive_path):
        if not verify_signature(archive_path, filename):
            raise SecurityError("Invalid signature")

    # Vulnerable: Extract after verification
    # Duplicate filenames cause overwrite with unverified content
    extract_archive(archive_path, INSTALL_DIR)
// Vulnerable: Resource pool with duplicate IDs
#include <stdio.h>
#include <string.h>

typedef struct {
    int id;
    char* name;
    int permission_level;
} Resource;

Resource resources[100];
int resource_count = 0;

// Vulnerable: No uniqueness check on resource ID
int add_resource(int id, char* name, int perm_level) {
    // Vulnerable: Allows duplicate IDs
    resources[resource_count].id = id;
    resources[resource_count].name = strdup(name);
    resources[resource_count].permission_level = perm_level;
    resource_count++;
    return 0;
}

// Vulnerable: Find returns first match, ignoring duplicates
Resource* find_resource(int id) {
    for (int i = 0; i < resource_count; i++) {
        if (resources[i].id == id) {
            return &resources[i];  // First match returned
        }
    }
    return NULL;
}

// Attack: Create high-permission resource with same ID as low-permission one
// If checks use find_resource and it returns high-permission one...
// Or vice versa - create low-permission version to bypass checks

Fixed Code

<!-- Fixed: Unique form names enforced by schema or validation -->
<form-validation>
    <formset>
        <form name="ProjectForm">
            <field property="name" depends="required,maxlength">
                <arg0 key="form.project.name"/>
                <arg1 name="maxlength" key="${var:maxlength}" resource="false"/>
                <var>
                    <var-name>maxlength</var-name>
                    <var-value>100</var-value>
                </var>
            </field>
            <field property="budget" depends="required,double">
                <arg0 key="form.project.budget"/>
            </field>
        </form>

        <!-- Different names for different forms -->
        <form name="ProjectFormSimple">
            <!-- Simplified validation for different context -->
        </form>
    </formset>
</form-validation>

<!-- Use validation tool that detects duplicates at startup -->
// Fixed: Detect and reject duplicates
import java.util.*;

public class SecureConfig {

    // Fixed: Detect duplicate keys
    public Map<String, String> loadConfigSecure(List<ConfigEntry> entries)
            throws DuplicateKeyException {
        Map<String, String> config = new HashMap<>();

        for (ConfigEntry entry : entries) {
            String key = entry.getKey();

            // Fixed: Check for existing key before adding
            if (config.containsKey(key)) {
                throw new DuplicateKeyException(
                    "Duplicate configuration key: " + key);
            }

            config.put(key, entry.getValue());
        }

        return config;
    }

    // Fixed: Enforce uniqueness at database level
    public User findUserSecure(String username) throws DuplicateUserException {
        List<User> users = database.query(
            "SELECT * FROM users WHERE username = ?", username);

        // Fixed: Detect and report duplicates
        if (users.size() > 1) {
            throw new DuplicateUserException(
                "Multiple users with username: " + username);
        }

        return users.isEmpty() ? null : users.get(0);
    }

    // Fixed: Database constraint ensures uniqueness
    public void createUser(String username) {
        // Database has UNIQUE constraint on username column
        // INSERT will fail if duplicate exists
        database.execute(
            "INSERT INTO users (username) VALUES (?)", username);
    }
}
# Fixed: Secure archive extraction with duplicate detection
import zipfile
import os

def secure_extract_archive(archive_path, dest_dir):
    with zipfile.ZipFile(archive_path, 'r') as zf:
        # Fixed: Build set of filenames to detect duplicates
        seen_names = set()

        for info in zf.infolist():
            normalized_name = os.path.normpath(info.filename)

            # Fixed: Check for duplicate filenames
            if normalized_name in seen_names:
                raise SecurityError(
                    f"Duplicate filename in archive: {normalized_name}")
            seen_names.add(normalized_name)

        # Only extract after verifying no duplicates
        zf.extractall(dest_dir)

# Fixed: Atomic verify-and-extract
def secure_verify_and_install(archive_path):
    # Check for duplicates first
    filenames = get_archive_files(archive_path)
    if len(filenames) != len(set(filenames)):
        raise SecurityError("Archive contains duplicate filenames")

    # Verify all files
    for filename in filenames:
        if not verify_signature(archive_path, filename):
            raise SecurityError(f"Invalid signature: {filename}")

    # Extract after verification - no duplicates to cause overwrite
    extract_archive(archive_path, INSTALL_DIR)
// Fixed: Unique resource IDs enforced
#include <stdio.h>
#include <string.h>

typedef struct {
    int id;
    char* name;
    int permission_level;
} Resource;

Resource resources[100];
int resource_count = 0;

// Fixed: Check uniqueness before adding
int add_resource_secure(int id, char* name, int perm_level) {
    // Fixed: Check if ID already exists
    for (int i = 0; i < resource_count; i++) {
        if (resources[i].id == id) {
            return -1;  // Error: duplicate ID
        }
    }

    resources[resource_count].id = id;
    resources[resource_count].name = strdup(name);
    resources[resource_count].permission_level = perm_level;
    resource_count++;
    return 0;
}

// Fixed: Verify uniqueness and handle duplicates
Resource* find_resource_secure(int id, int* count) {
    Resource* result = NULL;
    *count = 0;

    for (int i = 0; i < resource_count; i++) {
        if (resources[i].id == id) {
            if (result == NULL) {
                result = &resources[i];
            }
            (*count)++;
        }
    }

    // Caller can check count to detect duplicates
    return result;
}

int access_resource(int id) {
    int count;
    Resource* res = find_resource_secure(id, &count);

    // Fixed: Refuse to operate if duplicates exist
    if (count > 1) {
        log_error("Duplicate resource ID detected: %d", id);
        return -1;
    }

    if (res == NULL) {
        return -1;
    }

    return process_resource(res);
}

CVE Examples

  • CVE-2013-4787: Android "Master Key" vulnerability—mobile OS verified cryptographic signatures on archived files but installed different files with identical names.
  • CVE-2017-12617: Apache Tomcat duplicate parameter handling vulnerability.

References

  1. MITRE Corporation. "CWE-694: Use of Multiple Resources with Duplicate Identifier." https://cwe.mitre.org/data/definitions/694.html
  2. CWE-102: Struts Duplicate Validation Forms.
  3. CWE-462: Duplicate Key in Associative List.