DOS Your Meteor Application With Where

Written by Pete Corey on Aug 10, 2015.

If you’ve read my previous posts, you’ll know that I talk quite a bit about the dangers of not checking your method and publication arguments. These posts usually boil down to the dangers of letting users pass arbitrary data into your collection query objects. These types of vulnerabilities usually take the form of data leakage, or unauthorized data modifications (which are very serious issues), but it’s also possible to completely hang an application with a well-crafted query.

Let’s dig into an example to see how this can happen and what we can do to prevent it!

The Setup

Let’s pretend that you’re building a Meteor application. Within this application you have a very simple method called grabData. It expects you to pass in an ID, and it will return the corresponding item from the Data collection:

Meteor.methods({
  grabData: function(id) {
    return Data.findOne(id);
  }
});

Awesome, our method works! Now imagine what would happen if a malicious user ran the following method call in their browser console:

Meteor.call('grabData', {$where: "d = new Date; do {c = new Date;} while (c - d < 10000);"});

Uh oh… What is this $where operator? What’s all this Date and looping business? And why is my app completely unresponsive?

The Exploit

The $where operator will execute any valid Javascript string on each element in the collection over which you’re running your query. It’s intended use is to run complicated queries that may carry out some business logic on a document before deciding whether to include it in the result set. Unfortunately, $where will execute any Javascript passed into it - including Javascript designed to loop forever.

We were expecting the client to pass an ID into grabData, but our malicious user decided to get more creative. They passed in a selector object with a $where operator designed to spin your Mongo instance’s CPU at 100% for 10 seconds. By pegging the CPU of your Mongo instance (which may or may not be the same CPU used by your Meteor application), the malicious user has essentially DOS’d your application.

Check out a quick demonstration:

This is a particularly nasty vulnerability. In this case, our malicious user was kind enough to free the CPU after 10 seconds. In the real world, an attacker may peg your CPU indefinitely, forcing you to restart your Mongo instance.

The Fix

So how do we avoid this type of “NoSQL injection”? Wherever possible, don’t trust user input, and definitely don’t pass it directly into a collection query. Always check that your user arguments match your expectations, and be especially careful when using the $where operator.

A simple fix to our grabData method may look like this:

Meteor.methods({
  grabData: function(id) {
    check(id, String);
    return Data.findOne(id);
  }
});

You can use my new package, east5th:check-checker to see if you have any unchecked arguments in your application’s publications and methods.

Returning Promises Synchronously

Written by Pete Corey on Aug 3, 2015.

This past week I was working on a Meteor project that made use of a Node.js package that used promises; specifically es6-promises. I often found myself wanting to return results from this package in my Meteor method calls. This meant I had to use some form of Fibers/Futures to transform my asynchronous promises into “synchronous” code.

The usual method of transforming asynchronous code into a synchronous style is to use Meteor’s wrapAsync utility method. wrapAsync works by wrapping your provided function in a future that returns when the callback to your provided asynchronous function is called. Unfortunately, wrapAsync only works with traditional asynchronous methods that take an error-first callback as their last parameter. This means we won’t be able to use it to transform our promises into a synchronous style.

Without being able to use wrapAsync, I found myself writing a lot of code that looked like this:

Meteor.methods({
  lolpromises: function(a) {
    Future = Npm.require('fibers/future');
    var future = new Future();
    returnsPromise().then(function(res) {
      future.return(res);
    }, function(err) {
      future.throw(err);
    });
    return future.wait();
  }
});

Basically, I’m creating a Future, and returning what the value of that future will be from the method. My promise resolve method returns the value to the future, and the reject method throws the rejected value as an exception.


I decided to wrap this functionality into a package: east5th:wrap-promise. Using that package, you can return a promise in a synchronous styling like this:

Meteor.methods({
    lolpromises: function(a) {
        return wrapPromise(returnsPromise());
    }
});

The package is duck-typing the promise’s then interface, so it should work with any promise library that supports that interface. Check out the code if you’re interested.


After talking about this with Dean Radcliffe, I realized that there’s a better, officially supported way to accomplish my goal: Promise.await in the promise Meteor package.

Using the core promise package, our lolpromises method would look like this:

Meteor.methods({
    lolpromises: function(a) {
        return Promise.await(returnsPromise());
    }
});

Check-Checker Checks Your Checks

Written by Pete Corey on Jul 27, 2015.

I’ve been shouting about why you should check all of the user provided arguments in your Meteor applications for months now. Working with unchecked arguments can lead to a variety of serious security issues in your application.

But still, I find myself coming into client projects and security assessments where I see developers forgetting to check their arguments!


The audit-argument-checks is a great package designed to get people to check all of their method and publication arguments. Unfortunately, it has its shortcomings.

audit-argument-checks will only tell you that you’re missing check coverage for a method or publication at runtime, when that method or publication is called. The package politely informs you of this missing coverage by throwing an exception and killing the current method or publication.

What’s worse, audit-argument-checks is not a debugOnly package, so these exceptions will continue to be thrown in production releases, potentially breaking your application (arguably for good reason).


Wouldn’t it be great if we could get a report of missing checks at startup, rather than through exceptions at runtime? Now you can! Check out my newly released east5th:check-checker package.

meteor add east5th:check-checker

check-checker was born of my need to quickly get informed about the state of argument checking in an application during a security assessment. It’s built on top of ESLint, and uses static analysis techniques to find all method and publication declarations in a Meteor application. If check is not called on a method or publication argument within the body of the handler, a warning is shown in the server logs.

Imagine you have a file in your Meteor project, example.js, that contains method and publication declarations with unchecked arguments:

if (Meteor.isServer) {
  Meteor.methods({
    foo: function(bar) {
      return MyCollection.find();
    }
  });

  Meteor.publish({
    test: function(rab, oof) {
      SensitiveDocuments.update(rab, oof);
    }
  });
}

After adding check-checker, you’ll see the following warning in your server logs after the application starts:

/example.js:
   Method 'foo' has an unchecked argument: bar
   Publication 'baz' has an unchecked argument: rab
   Publication 'baz' has an unchecked argument: oof

The goal of check-checker is to make it easier for developers to quickly find where they’re lacking check coverage. The faster you can find the chinks in your armor, the faster you can secure your application.