diff --git a/CHANGES b/CHANGES
index 5df24b5cb49ee77cc06a8c71e1ef9fea00b58dd7..fd7ed90b2669d0a62fbbf745e546123d0ab52864 100644
--- a/CHANGES
+++ b/CHANGES
@@ -22,6 +22,7 @@ OpenLDAP 2.4.14 Engineering
 	Fixed slapd-meta double response sending (ITS#5854)
 	Fixed slapo-ppolicy to not be global (ITS#5858)
 	Updated contrib/addpartial module (ITS#5764)
+	Added contrib/cloak module (ITS#5872)
 	Build Environment
 		Fixed test049,test050 to work on windows (ITS#5842)
 		Removed patch for BerkeleyDB 4.7.25 (Official patch available)
diff --git a/contrib/ConfigOIDs b/contrib/ConfigOIDs
index df004580d3e31f5b2d8d83d91af3ec29cf488551..ebc1825b6c35ae45000a66e293e58e31f6be45d2 100644
--- a/contrib/ConfigOIDs
+++ b/contrib/ConfigOIDs
@@ -3,3 +3,4 @@ List of OpenLDAP Configuration OIDs allocated to contrib modules
 OLcfgCt{Oc|At}:1	smbk5pwd
 OLcfgCt{Oc|At}:2	autogroup
 OLcfgCt{Oc|At}:3	nssov
+OLcfgCt{Oc|At}:4	cloak
diff --git a/contrib/slapd-modules/README b/contrib/slapd-modules/README
index 6b50eb4cda2136059312f6a9568c795240d454a2..29d57083d110c054670adb40255faf87040048e1 100644
--- a/contrib/slapd-modules/README
+++ b/contrib/slapd-modules/README
@@ -20,6 +20,9 @@ allop (overlay)
 autogroup (overlay)
 	Automated updates of group memberships.
 
+cloak (overlay)
+	Hide specific attributes unless explicitely requested
+
 comp_match (plugin)
 	Component Matching rules (RFC 3687).
 
diff --git a/contrib/slapd-modules/cloak/cloak.c b/contrib/slapd-modules/cloak/cloak.c
new file mode 100644
index 0000000000000000000000000000000000000000..5e4f11d0e5be403f390a2111da77d2d65cdfa9bc
--- /dev/null
+++ b/contrib/slapd-modules/cloak/cloak.c
@@ -0,0 +1,328 @@
+/* $OpenLDAP$ */
+/* cloak.c - Overlay to hide some attribute except if explicitely requested */
+/* 
+ * Copyright 2008 Emmanuel Dreyfus
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+#include "portable.h"
+
+#ifdef SLAPD_OVER_CLOAK
+
+#include <stdio.h>
+
+#include <ac/string.h>
+#include <ac/socket.h>
+
+#include "lutil.h"
+#include "slap.h"
+#include "config.h"
+
+enum { CLOAK_ATTR = 1 };
+
+typedef struct cloak_info_t {
+	ObjectClass 		*ci_oc;	
+	AttributeDescription	*ci_ad;
+	struct cloak_info_t	*ci_next;
+} cloak_info_t;
+
+#define CLOAK_USAGE "\"cloak-attr <attr> [<class>]\": "
+
+static int
+cloak_cfgen( ConfigArgs *c )
+{
+	slap_overinst	*on = (slap_overinst *)c->bi;
+	cloak_info_t	*ci = (cloak_info_t *)on->on_bi.bi_private;
+
+	int		rc = 0, i;
+
+	if ( c->op == SLAP_CONFIG_EMIT ) {
+		switch( c->type ) {
+		case CLOAK_ATTR:
+			for ( i = 0; ci; i++, ci = ci->ci_next ) {
+				struct berval	bv;
+				int len;
+
+				assert( ci->ci_ad != NULL );
+
+				if ( ci->ci_oc != NULL )
+					len = snprintf( c->cr_msg, 
+					sizeof( c->cr_msg ),
+					SLAP_X_ORDERED_FMT "%s %s", i,
+					ci->ci_ad->ad_cname.bv_val,
+					ci->ci_oc->soc_cname.bv_val );
+				else
+					len = snprintf( c->cr_msg, 
+					sizeof( c->cr_msg ),
+					SLAP_X_ORDERED_FMT "%s", i,
+					ci->ci_ad->ad_cname.bv_val );
+
+				bv.bv_val = c->cr_msg;
+				bv.bv_len = len;
+				value_add_one( &c->rvalue_vals, &bv );
+			}
+			break;
+
+		default:
+			rc = 1;
+			break;
+		}
+
+		return rc;
+
+	} else if ( c->op == LDAP_MOD_DELETE ) {
+		cloak_info_t	*ci_next;
+
+		switch( c->type ) {
+		case CLOAK_ATTR:
+			for ( ci_next = ci, i = 0; 
+			      ci_next, c->valx < 0 || i < c->valx; 
+			      ci = ci_next, i++ ){
+
+				ci_next = ci->ci_next;
+
+				ch_free ( ci->ci_ad );
+				if ( ci->ci_oc != NULL )
+					ch_free ( ci->ci_oc );
+
+				ch_free( ci );
+			}
+			ci = (cloak_info_t *)on->on_bi.bi_private;
+			break;
+
+		default:
+			rc = 1;
+			break;
+		}
+
+		return rc;
+	}
+
+	switch( c->type ) {
+	case CLOAK_ATTR: {
+		ObjectClass		*oc = NULL;
+		AttributeDescription	*ad = NULL;
+		const char		*text;
+		cloak_info_t 	       **cip = NULL;
+		cloak_info_t 	        *ci_next = NULL;
+
+		if ( c->argc == 3 ) {
+			oc = oc_find( c->argv[ 2 ] );
+			if ( oc == NULL ) {
+				snprintf( c->cr_msg, 
+					  sizeof( c->cr_msg ), 
+					  CLOAK_USAGE
+					  "unable to find ObjectClass \"%s\"",
+					  c->argv[ 2 ] );
+				Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
+				       c->log, c->cr_msg, 0 );
+				return 1;
+			}
+		}
+
+		rc = slap_str2ad( c->argv[ 1 ], &ad, &text );
+		if ( rc != LDAP_SUCCESS ) {
+			snprintf( c->cr_msg, sizeof( c->cr_msg ), CLOAK_USAGE
+				"unable to find AttributeDescription \"%s\"",
+				c->argv[ 1 ] );
+			Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
+				c->log, c->cr_msg, 0 );
+			return 1;
+		}
+
+		for ( i = 0, cip = (cloak_info_t **)&on->on_bi.bi_private;
+		      c->valx < 0 || i < c->valx, *cip;
+		      i++, cip = &(*cip)->ci_next ) {
+			if ( c->valx >= 0 && *cip == NULL ) {
+				snprintf( c->cr_msg, sizeof( c->cr_msg ),
+					CLOAK_USAGE
+					"invalid index {%d}\n",
+					c->valx );
+				Debug( LDAP_DEBUG_ANY, "%s: %s.\n",
+					c->log, c->cr_msg, 0 );
+				return 1;
+			}
+			ci_next = *cip;
+		}
+
+		*cip = (cloak_info_t *)ch_calloc( 1, sizeof( cloak_info_t ) );
+		(*cip)->ci_oc = oc;
+		(*cip)->ci_ad = ad;
+		(*cip)->ci_next = ci_next;
+
+		rc = 0;
+		break;
+	}
+
+	default:
+		rc = 1;
+		break;
+	}
+
+	return rc;
+}
+
+static int
+cloak_search_cb( Operation *op, SlapReply *rs )
+{
+	slap_callback   *sc;
+	cloak_info_t	*ci;
+	Entry		*e = NULL;
+	Entry		*me = NULL;
+
+	assert( op && op->o_callback && rs );
+
+	if ( rs->sr_type != REP_SEARCH || !rs->sr_entry ) {
+		slap_freeself_cb( op, rs );
+		return ( SLAP_CB_CONTINUE );
+	}
+
+	sc = op->o_callback;
+	e = rs->sr_entry;
+
+	/* 
+	 * First perform a quick scan for an attribute to cloak
+	 */
+	for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) {
+		Attribute *a;
+
+		if ( ci->ci_oc != NULL &&
+		     !is_entry_objectclass_or_sub( e, ci->ci_oc ) )
+			continue;
+
+		for ( a = e->e_attrs; a; a = a->a_next )
+			if ( a->a_desc == ci->ci_ad )
+				break;
+
+		if ( a != NULL )
+			break;
+	}
+
+	/*
+	 * Nothing found to cloak
+	 */
+	if ( ci == NULL )
+		return ( SLAP_CB_CONTINUE );
+
+	/*
+	 * We are now committed to cloak an attribute.
+	 */
+	if ( rs->sr_flags & REP_ENTRY_MODIFIABLE )
+		me = e;
+	else
+		me = entry_dup( e );
+		
+	for ( ci = (cloak_info_t *)sc->sc_private; ci; ci = ci->ci_next ) {
+		Attribute *a;
+		Attribute *pa;
+
+		for ( pa = NULL, a = me->e_attrs;
+		      a; 
+		      pa = a, a = a->a_next ) {
+
+			if ( a->a_desc != ci->ci_ad )
+				continue;
+
+			Debug( LDAP_DEBUG_TRACE, "cloak_search_cb: cloak %s\n", 
+			       a->a_desc->ad_cname.bv_val,
+			       0, 0 );
+
+			if ( pa != NULL ) 
+				pa->a_next = a->a_next;
+			else
+				me->e_attrs = a->a_next;
+
+			attr_clean( a );
+		}
+
+	}
+
+	if ( me != e ) {
+		if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED )
+			entry_free( e );
+
+		rs->sr_entry = me;
+        	rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
+	}
+
+	return ( SLAP_CB_CONTINUE );
+}
+
+static int
+cloak_search( Operation *op, SlapReply *rs )
+{
+	slap_overinst   *on = (slap_overinst *)op->o_bd->bd_info;
+	cloak_info_t    *ci = (cloak_info_t *)on->on_bi.bi_private; 
+	slap_callback	*sc;
+
+	if ( op->ors_attrsonly ||
+	     op->ors_attrs ||
+	     get_manageDSAit( op ) )
+		return SLAP_CB_CONTINUE;
+
+	sc = op->o_tmpcalloc( 1, sizeof( *sc ), op->o_tmpmemctx );
+	sc->sc_response = cloak_search_cb;
+	sc->sc_cleanup = NULL;
+	sc->sc_next = NULL;
+	sc->sc_private = ci;
+	op->o_callback = sc;
+
+	return SLAP_CB_CONTINUE;
+}
+
+static slap_overinst cloak_ovl;
+
+static ConfigTable cloakcfg[] = {
+	{ "cloak-attr", "attribute [class]",
+		2, 3, 0, ARG_MAGIC|CLOAK_ATTR, cloak_cfgen,
+		"( OLcfgCtAt:4.1 NAME 'olcCloakAttribute' "
+			"DESC 'Cloaked attribute: attribute [class]' "
+			"EQUALITY caseIgnoreMatch "
+			"SYNTAX OMsDirectoryString "
+			"X-ORDERED 'VALUES' )",
+			NULL, NULL },
+	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
+};
+
+static ConfigOCs cloakocs[] = {
+	{ "( OLcfgCtOc:4.1 "
+	  "NAME 'olcCloakConfig' "
+	  "DESC 'Attribute cloak configuration' "
+	  "SUP olcOverlayConfig "
+	  "MAY ( olcCloakAttribute ) )", 
+	  Cft_Overlay, cloakcfg },
+	{ NULL, 0, NULL }
+};
+
+#if SLAPD_OVER_CLOAK == SLAPD_MOD_DYNAMIC
+static
+#endif
+int
+cloak_initialize( void ) {
+	int rc;
+	cloak_ovl.on_bi.bi_type = "cloak";
+	cloak_ovl.on_bi.bi_op_search = cloak_search;
+        cloak_ovl.on_bi.bi_cf_ocs = cloakocs;
+
+	rc = config_register_schema ( cloakcfg, cloakocs );
+	if ( rc ) 
+		return rc;
+
+	return overlay_register( &cloak_ovl );
+}
+
+#if SLAPD_OVER_CLOAK == SLAPD_MOD_DYNAMIC
+int init_module(int argc, char *argv[]) {
+	return cloak_initialize();
+}
+#endif
+
+#endif /* defined(SLAPD_OVER_CLOAK) */
+
diff --git a/contrib/slapd-modules/cloak/slapo-cloak.5 b/contrib/slapd-modules/cloak/slapo-cloak.5
new file mode 100644
index 0000000000000000000000000000000000000000..6c2410f5223115be787cb69595cb4aa4564f9f21
--- /dev/null
+++ b/contrib/slapd-modules/cloak/slapo-cloak.5
@@ -0,0 +1,82 @@
+.TH SLAPO-CLOAK 5 "RELEASEDATE" "OpenLDAP LDVERSION"
+.\" Copyright 1998-2008 The OpenLDAP Foundation, All Rights Reserved.
+.\" Copying restrictions apply.  See the COPYRIGHT file.
+.\" $OpenLDAP$
+.SH NAME
+slapo-cloak \- Attribute cloak overlay to slapd
+.SH SYNOPSIS
+ETCDIR/slapd.conf
+.SH DESCRIPTION
+The
+.B cloak
+overlay to
+.BR slapd (8)
+allows the server to hide specific attributes, unless explicitely requested
+by the client. This improve performance when a client requests all attributes
+and get a huge binary attribute that is of no interest for it.
+This behavior is disabled when the \fImanageDSAit\fP
+control (RFC 3296) is used.
+
+.SH CONFIGURATION
+The config directives that are specific to the
+.B cloak
+overlay must be prefixed by
+.BR cloak\- ,
+to avoid potential conflicts with directives specific to the underlying 
+database or to other stacked overlays.
+
+.TP
+.B overlay cloak
+This directive adds the cloak overlay to the current database,
+or to the frontend, if used before any database instantiation; see
+.BR slapd.conf (5)
+for details.
+
+.LP
+This
+.B slapd.conf
+configuration option is defined for the cloak overlay. It may have multiple 
+occurrences, and it must appear after the
+.B overlay
+directive:
+.TP
+.B cloak-attr <attribute> [<class>]
+The value 
+.B <attribute>
+is the name of the attribute that will be cloaked.
+
+The optional
+.B <class>
+restricts cloaking only to entries of the named 
+.B <class>.
+
+.SH EXAMPLE
+This example hide the
+.B jpegPhoto
+attribute. Add the following to slapd.conf:
+
+.LP
+.nf
+    database <database>
+    # ...
+
+    overlay cloak
+    cloak-attr jpegPhoto
+.fi
+.LP
+and that slapd loads cloak.la, if compiled as a run-time module;
+
+.SH FILES
+.TP
+ETCDIR/slapd.conf
+default slapd configuration file
+.SH SEE ALSO
+.BR slapd.conf (5),
+.BR slapd (8).
+The
+.BR slapo-cloak (5)
+overlay supports dynamic configuration via
+.BR back-config .
+.SH ACKNOWLEDGEMENTS
+.P
+This module was written in 2008 by Emmanuel Dreyfus.