Keep It Secret, Keep It Safe

Written by Pete Corey on May 25, 2015.

It’s fairly well established that you shouldn’t be storing your application’s deployment-specific configuration options directly in your source code. Keeping secrets in your code unnecessarily expands your application’s circle of trust. But did you know that by keeping secrets in your code you may inadvertently be leaking them to your clients?

The Setup

Let’s pretend that we have a Meteor method that’s called whenever a user purchases something in our application. Knowing that we want to leverage latency compensation, we define this method in a shared location so both the client and server have access to it. In a server block, the method adds a transaction to our payment processing system. In order to add this payment, we need to pass along a secret key associated with our application to verify that we authorize the transaction.

Take a look at the method:

    purchase: function(item) {
        // checks and validation
        if (Meteor.isServer) {
            Payments.add(..., 'XYZ-SSECRET-KEY');

It’s very important that we keep our secret key a secret! If anyone other than our server has access to our key, they would be able to add payments on our behalf.

The Problem

Unfortunately, in this scenario, our secret key is not being kept a secret. To grab our key, a malicious user would simply need to open their browser console anywhere in our application and grab the purchase method’s source:


"... 'XYZ-SSECRET-KEY' ..."

Our fundamental error here is assuming that our Meteor.isServer guard prevents code from being shipped to the client. This isn’t always true! When a method is defined in a location that is visible to both the client and the server, it’s entire handler function is passed to the client, server-only code and all.

Check out my post on black box auditing Meteor methods to get a better understanding of what code is made visible to the client.

The Solution

The quickest solution to this problem is to move our secret key out of our code and into our settings file:

    "payment_secret": "XYZ-SSECRET-KEY"

Our updated purchase method would look like this:

    purchase: function(item) {
        // checks and validation
        if (Meteor.isServer) {

From a client/server perspective, nothing has changed. Our Meteor.isServer block is still being sent to the client. The fundamental difference with this approach is that Meteor.settings.payment_settings is not available on the client. Even if a malicious user digs into the method’s source on the client, they won’t get to our secret key.

Mongo's Multi Parameter Saves the Day

Written by Pete Corey on May 18, 2015.

In the past, I’ve seen the multi parameter on MongoDB updates as an annoying inconvenience. Without fail, I’ll forget to add the flag when it’s needed, and waste a frustrating amount of time trying to deduce why my update isn’t behaving as expected. But, a recent trek through Telescope’s codebase revealed to me just how valuable it can be to default to updating a single item at a time. Come with me on a journey…

On a side note, Telescope is one of the highest quality open source Meteor projects I've seen to date. I highly recommend it as a platform!

Digging Into Telescope

The code that opened my proverbial eyes is the changeEmail method found in /server/users.js in Telescope. Take a look:

changeEmail: function (userId, newEmail) {
  var user = Meteor.users.findOne(userId);
  if (can.edit(Meteor.user(), user) !== true) {
    throw new Meteor.Error("Permission denied");
    {$set: {
        emails: [{address: newEmail, verified: false}],
        email_hash: Gravatar.hash(newEmail),
        "": newEmail

If you’ve read my previous posts, I hope you’ll immediately notice that userId and newEmail are not being checked. Can that be exploited? What happens if a malicious user, Mallory, decides to pass in a carefully crafted object as the userId?‘changeEmail', {_id: {$gte: Meteor.userId()}}, ‘mallory@is.evil');

This userId object, when used in a Mongo query, will return all users with IDs ordinally greater than or equal to the current user’s ID. We can roughly assume that this is about half of the users in the system. The list of returned users will always return the current user first, due to the index on the _id field.

In our changeEmail method, Meteor.users.findOne will happily accept our userId object and treat it as a query object. It will grab the first result of this query, which happens to be the current user (Mallory).

Next, the method checks if the current user has permission to edit the user found. Because the first user found is the current user, permission is granted. Proceed with the update!

You Get a New Email Address! And You Get a New Email Address!

If Mongo didn’t require explicitly setting the multi parameter, calling Meteor.users.update with our malicious userId object would result in a huge chunk of users having their emails changed to Mallory’s email address. This would be a Very Bad Thing™. He could easily reset their passwords through normal channels and take over their accounts!

But Not Really…

Thankfully, Mongo defaults to updating only a single object unless the multi flag is explicitly set to true. In this example, only the first result of the query, the current user, will be updated with the new email address. This means that the method functions as intended, and there is no vulnerability! Three cheers for the multi flag!

Final Thoughts

While I’m sure I’ll still continue to forget to add the multi flag when writing updates, I now have a newfound respect for this aspect of Mongo. This conservative default, which was initially built in with performance in mind, also acts as a protective mechanism to prevent us from inadvertently modifying more data than we intended.

Lastly, remember to always check your method and publication arguments! While it ended up not being a problem in this example, we nearly had a serious vulnerability on our hands. It’s always better to be safe than sorry.

Private Package Problems

Written by Pete Corey on May 11, 2015.

Recently I’ve been experiencing some pain points when trying to share private package between my Meteor projects.

Suppose you have two or more Meteor projects that share similar styles, components and functionality. Wouldn’t it be nice to bundle those shared bits into packages and use them across all of your projects?

The Problem With Packages

Packages are the solution! Well, partially…

Many articles have been written on the ease-of-use and power of Meteor’s packaging system. Unfortunately, when we’re writing closed source software, we’re not in the position to publish our private packages Meteor’s public package ecosystem. Our need for privacy means that we need to share our packages in a different way.

Git to the Rescue

My first attempt to solve this problem was to keep my private packages within private Git repositories. When an application needed one of these shared packages, I would clone the package into the project’s packages folder, and then add the package using the familiar meteor add command. Updates to the package could be made by manually running a git pull from within the package’s directory (goodbye meteor update).

cd packages
git clone
meteor add private-package
cd private-package
git pull

Finally, track the new package in the base project and commit the changes:

git add .
git commit -m "Added private package to project!"

This will work until a second developer checks out a fresh copy of the project. They’ll quickly notice that the packages/private-package is an empty directory! Where did our package go?

Unfortunately, Git noticed that the the packages/private-package directory was actually another Git repository, so it added the directory as an unmapped submodule, not a normal folder. This means that the base project isn’t concerned with tracking the contents of the packages/private-package directory, assuming that the submodule will handle that itself.

Git Submodules

Git submodules are the “accepted” standard for dealing with this kind of repository nesting. Git expects you to add and map these submodules through a special set of commands. Using our current example, to add private-package to our Meteor project we would:

git submodule add packages/private-package
meteor add private-package

This will pull the package down from its remote repository and set up the submodule mapping within Git. At this point, we can once again commit the changes to our base project. Another developer checking out a fresh copy of the project will now look at packages/private-package and see… an empty directory? Still?

One of the unfortunate subtleties of Git submodules is that they need to be initialized and updated on fresh checkouts:

git submodule init
git submodule update

Only then will the remote contents of each submodule be pulled into the project.

This means that the developer doing the checkout must be aware that submodules are being used by the project. This isn’t always the case, and often adds an unfortunate complexity when trying to introduce someone to a codebase.

Unfortunately, submodules have their fair share of quirks and problems.

“Fake” Submodules

My preferred method of sharing private Meteor packages between projects is a combination of the above two techniques, sometimes referred to as “fake” git submodules.

I begin by cloning my package into the packages folder, as before:

cd packages
git clone
meteor add private-package

There is a subtle step in how the package is added to my base project:

git add private-package/

The key here is the “/” at the end of the private-package path. Run a git status and you’ll notice that all of the private package’s files are now being tracked by the project. Additionally, if we cd into private-package and run a git status, we’ll see that the private-package is still operating under it’s own independent Git environment. The slash causes Git to treat this sub-repository as a normal directory and happily tracks all files within it without our base project!

Commit the changes to the base project and push them. Now, a new developer checking out a clean copy of the project will see that the private-package directory contains the contents of the package, as expected.

The only downside of this technique is that private-package in the fresh checkout no longer maintains a remote link to its private package repository. If changes need to be made in this package and pushed to the private package’s repository, the remote would have to be re-established:

git init
git remote add
git checkout master --force

Final Thoughts

My final thoughts are that this is a mess. I hope that the Meteor team adds some mechanism for adding and updating packages from private sources, rather than exclusively from its public package ecosystem. Maybe one day it will be as easy as meteor add and meteor update, but for now, these are the tools we have to work with.