diff --git a/Signal/src/util/ThreadUtil.m b/Signal/src/util/ThreadUtil.m
index 8083ecc20..37ca8e2f6 100644
--- a/Signal/src/util/ThreadUtil.m
+++ b/Signal/src/util/ThreadUtil.m
@@ -340,6 +340,8 @@ NS_ASSUME_NONNULL_BEGIN
                     shouldHaveAddToContactsOffer = NO;
                     // Only create block offers for users which are not already blocked.
                     shouldHaveBlockOffer = NO;
+                    // Don't create profile whitelist offers for users which are not already blocked.
+                    shouldHaveAddToProfileWhitelistOffer = NO;
                 }
 
                 SignalAccount *signalAccount = contactsManager.signalAccountMap[recipientId];
@@ -374,6 +376,19 @@ NS_ASSUME_NONNULL_BEGIN
             // Don't show offer if thread is local user hasn't configured their profile.
             // Don't show offer if thread is already in profile whitelist.
             shouldHaveAddToProfileWhitelistOffer = NO;
+        } else if (thread.isGroupThread) {
+            BOOL hasUnwhitelistedMember = NO;
+            for (NSString *recipientId in thread.recipientIdentifiers) {
+                if (![OWSProfileManager.sharedManager isUserInProfileWhitelist:recipientId]) {
+                    hasUnwhitelistedMember = YES;
+                    break;
+                }
+            }
+            if (!hasUnwhitelistedMember) {
+                // Don't show offer in group thread if all members are already individually
+                // whitelisted.
+                hasUnwhitelistedMember = YES;
+            }
         }
 
         // We use these offset to control the ordering of the offers and indicators.
diff --git a/SignalServiceKit/src/Messages/TSMessagesManager.m b/SignalServiceKit/src/Messages/TSMessagesManager.m
index 7b53a0938..334b43f5d 100644
--- a/SignalServiceKit/src/Messages/TSMessagesManager.m
+++ b/SignalServiceKit/src/Messages/TSMessagesManager.m
@@ -702,6 +702,9 @@ NS_ASSUME_NONNULL_BEGIN
             // user, we can infer that that user belongs in our profile whitelist.
             id<ProfileManagerProtocol> profileManager = [TextSecureKitEnv sharedEnv].profileManager;
             [profileManager addUserToProfileWhitelist:destination];
+
+            // TODO: Can we also infer when groups are added to the whitelist
+            //       from sent messages to groups?
         }
 
         if ([self isDataMessageGroupAvatarUpdate:syncMessage.sent.message]) {
diff --git a/SignalServiceKit/src/Network/API/Requests/TSProfileAvatarUploadFormRequest.h b/SignalServiceKit/src/Network/API/Requests/TSProfileAvatarUploadFormRequest.h
new file mode 100644
index 000000000..73b36c9ba
--- /dev/null
+++ b/SignalServiceKit/src/Network/API/Requests/TSProfileAvatarUploadFormRequest.h
@@ -0,0 +1,17 @@
+//
+//  Copyright (c) 2017 Open Whisper Systems. All rights reserved.
+//
+
+#import "TSRequest.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface TSProfileAvatarUploadFormRequest : TSRequest
+
+- (nullable instancetype)init;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/SignalServiceKit/src/Network/API/Requests/TSProfileAvatarUploadFormRequest.m b/SignalServiceKit/src/Network/API/Requests/TSProfileAvatarUploadFormRequest.m
new file mode 100644
index 000000000..bb820c210
--- /dev/null
+++ b/SignalServiceKit/src/Network/API/Requests/TSProfileAvatarUploadFormRequest.m
@@ -0,0 +1,23 @@
+//
+//  Copyright (c) 2017 Open Whisper Systems. All rights reserved.
+//
+
+#import "TSProfileAvatarUploadFormRequest.h"
+#import "TSConstants.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@implementation TSProfileAvatarUploadFormRequest
+
+- (nullable instancetype)init
+{
+    self = [super initWithURL:[NSURL URLWithString:textSecureProfileAvatarFormAPI]];
+
+    self.HTTPMethod = @"GET";
+
+    return self;
+}
+
+@end
+
+NS_ASSUME_NONNULL_END