No puedo encontrar la vulnerabilidad en este programa C

Estudiando para un examen encontré el siguiente problema que no puedo resolver. La primera pregunta es encontrar el error en el código, la segunda es dar un ejemplo de cómo un atacante puede aprovechar el error. Por lo tanto, es explotable y tiene que tener algo que ver con una de las declaraciones 'fscanf', supongo, pero no sé cuál es la vulnerabilidad, ya que todos leen 1 byte menos que el tamaño del búfer para dar espacio para el terminador nulo.

#define USR_LEN 16
#define PWD_LEN 16
#define EMAIL_LEN 32

// Fetches password for given username and stores it into 'destination'
// Passwords are never longer than 15 characters.
// Returns 0 on success and 1 on error.
int get_pwd_from_user_db(const char* username, char* destination);

// Sends a password-reset link to given email, provided that the email is
// registered with the given username. Returns 0 on success and 1 on error.
int request_email(const char* username, const char* email);

// Performs credentials check. Returns 0 on successful login and 1 on
// failed login or error.
int login()
{
    char username[USR_LEN];
    char given_password[PWD_LEN];
    char email[USR_LEN];
    char stored_password[PWD_LEN];
    int choice;

    printf("User name: ");
    // Read string from standard input. Given format specifier "%Ns" fscanf will
    // read at most N characters into destination buffer ('username' here), or
    // until whitespace (e.g. newline) is encountered. A null terminator is
    // always appended after the last read character in the destination buffer.
    fscanf(stdin, "%15s", username);
    if(get_pwd_from_user_db(username, stored_password) != 0) {    
        printf("Error accessing user database\n");
        return 1;
    }
    // Loop until explicitly terminated with return statement
    while(1) {
        printf("Choose action:\n");
        printf(" 1: Proceed to type password\n");
        printf(" 2: Cancel login\n");
        printf(" 3: Request password reset email\n");
        // Read one integer from standard input into 'choice'
        fscanf(stdin, "%d", &choice);

        if(choice == 1) {
            printf("Password: ");
            fscanf(stdin, "%15s", given_password);
            // strcmp returns 0 if strings are equal
            if(strcmp(given_password, stored_password) == 0) {
                printf("Login successful!\n");
                return 0;
            } else {
                printf("Incorrect password!\n");
                return 1;
            }
        } else if(choice == 2) {
            return 1;
        } else if(choice == 3) {
            printf("Email address: ");
            fscanf(stdin, "%31s", email);
            if(request_email(username, email) != 0) {
                printf("Error sending email\n");
                return 1;
            } else {
                printf("A password reset link has been sent!\n");
            }
        } else {
            printf("Invalid choice, please try again.\n");
        }
    }
}
Answer

emailse declara con char email[USR_LEN];y USR_LENes 16, pero se lee con fscanf(stdin, "%31s", email);.

Además, los resultados de fscanfno se prueban. El usuario puede usar Control-D(en Unix) para no generar entrada, dejando los búferes sin inicializar, y luego strcmppuede desbordar un búfer.