diff --git a/tensorflow/opensource_only.files b/tensorflow/opensource_only.files
index be0396dd113..d49b1c1e381 100644
--- a/tensorflow/opensource_only.files
+++ b/tensorflow/opensource_only.files
@@ -13,6 +13,7 @@ tensorflow/python/tpu/profiler/pip_package/README
 tensorflow/python/tpu/profiler/pip_package/build_pip_package.sh
 tensorflow/python/tpu/profiler/pip_package/setup.py
 tensorflow/python/tpu/tpu.bzl
+tensorflow/security/fuzzing/tf_fuzzing.bzl
 tensorflow/stream_executor/build_defs.bzl
 tensorflow/third_party/BUILD
 tensorflow/third_party/__init__.py
diff --git a/tensorflow/security/fuzzing/BUILD b/tensorflow/security/fuzzing/BUILD
new file mode 100644
index 00000000000..887e1a23cdf
--- /dev/null
+++ b/tensorflow/security/fuzzing/BUILD
@@ -0,0 +1,17 @@
+# Fuzzing TensorFlow.
+# Since we use OSSFuzz, gather all fuzzers into a single place.
+# This way, we can use tooling to determine the status of the fuzzing efforts.
+
+load(
+    "//tensorflow/security/fuzzing:tf_fuzzing.bzl",
+    "tf_fuzz_target",
+)
+
+package(
+    licenses = ["notice"],  # Apache 2.0
+)
+
+tf_fuzz_target(
+    name = "demo_fuzz",
+    srcs = ["demo_fuzz.cc"],
+)
diff --git a/tensorflow/security/fuzzing/demo_fuzz.cc b/tensorflow/security/fuzzing/demo_fuzz.cc
new file mode 100644
index 00000000000..71777591694
--- /dev/null
+++ b/tensorflow/security/fuzzing/demo_fuzz.cc
@@ -0,0 +1,32 @@
+/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+#include <cstdint>
+#include <cstdlib>
+
+// This is a demo fuzzer to test that the entire framework functions correctly.
+// Once we start moving the existing fuzzers to this framework we will delete
+// this.
+// TODO(mihaimaruseac): Delete this when no longer needed
+void DemoFuzzer(const uint8_t* data, size_t size) {
+  // Trigger a small bug that should be found by the fuzzer quite quickly
+  if (size > 10 && size % 3 == 2)
+    if (data[0] > data[1])
+      if (data[5] % data[2] == data[3]) abort();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  DemoFuzzer(data, size);
+  return 0;
+}
diff --git a/tensorflow/security/fuzzing/tf_fuzzing.bzl b/tensorflow/security/fuzzing/tf_fuzzing.bzl
new file mode 100644
index 00000000000..63a8cbac704
--- /dev/null
+++ b/tensorflow/security/fuzzing/tf_fuzzing.bzl
@@ -0,0 +1,80 @@
+"""Definitions for rules to fuzz TensorFlow."""
+
+# TensorFlow fuzzing can be done in open source too.
+#
+# For a fuzzer ${FUZZ} we have the following setup:
+#   - ${FUZZ}_fuzz.cc           : the implementation of the fuzzer
+#   - corpus/${FUZZ}/...        : public corpus for the fuzzer
+#   - dictionaries/${FUZZ}.dict : fuzzing dictionary for the fuzzer
+#   - ${FUZZ}_internal/...      : internal data for the fuzzer
+#
+# If a fuzzer needs some framework to build, we can use the ${FUZZ}_internal/
+# directory to hold the harness. Or, if the infrastructure needs to be shared
+# across multiple fuzzers (for example fuzzing ops), we can store it in other
+# places in TF or move it to a different folder here. We will decide on these
+# on a case by case basis, for now the ops fuzzing harness resides under
+# tensorflow/core/kernels/fuzzing.
+#
+# The internal folder can also contain proto definitions (if using proto-based
+# mutators to do structure aware fuzzing) or any other type of content that is
+# not classified elsewhere.
+
+# tf_cc_fuzz_target is a cc_test modified to include fuzzing support.
+def tf_fuzz_target(
+        name,
+        # Fuzzing specific arguments
+        fuzzing_dict = [],
+        corpus = [],
+        parsers = [],
+        # Reporting bugs arguments, not used in open source
+        componentid = None,
+        hotlists = [],
+        # Additional cc_test control
+        data = [],
+        deps = [],
+        tags = [],
+        # Remaining cc_test arguments
+        **kwargs):
+    """Specify how to build a TensorFlow fuzz target.
+
+    Args:
+      name: Mandatory name of the fuzzer target.
+
+      fuzzing_dict: An optional a set of dictionary files following
+        the AFL/libFuzzer dictionary syntax.
+
+      corpus: An optional set of files used as the initial test corpus
+        for the target. When doing "bazel test" in the default null-fuzzer
+        (unittest) mode, these files are automatically passed to the target
+        function.
+
+      parsers: An optional list of file extensions that the target supports.
+        Used by tools like autofuzz to reuse corpus sets across targets.
+
+      componentid: Used internally for reporting fuzz discovered bugs.
+
+      hotlists: Used internally for reporting fuzz discovered bugs.
+
+      data: Additional data dependencies passed to the underlying cc_test rule.
+
+      deps: An optional list of dependencies for the code you're fuzzing.
+
+      tags: Additional tags passed to the underlying cc_test rule.
+
+      **kwargs: Collects all remaining arguments and passes them to the
+        underlying cc_test rule generated by the macro.
+    """
+    componentid = None
+    hotlists = None
+
+    # Fuzzers in open source must be run manually
+    tags = tags + ["manual"]
+
+    # Now, redirect to cc_test
+    native.cc_test(
+        name = name,
+        deps = deps,  # TODO(mihaimaruseac): fuzzing lib?
+        data = data,  # TODO(mihaimaruseac): dict, corpus, parsers??
+        tags = tags,  # TODO(mihaimaruseac): fuzzing tags?
+        **kwargs
+    )