It's really important to keep in mind, that memory vulnerabilities are from the only issues out there.
I've found that it's the logic errors, which really bring a program to its knees. Several have lead me to successful DDoS or RCE. These occur in all languages, human error can easily and frequently be exploited.
Here is a list of some, in no particular order:
Improper input validation
Real-World-Example: Injection. Being part of the OWASP Top 10, it can be found anywhere, and in any language. Especially SQL injection and XSS stand out.
Real-World-Example: These more often that not lead to a DDoS. I once looked at a program using threads and locks. Too bad that I could reliably trigger an exception state just after the lock was acquired. Ouch.
Use of insecure functions
Real-World-Example: Many programming languages (especially scripted ones) offer some sort of real-time
eval. The use of these is bad practices.
You know what else is bad practice? Rushing out an unfinished prototype as the actual product. Happens more often then you'd think. I know that these kind of relate to input validation, however it does not always need user input specifically to exploit these.
Pro-Tipp: My scripts
grep for these functions before any assessment takes place. (Source known, obviously)
Dev- vs. Production Environment
Real-World-Example: A program which used sockets. In their development environment, each machine had 'unlimited' amount of available sockets.
The computers where the software was eventually deployed on didn't.
Their server could easily be crashed, and it was a critical piece of infrastructure as well.
Developer Misunderstanding or Lazyness
Real-World-Example: This one is my favorite by far! I once looked at web server, self-built in Python.
In Python, the inbuilt HTTP-Handler has a 'do_METHOD' function for every HTTP-method. If you want your own handler, you subclass it and overwrite these functions, which is exactly what they did. Now they had one function which was called 'do_WORK', that had nothing to do with serving HTTP at all.
Python (for forward-compatibility reasons, I can only assume) calls these functions by string-matching them. Which means that Python would actually try to call whatever function with the name of 'do_METHOD' (where method is the method stated by an HTTP-Client/Request) would be available. HTTP-method 'WORK' wasn't a thing...Until then. Therefore I could now call 'do_WORK' early and trigger a race condition. Beautiful.
These are just a few, but always remember: Computers do not make mistakes, humans do.