Let's face it. .env
files are amazing. They have an easy-to-read syntax that stores all of our essential configurations into one file. Not only that, they keep our deepest, darkest secrets as web developers. They make sure that our precious API keys and database passwords are kept locally, away from prying eyes. Having such a critical role in our code bases, we are constantly reminded by the community to never share our .env
files; to treat them like how the government treats their confidential information.
This is especially enforced in the open-source community where everyone shares, copies, and reuses code with each other. Accidentally committing and pushing the .env
file is considered by many as a relatable moment. Personally, I have never done it myself yet, but I'm sure my fate is sealed at this point.
As fun as it is to talk about "that one time you committed the goods" in a casual conversation between developers in a party, it is pretty alarming that it has become a common conversation—perhaps even a rite of passage—in web development.
A stain in the commit history
Running a quick search on GitHub reveals that there are still a number of people who didn't get the memo. The occasional add .env
and remove .env
commit titles appear every now and then in the search results. Looking into the content of the commits indeed shows their precious API keys and database passwords. It's honestly funny to see how they revert their changes like how a child becomes guilty of doing something they shouldn't have.
What's more alarming about this is that there are still some others who have not reverted their commits. The .env
file is still alive and well in their repositories. For all we know, these might be real, actual API keys and database passwords they currently depend on in a regular basis. To make matters worse, sorting the search results by recently committed shows how common and frequent these commits are.
The problem with simply removing the .env
file in the working tree is the fact that Git keeps a record of all the commits made in a repository, even the earliest ones. Unless clever tricks have been made (more on that later), committing that .env
file will forever be a stain in the commit history. This is just what a version control system is supposed to do after all: keep a history of changes, even the bad ones.
Having said that, how does one handle sensitive data in a repository?
.gitignore
is your best friend
Adding a .gitignore
file to your repository is your first line of defense against these hiccups. Properly and explicitly specifying what files and directories to ignore is a surefire way of preventing sensitive data from ever reaching public repositories and prying eyes.
GitHub and gitignore.io provide general-purpose .gitignore
templates for specific languages and environments. Most of the time, these templates are more than enough to suit your needs.
In the case of already having committed sensitive data in a repository, GitHub has a handy, and rather overkill, guide on how to purge a file from the commit history. "Overkill" is not a bad thing, though. One can never be too safe when it comes to security. 😉
We all make mistakes
We're all humans here. Nobody is perfect. Mistakes are just a part of life. In fact, it is probably one of the most important realities we have to face everyday. Without facing these mistakes, we can never become better developers. A huge part of learning isn't in the affirmation of success but in the recognition of the "whats" and "whys" of failure.
Sure, committing the .env
file is a grave mistake. Sure, it will pose serious security risks in your app. Sure, the business will suffer significant losses. Sure, it will be a hassle to clean up the commit history. Sure, it will be hard to sleep at night knowing that you have been compromised. But if there's one good thing that comes out of this experience, it has to be the fact that you will come out as a better, more experienced developer in the end.
With that said, here's a toast to all the future projects that you will never commit the .env
file to. Cheers! 🥂 *clink* I shall conclude this article with a parting thought and a final reminder to you, the reader:
Please don't commit .env
. You wouldn't want to end up at the top of GitHub's search results.
Top comments (76)
vim ~/.gitignore
Do not think you will not make a mistake, be proactive and presume you will, we are only humans.
Edit: this will prevent adding to your project your IDE config files, environment and private keys
You shouldn't ignore the idea folder. you're supposed to commit almost all of it to the repo.
intellij-support.jetbrains.com/hc/...
rider-support.jetbrains.com/hc/en-...
Nope, thats what they say but is it a bad practice.
Each env had its own tweaks and sometimes diffenrent platforms, tasks, settings and folders. Each dev should have the liberty of using its own IDE in their own productive way.
Ah yes, let's not use the tool as instructed. That will go great.
Yeah, and they tell you exactly which things to exclude in order to get that.
You should include the idea folder. End of story.
No, sorry.
Do some research on the topic you will see that many other developers share my opinion. Do not blindly trust the IDE creators, for them is a business, for you is just a tool.
IDE's are local tools, they are not related to the project. A big project then will have
.vim
.idea
.eclipse
.atom
.vscode
folders. Where did you saw that?
You can also browse popular open source projects source code and see that most of them do not have IDE config files.
That's because devs want "clean" repos, but there is a JetBrains template, which will ignore USER settings, but you should still commit PROJECT setttings, as not all settings can be read from
.editorconfig
or linting etc.... This will help other devs that uses that IDE to not waste time on configuring the IDE to get auto-format correct etc... Also VSCode has files that should be committed.That's pretty dangerous advice because it depends on how you configure your application.
I personally commit
.env
files because they don't contain sensitive information and typically having settings important to being able to start up my app in development. I have a feeling just about anyone using Docker Compose would also commit.env
files too since it's used for setting your project name.I reserve
.env.prod
or other environment specific files for sensitive API keys and other things I wouldn't want to commit.It is not dangerous and also .env.prod is very specific.
You can always commit the files from gitignore, but you have to do it explicitly, so you avoid mistakes
--force
.I just mean putting it into your main
.gitignore
file is dangerous because you run the risk of not committing essential settings to make your project work if it depends on.env
being around.Using
--force
every time they want to add a file isn't a viable solution IMO. That's a command you might run 50 times a day.In other words, you should add
.env
on a per project basis when your project may have.env
files that contain sensitive info, just like you would want to ignore any other files that have sensitive data.Awesome, just did this in all my repos.
We're glad to hear that!
Cheers! 🥂 *clink*
Best and most useful solution. prevention before cure.
Just to clarity all this text above, which is misleading, the issue is not to commit the
.env
file!The issue is storing sensitive data in plain text -be it
.env
or any other kind of file- inside the repository, either be public (as an obvious security measure) or private (as a double security measure).It's perfectly fine to have a
.env
that stores your DB user, password and model if that's meant to point to a local database in your computer (Docker-ized or not) for development purposes or an API key that's meant to work just in local environment within your app cluster. You can then override these values with the production -or any other public environment- ones in the pipeline with the sensitive data values stored in a vault or repository variables.Best regards
I totally agree with this. I should have been clearer in emphasizing this point. Of course, hindsight is 20-20 five years later (when this article was first published). 😅
This is actually my current stance on the subject nowadays. However, strictly out of abundance of caution, I still avoid committing an
.env
file into any of my repositories. It's more about the fact that I know I will be working with other people, so I just outright.gitignore
potentially sensitive files from the get-go. It is not to say that committing.env
is inherently evil, but proactive measures are still better than reactive measures when it comes to computer security.true! 😁
When users access the front-end project, they can naturally capture all the content, so how can the front-end project prevent API key exposure? Is there no way?
The most effective way to combat this is to just never embed API keys in the front end. Instead, we use API calls (e.g.,
fetch
) so that some back-end server somewhere performs the API request on behalf of the front end. The API keys thus remain secret in the back end. This is an unfortunately cumbersome but necessary measure.If so, access the API encryption interface through the fetch reappropriate back-end interface. So the API interface encryption on and from the front and back ends is meaningless.
What do you mean by encryption, by the way? Are you referring to API keys that are embedded inside JWTs? Or are you referring to the general pattern of encrypting API secrets before sending to the front end?
general pattern of encrypting API secrets before sending them to the front end
I suppose that is one possible way. Personally, though, I would still prefer just having a centralized server that acts as a proxy for privileged API calls.
Just to clarify for anyone reading, a
git revert
will not solve the problem: you'll still have the.env
file visible in your public git history. If you've accidentally committed a secret, you need to remove that commit completely.If you catch the problem immediately, you can do a
git reset HEAD^
followed bygit push -f
. This deletes the most recent commit and overwrites the remote Git history. If you realize too late what you've done, you'll need a slightly more complicated method (see this useful blog post for pointers).Of course, on the Internet this is all pretty optimistic; someone could have scraped your secrets while they were publicly visible, even if only for a handful of seconds. The only way to really get your security back is to go change all your secret keys and passwords.
Yup! That's true. If at any time you feel that you have been compromised, never hesitate to reset those keys and passwords. In fact, it should be the first thing you should do before messing up the commit history. The less time the API key is valid, the better it will be for everyone (except potential hijackers).
Not to mention that
git push -f
opens the door to all kinds of accidents.Hm, I would recommend adding an
.env.sample
file in the repository. Instead of filling in the fields with real values, you can add placeholders, redactions, and "pseudo-values".Then, of course, this would have to be documented and explained in the appropriate
README.md
.Or perhaps, you could even forgo the
.env.sample
file and declare the environment variables in theREADME.md
itself, but I personally prefer the former because it is more explicit.I see no point in the general advice, not to commit a
.env
-file per se: I do it frequently and wondered what this post is about.It is not about committing a standard configuration in your repo, which could be overriden e.g. by a
.env.local
. It is about not storing secrets in your repository. That's another topic and indeed best practice.So my usage of
.env
seems to differ: providing a sane default configuration, which can and should be overridden and does not contain any secrets whatsoever.For managing secrets in a repo there is an interesting approach by stackoverflow: github.com/StackExchange/blackbox
which unfortunately I had not the time trying, but looks interesting.
The only thing I don't like about doing this is that when I change the defaults, they now show up as a diff. On some of my smaller projects I SSH onto the server and just pull the latest changes, so if I've made a change to my default
.env
file I have to worry about conflicts. I can avoid this problem in production by having the defaults be my production settings, but then I constantly have a dirty file in development.The best solution to this in my opinion is to not commit
.env
and instead commit a.env.example
. Then all you have to do iscp .env.example .env
and you have the exact same things as before but without a dirty file when you change settings.Hmmm. Interesting. I came into first contact with .env files via vuejs. It seems there, that you have a .env file which acts like your ".env.example" and could have a .env.local which contains overrides.
But doing some research that seems an uncommon practice 🤔
Mostly there is one .env and it isn't committed.
Yes, it's definitely okay to commit the
.env
file if and only if they contain general and not-so-sensitive information. Otherwise, the point of this article is to remind people that they should think twice before they commit.env
files because of the serious ramifications that come with it.There's sooooooo... many unaware user be out there , anybody can literally bring their whole business to an end! 😓
I tried to talk with some of them and make them aware, but got no response for months..😑
Seems like they're like,
You could always show them a demo of the amount of damage you can do if you had access to that "small"
.env
file. I'm sure they'll be alarmed after that.Be very careful when doing this as some wildly misguided company may accuse you of hacking and try and prosecute.
I'm sure he'll be informing them about the demo beforehand. 😉
@somedood , Yes Yes!
Will Do.
I've seen many juicy leaks there such as Google Cloud Platform Keys , Facebook Credentials , GitHub Credentials and even someone's phone number 😂
Hack responsibly! 😉
Just Proof-Of-Concept 😄
I need the
.env
file during build on CI how do I make sure GCP receives my .env file if I have not committed it on github ?/settings/secrets
.env
file/settings/secrets
) same in local setup ?To be honest, I am not exactly versed in the Google Cloud Platform. However, I do know they provide a (paid) Secrets Manager service that does exactly what you need in a secure manner. Otherwise, there doesn't seem to be a "free" workaround.
But that doesn't mean other cloud platforms have this limitation. Heroku, for example, allows you to directly set environment variables in the app itself.
So at the moment, I can't offer you any solutions with GCP. I'm unfortunately not familiar with it.
cool. thanks
Why have it in your git directory at all? Most frameworks let you override the config location so set it to
~/.app-name/.env
or similar. If you need to provide an example dummy config you can check in an.env.sample
file.Yes, that's true. At least for me, I think it's just easier to have a
.env
file because it requires minimal setup and messing around with global configurations.At least in Node.js, all you have to do is
npm install
andrequire
the dotenv package. Then in your code, just invoke thedotenv.config()
and it should all be running smoothly via the process.env object. This way just saves you from the little extra effort you have to do with the nitty-gritty configurations.But to each its own. Whatever workflow works the best for you, you should apply it, not because everyone does it but because you feel productive with it.
Got a question probably a dumb one :D. Let's say the configs in our .env are just for a client side application like react and it includes api keys and such (no database or backend user pass stuff). Why would we care about committing since after the build all the keys are going to be somewhere inside the built file as well? and its visible through the browser when user is working with the website?
First and foremost, that's not a dumb question! 😂
You are correct that it shouldn't really matter if the environment variables are truly meant to be deployed with the file bundles.
However, the real issue here is the fact that sensitive keys are publicized in the first place. Needless to say, this is not exactly a secure deployment strategy. Even if the bundles are minified and such, this is a potential attack surface nonetheless.
API keys must be stored and indirectly served via some in-house server-side API, never directly through the client-side code. Potential security risks include (but are not limited to) denial-of-service attacks, impersonation, and backdoor access to app internals. That's no fun!
Though, if the environment variables only include non-sensitive static build configurations and such (i.e. theming options, CSS variables, etc.), perhaps it may be alright to publicize them. Otherwise, you should be extra wary about this deployment strategy—if not reconsider it altogether.