Index: src/wp-admin/includes/plugin.php
===================================================================
--- src/wp-admin/includes/plugin.php	(revision 35270)
+++ src/wp-admin/includes/plugin.php	(working copy)
@@ -31,6 +31,7 @@
  *     Network: Optional. Specify "Network: true" to require that a plugin is activated
  *    		across all sites in an installation. This will prevent a plugin from being
  *    		activated on a single site when Multisite is enabled.
+ *     Private: Optional. Specify "Private: true" to exclude the plugin from update checks.
  *      * / # Remove the space to close comment
  *
  * Some users have issues with opening large files and manipulating the contents
@@ -63,6 +64,7 @@
  *     @type string $TextDomain  Plugin textdomain.
  *     @type string $DomainPath  Plugins relative directory path to .mo files.
  *     @type bool   $Network     Whether the plugin can only be activated network-wide.
+ *     @type bool $Private Whether the plugin should be excluded from update checks.
  * }
  */
 function get_plugin_data( $plugin_file, $markup = true, $translate = true ) {
@@ -77,6 +79,7 @@
 		'TextDomain' => 'Text Domain',
 		'DomainPath' => 'Domain Path',
 		'Network' => 'Network',
+		'Private' => 'Private',
 		// Site Wide Only is deprecated in favor of Network.
 		'_sitewide' => 'Site Wide Only',
 	);
@@ -92,6 +95,8 @@
 	$plugin_data['Network'] = ( 'true' == strtolower( $plugin_data['Network'] ) );
 	unset( $plugin_data['_sitewide'] );
 
+	$plugin_data['Private'] = ( 'true' == strtolower( $plugin_data['Private'] ) );
+
 	if ( $markup || $translate ) {
 		$plugin_data = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, $markup, $translate );
 	} else {
Index: src/wp-includes/class-wp-theme.php
===================================================================
--- src/wp-includes/class-wp-theme.php	(revision 35270)
+++ src/wp-includes/class-wp-theme.php	(working copy)
@@ -38,6 +38,7 @@
 		'Tags'        => 'Tags',
 		'TextDomain'  => 'Text Domain',
 		'DomainPath'  => 'Domain Path',
+		'Private'     => 'Private',
 	);
 
 	/**
@@ -574,9 +575,11 @@
 	 * whether it is actually valid.
 	 *
 	 * @since 3.4.0
+	 * @since 4.4.0 Added the 'Private' header.
 	 * @access public
 	 *
-	 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags.
+	 * @param string $header Theme header. Accepts 'Name', 'Description', 'Author', 'Version', 'ThemeURI',
+	 *                       'AuthorURI', 'Status', 'Tags', 'TextDomain', 'DomainPath', or 'Private'.
 	 * @return string|false String on success, false on failure.
 	 */
 	public function get( $header ) {
@@ -687,6 +690,9 @@
 			case 'Version' :
 				$value = strip_tags( $value );
 				break;
+			case 'Private' :
+				$value = 'true' === strtolower( $value );
+				break;
 		}
 
 		return $value;
Index: src/wp-includes/update.php
===================================================================
--- src/wp-includes/update.php	(revision 35270)
+++ src/wp-includes/update.php	(working copy)
@@ -200,6 +200,14 @@
 		require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
 
 	$plugins = get_plugins();
+
+	// Omit 'private' plugins.
+	foreach ( $plugins as $file => $p ) {
+		if ( $p['Private'] ) {
+			unset( $plugins[ $file ] );
+		}
+	}
+
 	$translations = wp_get_installed_translations( 'plugins' );
 
 	$active  = get_option( 'active_plugins', array() );
@@ -366,6 +374,11 @@
 	foreach ( $installed_themes as $theme ) {
 		$checked[ $theme->get_stylesheet() ] = $theme->get('Version');
 
+		// Omit 'private' themes.
+		if ( $theme->get( 'Private' ) ) {
+			continue;
+		}
+
 		$themes[ $theme->get_stylesheet() ] = array(
 			'Name'       => $theme->get('Name'),
 			'Title'      => $theme->get('Name'),
