diff --git a/add-on/lib/proxyblock.js b/add-on/lib/proxyblock.js
index 2897879..74b7828 100644
--- a/add-on/lib/proxyblock.js
+++ b/add-on/lib/proxyblock.js
@@ -104,10 +104,22 @@
                 }
             };
 
+            // Every time the proxy has been called 1000 times, return
+            // undefined instead of the proxy object, to ensure that the
+            // proxy doesn't get stuck in an infinite loop.
+            let recursionGuardCounter = 0;
+
             const blockingProxy = new Proxy(defaultFunction, {
                 get: function (ignore, property) {
                     logKeyPath();
 
+                    if (recursionGuardCounter === 1000) {
+                        recursionGuardCounter = 0;
+                        return undefined;
+                    }
+
+                    recursionGuardCounter += 1;
+
                     if (property === Symbol.toPrimitive) {
                         return toPrimitiveFunc;
                     }
diff --git a/gulpfile.js b/gulpfile.js
index 4a5e271..b32caea 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -15,7 +15,13 @@ gulp.task("default", function () {
             }
 
             const fileContents = fs.readFileSync(standardsDefDir + "/" + next, {encoding: "utf8"});
-            const standardContents = JSON.parse(fileContents);
+            let standardContents;
+            try {
+                standardContents = JSON.parse(fileContents);
+            } catch (e) {
+                console.log("Invalid JSON in " + next);
+                throw e;
+            }
 
             const stdName = standardContents.info.name;
             const stdSubName = standardContents.info.subsection_name;
diff --git a/package.json b/package.json
index 93111f4..ef82442 100644
--- a/package.json
+++ b/package.json
@@ -26,8 +26,9 @@
         "firefox": "web-ext -s add-on run",
         "lint": "node_modules/eslint/bin/eslint.js .",
         "lint:fix": "node_modules/eslint/bin/eslint.js --fix .",
-        "test": "npm run clean; npm run bundle && ln -s `ls dist/` dist/webapi_manager.zip && cross-env node_modules/mocha/bin/mocha test/functional/*.js",
-        "test:watch": "cross-env npm test --watch"
+        "test": "npm run clean; npm run bundle && ln -s `ls dist/` dist/webapi_manager.zip && cross-env node_modules/mocha/bin/mocha test/functional/*.js --only-local-tests",
+        "test:watch": "cross-env npm test --watch",
+        "test:all": "npm run clean; npm run bundle && ln -s `ls dist/` dist/webapi_manager.zip && cross-env node_modules/mocha/bin/mocha test/functional/*.js"
     },
     "pre-push": {
         "run": [
diff --git a/test/fixtures/infinite-loop.html b/test/fixtures/infinite-loop.html
new file mode 100644
index 0000000..3ce4482
--- /dev/null
+++ b/test/fixtures/infinite-loop.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <meta charset="utf-8">
+        <title>Testing Infinite Loop Case</title>
+    </head>
+    <body>
+        <div id="example-div">
+            <p>A child node</p>
+        </div>
+        <script>
+            // For testing when "Selectors API Level 1" is being blocked.
+            const exampleDiv = document.querySelector("example-div");
+            let childNode = exampleDiv.childNode;
+            let nextSibling;
+
+            // Will be stuck in an infinite loop, as nextSibling will keep
+            // returning the blockign proxy.
+            while (childNode) {
+                nextSibling = childNode.nextSibling;
+                exampleDiv.removeChild(childNode);
+                childNode = nextSibling;
+            }
+        </script>
+        <script>
+            // This will only trigger if the above infinite loop is broken.
+            const elementToInsert = document.createElement("div");
+            elementToInsert.className = "success-case";
+            document.body.appendChild(elementToInsert);
+        </script>
+    </body>
+</html>
diff --git a/test/functional/block.js b/test/functional/block.js
index 1ac15df..c16ac36 100644
--- a/test/functional/block.js
+++ b/test/functional/block.js
@@ -3,6 +3,9 @@
 const utils = require("./lib/utils");
 const injected = require("./lib/injected");
 const testServer = require("./lib/server");
+const webdriver = require("selenium-webdriver");
+const by = webdriver.By;
+const until = webdriver.until;
 
 describe("Basic Functionality", function () {
 
@@ -27,7 +30,7 @@ describe("Basic Functionality", function () {
 
             testUrl = url;
             httpServer = server;
-    
+
             const standardsToBlock = [];
             let driverReference;
 
@@ -54,10 +57,8 @@ describe("Basic Functionality", function () {
 
         it("SVG blocking", function (done) {
 
-            this.timeout = function () {
-                return 10000;
-            };
-        
+            this.timeout = () => 10000;
+
             const [server, url] = testServer.start();
 
             testUrl = url;
@@ -84,5 +85,34 @@ describe("Basic Functionality", function () {
                     done(e);
                 });
         });
+
+        it("Proxyblock does not get stuck in infinite loop", function (done) {
+
+            const [server, url] = testServer.startWithFile("infinite-loop.html");
+
+            testUrl = url;
+            httpServer = server;
+
+            const standardsToBlock = ["Selectors API Level 1"];
+            let driverReference;
+
+            utils.promiseGetDriver()
+                .then(function (driver) {
+                    driverReference = driver;
+                    return utils.promiseSetBlockingRules(driver, standardsToBlock);
+                })
+                .then(() => driverReference.get(testUrl))
+                .then(() => driverReference.wait(until.elementLocated(by.css("div.success-case")), 2000))
+                .then(function () {
+                    driverReference.quit();
+                    testServer.stop(httpServer);
+                    done();
+                })
+                .catch(function (e) {
+                    driverReference.quit();
+                    testServer.stop(httpServer);
+                    done(e);
+                });
+        });
     });
 });
diff --git a/test/functional/lib/server.js b/test/functional/lib/server.js
index ada3a23..04ee324 100644
--- a/test/functional/lib/server.js
+++ b/test/functional/lib/server.js
@@ -1,5 +1,7 @@
 "use strict";
 
+const path = require("path");
+const fs = require("fs");
 const http = require("http");
 
 const testPort = 8989;
@@ -34,6 +36,27 @@ module.exports.start = function (callback, html) {
     return [httpServer, testUrl];
 };
 
+/**
+ * Starts the test server, serving the provided html file from the fixtures dir.
+ *
+ * @param {string} testHtmlFileName
+ *   The name of the fixture file the test server should serve.
+ * @param {function|undefined} callback
+ *   An optional callback function that, if provided, will be called with
+ *   a single argument, an object describing which headers will be sent from
+ *   the server.  The callback function can modify this as needed.
+ *
+ * @return {array}
+ *   An array of length two.  The first item is the server object, and the
+ *   second item is the absolute URL that the server is serving from.
+ */
+module.exports.startWithFile = function (testHtmlFileName, callback) {
+
+    const pathToTestHtmlFileName = path.join(__dirname, "..", "..", "fixtures", testHtmlFileName);
+    const htmlFileContents = fs.readFileSync(pathToTestHtmlFileName, "utf8");
+    return module.exports.start(callback, htmlFileContents);
+};
+
 module.exports.stop = function (server) {
     server.close();
 };
diff --git a/test/functional/lib/utils.js b/test/functional/lib/utils.js
index 972a0e1..8de98f9 100644
--- a/test/functional/lib/utils.js
+++ b/test/functional/lib/utils.js
@@ -5,14 +5,16 @@
 require("geckodriver");
 
 const firefox = require("selenium-webdriver/firefox");
-const webdriver = require("selenium-webdriver");
 const injectedScripts = require("./injected");
-const by = webdriver.By;
 const Context = firefox.Context;
+const webdriver = require("selenium-webdriver");
+const by = webdriver.By;
 const until = webdriver.until;
 const keys = webdriver.Key;
 const path = require("path");
 
+module.exports.shouldRunRemoteTests = process.argv.indexOf("--only-local-tests") === -1;
+
 module.exports.constants = {
     svgBlockRule: ["Scalable Vector Graphics (SVG) 1.1 (Second Edition)"]
 };
diff --git a/test/functional/logins.js b/test/functional/logins.js
index bbcdb3a..ca4c804 100644
--- a/test/functional/logins.js
+++ b/test/functional/logins.js
@@ -13,8 +13,14 @@ const keys = webdriver.Key;
 const by = webdriver.By;
 const until = webdriver.until;
 
+
 describe("Logging into popular sites", function () {
 
+    if (utils.shouldRunRemoteTests === false) {
+        // Skipping remote tests because of --only-local-tests flag
+        return;
+    }
+
     describe("GitHub", function () {
 
         if (!testParams.github.username) {