Lets examine CAPTCHA user validation algorithm, paying attention to protection against vulnerabilities which are not concerned with image recognition:
User loads protected page, we create session for him. Will be best, if the session would be created by CAPTCHA image script itself.
The script generates random text, writes it to session and outputs image with this text to the user. And, while validating, user entered text is compared with the one from session.
It is important if encoded text can't be calculated anyway from the data transferred to browser. For instance, idea to transfer the text (even encrypted) as an argument (in address line or in cookie), not storing on server in session, is bad. The text can be decoded or substituted by other one.
If random text would be generated while generating page with input form, not while generating image, bot will has an opportunity to make many requests to image script directly having many variants of same text (if distortion of the text varies). Having pack of variants may simplify text recognition.
Code generation by image inself also allow to create feature "generate another code, if this one unreadable" — simply refresh the image.
Common mistake is comparing entered text with one from session while validating user input. Hacker can give us identificator of non-existent session and enter empty validation text. And empty text will be equal to one fron non-existent session. So you must check text in the session if it is not empty.
It is important to clean session after each validation (successfull or not). Do not consider on generation of new text while refreshing an image. Hacker can read image at first time, give answer to bot, so it could send this answer submitting form many times not loading an CAPTCHA image.
If you would pay attention to this moments, your CAPTCHA will be protected against bots which uses no image recognition. See next article about recognition-protected images generating.