If an attacker gets access to the stored hashes and knows that each of these only encodes a single character he can brute-force this character with very few guesses. The salt does not protect against this since it is part of the stored password hash and thus known to the attacker. The slow-down done by bcrypt does not help either since only a few characters are to guess.
Even worse, once the attacker got access to the first 3 characters of the password this easy way brute-forcing the remaining characters is considerably less effort as if the password would need to be brute-forced in full.
If there is no separate hash for each of the first 3 characters but only one hash over all three together it is not as insecure as with three one-letter passwords but still totally insecure.
In order to make the problem of storing one or few instead of all characters of a password in a separate hash more clear show the math involved consider the following an example:
- Assuming that a password consists of 100 random digits.
- When brute-forcing this password at once an attacker would need to check at most all 2^100 permutations and on average the half which is still too much for practical attacks.
- But, if all these digits are stored in separate hashes and the attacker thus gets a positive feedback already after cracking the digit for a specific position he only needs at most 10 attempts for each position and thus 10*100 attempts in total. This makes the password trivially to crack within a short time even if each attempt would take a full second. And no salt will protect against this.
- If you don't hash a single digit but only combinations of 3 digits it gets a little bit better but is still far from secure. In this case each of these hashes for 3 digits would need at most 1000 tries. With 33 of such hashes (and one for a single digit) o store the original 100 digit password an attacker would need at most 33*1000+10 attempts, i.e. it is still absurdly insecure.