NSSecureCoding allowed classes list

We see warnings like this logged by our processes using XPC:

(Foundation) [com.apple.runtime-issues:Foundation] *** -[NSXPCDecoder validateAllowedClass:forKey:]: NSSecureCoding allowed classes list contains [NSObject class], which bypasses security by allowing any Objective-C class to be implicitly decoded. Consider reducing the scope of allowed classes during decoding by listing only the classes you expect to decode, or a more specific base class than NSObject. This will become an error in the future. Allowed class list: {(
    "'NSObject' (0x7ff844ee0d88) [/usr/lib]"
)}

As far as we can see, there is no explicit NSObject in allowed classes for any XPC connection. Where does this list and NSObject come from?

Replies

Seems like it is only happening on the Monterey. Feedback FB9605587.

Add a Comment

It seems it's happening only for Swift classes that extend NSObject.

It seems it's happening only for Swift classes that extend NSObject.

There’s a couple of options here:

  • If you’d like help getting to the bottom of this, you should open a DTS tech support incident. That’ll allow me to allocate time to look at your code in detail.

  • If you’d rather just treat this as a bug, that’s fine. In that case, please file your own bug about this [1], and post the bug number, just for the record. If you can attach a tiny test project to your bug report, that’d be grand.

ps The trick to creating tiny XPC test projects is to use loopback. I’ve pasted an example of this technique below. This technique is also super useful when testing your XPC code.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Unfortunately the bug mentioned earlier in this thread (FB9605587) didn’t go anywhere.

import Foundation

@objc private protocol StringTransformer {
    func uppercaseString(_ input: String, reply: @escaping (_ output: String) -> Void)
}

private final class Listener: NSObject, NSXPCListenerDelegate {

    override init() {
        let listener = NSXPCListener.anonymous()
        self.listener = listener
        self.endpoint = listener.endpoint
        super.init()
        listener.delegate = self
        listener.resume()
        print("server did start listening")
    }
    
    let listener: NSXPCListener
    let endpoint: NSXPCListenerEndpoint
    
    func listener(_ listener: NSXPCListener, shouldAcceptNewConnection connection: NSXPCConnection) -> Bool {
        print("server will accept connection")
        _ = ServerConnection(connection: connection)
        return true
    }
}

private final class ServerConnection: NSObject, StringTransformer {

    init(connection: NSXPCConnection) {
        self.connection = connection
        super.init()
        connection.interruptionHandler = { print("server interrupted") }
        connection.invalidationHandler = { print("server invalidated") }
        connection.exportedInterface = NSXPCInterface(with: StringTransformer.self)
        connection.exportedObject = self
        connection.resume()
    }

    let connection: NSXPCConnection
    
    fileprivate func uppercaseString(_ input: String, reply: @escaping (String) -> Void) {
        print("server did receive request, input: \(input)")
        let output = input.uppercased()
        print("server will send response, output: \(output)")
        reply(output)
    }
}

private final class Client: NSObject {

    init(connection: NSXPCConnection) {
        self.connection = connection
        super.init()
        connection.remoteObjectInterface = NSXPCInterface(with: StringTransformer.self)
        connection.interruptionHandler = { print("client interrupted") }
        connection.invalidationHandler = { print("client invalidated") }
        connection.resume()
    }

    let connection: NSXPCConnection
    
    func sendRequest(_ input: String) {
        print("--")
        print("client will send request, request: \(input)")
        
        let proxy = (self.connection.remoteObjectProxyWithErrorHandler { error in
            print("client did not send request, proxy error: \(error)")
        } as! StringTransformer)
        proxy.uppercaseString(input) { output in
            print("client did receive response, output: \(output)")
        }
    }
}

func main() {
    let listener = Listener()
    let client = Client(connection: NSXPCConnection(listenerEndpoint: listener.endpoint))
    let timer = DispatchSource.makeTimerSource(queue: .main)
    timer.setEventHandler {
        client.sendRequest("Hello Cruel World! \(Date())")
    }
    timer.schedule(deadline: .now() + 1.0, repeating: 5.0)
    timer.activate()
    withExtendedLifetime(listener) {
        withExtendedLifetime(client) {
            dispatchMain()
        }
    }
}

main()

@eskimo I am facing the same issue while working with Share Extensions.

Adding a share extension on a blank new project and running it throws the same warning:

Info.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>NSExtension</key>
	<dict>
		<key>NSExtensionAttributes</key>
		<dict>
			<key>NSExtensionActivationRule</key>
			<dict>
				<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
				<integer>1</integer>
			</dict>
		</dict>
		<key>NSExtensionMainStoryboard</key>
		<string>MainInterface</string>
		<key>NSExtensionPointIdentifier</key>
		<string>com.apple.share-services</string>
	</dict>
</dict>
</plist>

Warning

[Foundation] *** -[NSXPCDecoder validateAllowedClass:forKey:]: NSSecureCoding allowed classes list contains [NSObject class], which bypasses security by allowing any Objective-C class to be implicitly decoded. Consider reducing the scope of allowed classes during decoding by listing only the classes you expect to decode, or a more specific base class than NSObject. This will become an error in the future. Allowed class list: {(
    "'NSObject' (0x7fff862bc6e8) [/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/usr/lib]"
)}

I am facing the same issue while working with Share Extensions.

Given that you’re not using XPC directly — the share extension infrastructure uses XPC under the covers but it doesn’t expose any of those details to you — this is clearly Apple’s problem. I encourage you to file a bug report with details on how to reproduce the issue. Please post your bug number, just for the record.

Make sure to be clear about:

  • The version of Xcode you’re using.

  • The platform you’re targeting (share extensions are supported on multiple platforms).

  • The templates you selected for both the app and the share extension.

  • The OS version you’re testing on.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I have filed a feedback FB9793368

DTS has confirmed this is a bug, hope it gets fixed, fingers crossed

  • Thanks for the bug report (FB9793368).

  • I am facing the same issue right now and the above feedback page is missing. Is this bug solved? Please let me know about any details.

Add a Comment

Looks like still not fixed. IOS 16.5 have problems with sharing on Instagram. Submitted a ticket

https://feedbackassistant.apple.com/feedback/12322665