The UI Performs the Wrong Action

Description

The UI Performs the Wrong Action is a vulnerability where the user interface executes an incorrect operation despite receiving proper user input. When a user initiates an action through the UI, the system performs a different action than intended, potentially leading to security violations, data loss, or system misconfiguration. This can occur due to implementation bugs, incorrect mappings between UI elements and backend functions, or logic errors in action dispatch.

Risk

When UI performs wrong actions, users lose control over system behavior. Security settings may be misconfigured when users believe they are applying restrictions. Sensitive data may be exposed when users attempt to protect it. Access permissions may be granted when users intend to revoke them. The risk is amplified because users trust that the system will perform the action they requested, and may not verify the actual outcome. Attackers can exploit predictable wrong-action patterns to manipulate systems through legitimate user interactions.

Solution

Implement comprehensive testing that verifies UI actions produce correct backend results. Use automated UI testing frameworks that validate action outcomes, not just UI state changes. Map UI elements to backend functions through a centralized, auditable dispatch mechanism. Implement action confirmation for critical operations that shows exactly what will be performed. Log all actions with both intended and actual operations for audit purposes. Use contract testing between UI and backend to ensure action semantics remain consistent across updates.

Common Consequences

ImpactDetails
OtherScope: Other

Quality Degradation - System quality degrades when user actions produce unexpected results, leading to user frustration and potential security issues.
OtherScope: Other

Varies by Context - Security impact depends on the specific wrong action performed. May cause data exposure, access control bypass, or configuration errors.

Example Code

Vulnerable Code

// Vulnerable: Button click handlers mapped incorrectly
class VulnerableUserManagement {

    constructor() {
        // Vulnerable: Action handlers mixed up
        this.actions = {
            'grant_access': this.revokeUserAccess.bind(this),  // WRONG!
            'revoke_access': this.grantUserAccess.bind(this),  // WRONG!
            'delete_user': this.suspendUser.bind(this),        // Wrong action
            'suspend_user': this.deleteUser.bind(this)         // Wrong action
        };
    }

    handleButtonClick(action, userId) {
        // User clicks "Revoke Access" but grants access instead
        if (this.actions[action]) {
            return this.actions[action](userId);
        }
    }

    grantUserAccess(userId) {
        setUserPermission(userId, 'full_access');
        return { message: 'User access granted' };  // Correct message, wrong action
    }

    revokeUserAccess(userId) {
        setUserPermission(userId, 'no_access');
        return { message: 'User access revoked' };  // Correct message, wrong action
    }
}
# Vulnerable: Form submission performs wrong database operation
class VulnerableDataForm:
    def handle_submit(self, form_data, operation):
        # Vulnerable: Operation parameter doesn't match actual operation
        if operation == 'encrypt':
            # Bug: Actually decrypts instead of encrypts
            return self.decrypt_data(form_data)  # WRONG ACTION!

        elif operation == 'decrypt':
            # Bug: Actually encrypts instead of decrypts
            return self.encrypt_data(form_data)  # WRONG ACTION!

        elif operation == 'delete_selected':
            # Bug: Deletes ALL instead of selected
            return self.delete_all()  # WRONG ACTION!

    def process_file_operation(self, filename, action):
        # Vulnerable: Copy/paste error in conditions
        if action == 'make_public':
            self.set_private(filename)  # WRONG - should be set_public

        elif action == 'make_private':
            self.set_public(filename)   # WRONG - should be set_private

        return f"File {filename}: {action} completed"  # Misleading message
// Vulnerable: Firewall rules applied with wrong direction
public class VulnerableFirewallUI {

    public void applyRule(FirewallRule rule) {
        // Vulnerable: UI says "Block Inbound" but blocks outbound
        if (rule.getDirection() == Direction.INBOUND) {
            // Bug: Wrong method called
            blockOutbound(rule.getPort());  // Should be blockInbound!
        } else if (rule.getDirection() == Direction.OUTBOUND) {
            // Bug: Wrong method called
            blockInbound(rule.getPort());   // Should be blockOutbound!
        }

        // User interface shows "Blocked inbound traffic on port 443"
        // Actually blocked outbound - users can't reach HTTPS sites
        logRuleApplication(rule);
    }

    // Vulnerable: Toggle performs opposite action
    public void toggleFeature(String feature, boolean enable) {
        switch (feature) {
            case "intrusion_detection":
                if (enable) {
                    disableIDS();  // WRONG - should enable
                } else {
                    enableIDS();   // WRONG - should disable
                }
                break;

            case "logging":
                // Bug: Timeout functionality inverted
                if (enable) {
                    setLogTimeout(0);     // Disables logging!
                } else {
                    setLogTimeout(3600);  // Enables logging!
                }
                break;
        }
    }
}
// Vulnerable: Command-line tool with wrong option implementation
#include <stdio.h>
#include <string.h>

// Vulnerable: Options do opposite of documentation
void process_options(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "--enable-encryption") == 0) {
            // Bug: Disables instead of enables
            disable_encryption();  // WRONG ACTION
            printf("Encryption enabled\n");  // Misleading output

        } else if (strcmp(argv[i], "--disable-logging") == 0) {
            // Bug: Enables instead of disables
            enable_detailed_logging();  // WRONG ACTION
            printf("Logging disabled\n");  // User thinks logging is off
            // Actually, detailed logging enabled - privacy issue
        }
    }
}

// Vulnerable: Permission bits set incorrectly
void set_file_permissions(const char *filename, const char *mode) {
    if (strcmp(mode, "private") == 0) {
        // Bug: Sets world-readable instead of private
        chmod(filename, 0644);  // WRONG - should be 0600
        printf("File set to private\n");

    } else if (strcmp(mode, "public") == 0) {
        // Bug: Sets private instead of public
        chmod(filename, 0600);  // WRONG - should be 0644
        printf("File set to public\n");
    }
}

Fixed Code

// Fixed: Action handlers with verification
class SecureUserManagement {

    constructor() {
        // Fixed: Clear, verified action mappings
        this.actions = new Map([
            ['grant_access', {
                handler: this.grantUserAccess.bind(this),
                verify: this.verifyAccessGranted.bind(this),
                description: 'Grant user access'
            }],
            ['revoke_access', {
                handler: this.revokeUserAccess.bind(this),
                verify: this.verifyAccessRevoked.bind(this),
                description: 'Revoke user access'
            }],
            ['delete_user', {
                handler: this.deleteUser.bind(this),
                verify: this.verifyUserDeleted.bind(this),
                description: 'Permanently delete user'
            }],
            ['suspend_user', {
                handler: this.suspendUser.bind(this),
                verify: this.verifyUserSuspended.bind(this),
                description: 'Suspend user account'
            }]
        ]);
    }

    async handleButtonClick(action, userId) {
        const actionConfig = this.actions.get(action);

        if (!actionConfig) {
            return { success: false, error: 'Unknown action' };
        }

        // Fixed: Log intended action
        auditLog.record('ACTION_INITIATED', {
            action,
            userId,
            description: actionConfig.description,
            timestamp: Date.now()
        });

        // Fixed: Execute action
        const result = await actionConfig.handler(userId);

        // Fixed: Verify correct action was performed
        const verified = await actionConfig.verify(userId);

        if (!verified) {
            // Fixed: Alert on verification failure
            auditLog.record('ACTION_VERIFICATION_FAILED', {
                action,
                userId,
                timestamp: Date.now()
            });

            return {
                success: false,
                error: 'Action verification failed - please check system state'
            };
        }

        return {
            success: true,
            action: action,
            verified: true
        };
    }

    async verifyAccessGranted(userId) {
        const user = await getUser(userId);
        return user.permission === 'full_access';
    }

    async verifyAccessRevoked(userId) {
        const user = await getUser(userId);
        return user.permission === 'no_access';
    }
}
# Fixed: Form submission with action verification
class SecureDataForm:
    ACTION_MAP = {
        'encrypt': ('encrypt_data', lambda d: d.is_encrypted),
        'decrypt': ('decrypt_data', lambda d: not d.is_encrypted),
        'delete_selected': ('delete_selected', lambda d: d.selected_deleted),
    }

    def handle_submit(self, form_data, operation):
        if operation not in self.ACTION_MAP:
            raise ValueError(f"Unknown operation: {operation}")

        method_name, verify_func = self.ACTION_MAP[operation]
        method = getattr(self, method_name)

        # Fixed: Log intended operation
        logger.info(f"Executing operation: {operation}")

        # Fixed: Execute correct method
        result = method(form_data)

        # Fixed: Verify operation result
        if not verify_func(result):
            logger.error(f"Operation verification failed: {operation}")
            raise OperationError(f"{operation} verification failed")

        logger.info(f"Operation verified: {operation}")
        return result

    def encrypt_data(self, data):
        encrypted = self._perform_encryption(data)
        encrypted.is_encrypted = True
        return encrypted

    def decrypt_data(self, data):
        decrypted = self._perform_decryption(data)
        decrypted.is_encrypted = False
        return decrypted

    def process_file_operation(self, filename, action):
        # Fixed: Use action constants
        if action == FileAction.MAKE_PUBLIC:
            self.set_public(filename)
            # Fixed: Verify permission was set correctly
            if not self.is_public(filename):
                raise OperationError("Failed to make file public")

        elif action == FileAction.MAKE_PRIVATE:
            self.set_private(filename)
            # Fixed: Verify permission was set correctly
            if not self.is_private(filename):
                raise OperationError("Failed to make file private")

        return f"File {filename}: {action} verified"
// Fixed: Firewall rules with direction verification
public class SecureFirewallUI {

    public FirewallResult applyRule(FirewallRule rule) {
        Direction direction = rule.getDirection();
        int port = rule.getPort();

        // Fixed: Clear action mapping
        if (direction == Direction.INBOUND) {
            blockInbound(port);
        } else if (direction == Direction.OUTBOUND) {
            blockOutbound(port);
        }

        // Fixed: Verify rule was applied correctly
        FirewallState state = getCurrentFirewallState();

        boolean verified = false;
        if (direction == Direction.INBOUND) {
            verified = state.isInboundBlocked(port);
        } else if (direction == Direction.OUTBOUND) {
            verified = state.isOutboundBlocked(port);
        }

        if (!verified) {
            // Fixed: Report verification failure
            logError("Firewall rule verification failed", rule);
            return FirewallResult.verificationFailed(rule);
        }

        logRuleApplication(rule);
        return FirewallResult.success(rule);
    }

    public ToggleResult toggleFeature(String feature, boolean enable) {
        // Fixed: Use action enum to prevent mixups
        FeatureAction action = enable ? FeatureAction.ENABLE : FeatureAction.DISABLE;

        switch (feature) {
            case "intrusion_detection":
                return toggleIDS(action);

            case "logging":
                return toggleLogging(action);

            default:
                return ToggleResult.unknownFeature(feature);
        }
    }

    private ToggleResult toggleIDS(FeatureAction action) {
        if (action == FeatureAction.ENABLE) {
            enableIDS();
            // Fixed: Verify IDS is actually enabled
            if (!isIDSEnabled()) {
                return ToggleResult.verificationFailed("IDS enable");
            }
        } else {
            disableIDS();
            // Fixed: Verify IDS is actually disabled
            if (isIDSEnabled()) {
                return ToggleResult.verificationFailed("IDS disable");
            }
        }

        return ToggleResult.success(action);
    }
}
// Fixed: Command-line tool with correct action implementation
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>

typedef enum { ACTION_ENABLE, ACTION_DISABLE } Action;

// Fixed: Action struct ties option to correct function and verification
typedef struct {
    const char *option;
    void (*action_func)(void);
    int (*verify_func)(void);
    const char *success_msg;
    const char *failure_msg;
} OptionAction;

int verify_encryption_enabled(void) {
    return is_encryption_active();
}

int verify_logging_disabled(void) {
    return !is_logging_active();
}

// Fixed: Clear mapping between options and actions
OptionAction options[] = {
    {
        "--enable-encryption",
        enable_encryption,      // Correct function
        verify_encryption_enabled,
        "Encryption enabled and verified",
        "Encryption enable verification failed"
    },
    {
        "--disable-logging",
        disable_logging,        // Correct function
        verify_logging_disabled,
        "Logging disabled and verified",
        "Logging disable verification failed"
    }
};

void process_options(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        for (size_t j = 0; j < sizeof(options)/sizeof(options[0]); j++) {
            if (strcmp(argv[i], options[j].option) == 0) {
                // Fixed: Execute action
                options[j].action_func();

                // Fixed: Verify action result
                if (options[j].verify_func()) {
                    printf("%s\n", options[j].success_msg);
                } else {
                    fprintf(stderr, "ERROR: %s\n", options[j].failure_msg);
                    exit(1);
                }
                break;
            }
        }
    }
}

// Fixed: Permission setting with verification
int set_file_permissions(const char *filename, const char *mode) {
    mode_t target_mode;

    if (strcmp(mode, "private") == 0) {
        target_mode = 0600;
    } else if (strcmp(mode, "public") == 0) {
        target_mode = 0644;
    } else {
        fprintf(stderr, "Unknown mode: %s\n", mode);
        return -1;
    }

    // Fixed: Set permissions
    if (chmod(filename, target_mode) != 0) {
        perror("chmod failed");
        return -1;
    }

    // Fixed: Verify permissions were set correctly
    struct stat st;
    if (stat(filename, &st) != 0) {
        perror("stat failed");
        return -1;
    }

    if ((st.st_mode & 0777) != target_mode) {
        fprintf(stderr, "Permission verification failed\n");
        return -1;
    }

    printf("File %s set to %s (mode %o verified)\n", filename, mode, target_mode);
    return 0;
}

CVE Examples

  • CVE-2001-1387 - Network firewall implemented incorrect command-line options, potentially causing information leaks.
  • CVE-2001-0081 - User prompts were suppressed but underlying features remained active despite specification requirements.
  • CVE-2002-1977 - Timeout functionality failed to operate per user specifications, exposing sensitive data beyond intended duration.

References

  1. MITRE Corporation. "CWE-449: The UI Performs the Wrong Action." https://cwe.mitre.org/data/definitions/449.html
  2. OWASP Testing Guide. "Business Logic Testing."