Security is hard. It’s often very easy to overlook things, and one small mistake can have a very big impact.
When writing JavaScript, it’s easy to forget that you’re writing code that will be sent in plain text to your users.
Recently I have been doing a bit of offensive security, with a special interest on JavaScript files, to see what kind of information could be retrieved from them.
Here’s what I’ve learned.
Business logic and other business leaks
It’s not uncommon to see some business logic in JavaScript files, especially for frontend-heavy websites.
While this is not a direct security problem, it can tell a great deal about your internals.
It could be a secret pricing function, a list of states that reveal an upcoming feature, or an array of translation strings that uncover some internal tools.
You wouldn’t want your secret algorithms exposed to the face of the world, would you?
Internal API paths
Another interesting find in JavaScript files is API paths.
Frontend-heavy applications need to make calls to an internal API, and often the list of API endpoints is conveniently stored in an Object in one of the JavaScript files.
This makes the work of security searchers very easy as they have access to all endpoints at once. Some endpoints are maybe deprecated but are still showing in the list: this is more attack surface for a security searcher.
Access tokens
This one is really bad, but is really not that uncommon.
In JavaScript files, I’ve found the following:
- AWS S3 id and secret key giving anyone full control over a S3 bucket
- Cloudinary credentials giving anyone full control over the bucket
- A CircleCI token, allowing me to launch builds, view commit history, and more
- Various other third party API keys
Those are often found in the admin / internal JS files. Developers may think these files won’t be served to regular users so it’s fine to put sensitive information inside, but more often that not, it’s easy to get access to those files.
Getting to the interesting files
The interesting files are often the ones not intended for regular users: it can be an admin part, some internal tools, etc.
Every website has a different JS architecture. Some will load all the JS in every page, some more modern will have different entry points depending on the page you are visiting.
Let’s consider the following:
<script src="/assets/js/front.js"></script>
It’s very trivial, but in this case, one could try to load back.js, or admin.js.
Let’s consider another example:
<script src="/static/compiled/homepage.d1239afab9972f0dbeef.js"></script>
Now this is a bit more complicated, the file has a hash in its name so it’s impossible to do some basic enumeration.
What if we try to access this url: https://website/static/compiled/manifest.json?
{
"assets": {
"admin.js": "admin.a8240714830bbf66efb4.js",
"homepage.js": "homepage.d1239afab9972f0dbeef.js"
},
"publicPath": "/static/compiled/"
}
Ooops! In this case this website is using webpack, a famous assets bundler. It is often used with a plugin that generates a manifest.json file containing the link to all assets, which is often served by the web server.
If you manage to find which tools a website is using, it’s easier to find this kind of vulnerabilities.
How to protect yourself
Here are a few tips to avoid being vulnerable to this kind of attacks:
- Consider your JavaScript code public, all of it
- If you really need access tokens in the front-end, get them via (secure & authenticated) API
- Know your front-end toolbelt well to avoid basic attacks (manifest.json example)
- Regularly audit your front-end code and look for specific keywords:
- secret
- token, accessToken, access_token, etc
- your domain name, for possible API urls
- your company name, for possible 3rd party credentials
Conclusion
Security issues can come from a lot of unexpected spots. When writing any kind of code, when pasting sensible data, it’s always good to ask yourself who will have access to this code, to avoid leaking all your secrets!
Top comments (0)