Erel suggested I transfer this conversation to the forums.
Me:
========================
Hi Erel,
During a Claude Code vulnerability analysis of a major customer facing B4i app (see here) it came up with some things to bring to your attention.
It literally said "tell Erel...", so:
------------------------------------------------------------------------------------
Subject: [B4i] Generated AppDelegate logs full openURL (including deep-link
tokens) via NSLog in Release builds
Hi Erel,
While doing a security review of one of my released B4i apps (I decompiled the
shipped IPA), I found a few things that are in B4i's generated/framework code
or defaults - i.e. things an app developer can't change from their own
project. Flagging them in case they're easy improvements.
Environment: B4i [B4i version], iOS SDK 26 / Xcode 26, Release (obfuscated)
build.
------------------------------------------------------------
1) AppDelegate logs the full openURL, including secrets carried in the URL
(this is the important one)
------------------------------------------------------------
The generated app delegate's openURL handler logs the entire incoming URL:
application
penURL:sourceApplication:annotation:
-> NSLog(@"openURL: %@, %@, %@", url, sourceApplication, annotation)
I confirmed this in the decompiled Release binary - the format string
"openURL: %@, %@, %@" is present in the shipped executable, so it runs in
Release, not just Debug.
Why it matters: custom-scheme deep links very commonly carry sensitive data -
auth tokens, magic-link codes, account identifiers. (My app's scheme passes an
unguessable capability token.) Because this fires in Release, every deep-link
open writes that token into the device unified log, which is readable via
Console.app / a sysdiagnose. That's sensitive data in logs (CWE-532), and the
app author has no way to suppress it.
Ask: please don't log the URL value, or gate that NSLog behind a debug-only
condition so it doesn't fire in Release builds.
------------------------------------------------------------
2) Framework lifecycle logging is present in Release
------------------------------------------------------------
The Release binary also contains framework NSLog calls such as
NSLog(@"Class <classname> instance released")
on object deallocation, plus some internal error logs. Minor, but it's console
noise and a little internal-structure disclosure in production.
Ask: suppress framework NSLog in Release builds (or provide a switch).
------------------------------------------------------------
3) ATS is disabled by default, with no clean way to scope exceptions
------------------------------------------------------------
B4i injects NSAppTransportSecurity { NSAllowsArbitraryLoads = true } into the
generated Info.plist by default (there is no #ATSEnabled in my project, yet it
is present). To restrict cleartext to a few specific hosts I had to add
NSExceptionDomains via #PlistExtra - which risks producing a duplicate
NSAppTransportSecurity key if the framework also emits its own.
Ask: consider defaulting ATS on, and/or adding a supported directive for
NSExceptionDomains, so apps can scope cleartext without fighting the default
or risking a duplicate key.
------------------------------------------------------------
I'm happy to send the decompiled snippets or any more detail if useful.
Thanks for B4i.
------------------------------------------------------------------------------------
Thanks....
Me:
========================
Hi Erel,
During a Claude Code vulnerability analysis of a major customer facing B4i app (see here) it came up with some things to bring to your attention.
It literally said "tell Erel...", so:
------------------------------------------------------------------------------------
Subject: [B4i] Generated AppDelegate logs full openURL (including deep-link
tokens) via NSLog in Release builds
Hi Erel,
While doing a security review of one of my released B4i apps (I decompiled the
shipped IPA), I found a few things that are in B4i's generated/framework code
or defaults - i.e. things an app developer can't change from their own
project. Flagging them in case they're easy improvements.
Environment: B4i [B4i version], iOS SDK 26 / Xcode 26, Release (obfuscated)
build.
------------------------------------------------------------
1) AppDelegate logs the full openURL, including secrets carried in the URL
(this is the important one)
------------------------------------------------------------
The generated app delegate's openURL handler logs the entire incoming URL:
application
-> NSLog(@"openURL: %@, %@, %@", url, sourceApplication, annotation)
I confirmed this in the decompiled Release binary - the format string
"openURL: %@, %@, %@" is present in the shipped executable, so it runs in
Release, not just Debug.
Why it matters: custom-scheme deep links very commonly carry sensitive data -
auth tokens, magic-link codes, account identifiers. (My app's scheme passes an
unguessable capability token.) Because this fires in Release, every deep-link
open writes that token into the device unified log, which is readable via
Console.app / a sysdiagnose. That's sensitive data in logs (CWE-532), and the
app author has no way to suppress it.
Ask: please don't log the URL value, or gate that NSLog behind a debug-only
condition so it doesn't fire in Release builds.
------------------------------------------------------------
2) Framework lifecycle logging is present in Release
------------------------------------------------------------
The Release binary also contains framework NSLog calls such as
NSLog(@"Class <classname> instance released")
on object deallocation, plus some internal error logs. Minor, but it's console
noise and a little internal-structure disclosure in production.
Ask: suppress framework NSLog in Release builds (or provide a switch).
------------------------------------------------------------
3) ATS is disabled by default, with no clean way to scope exceptions
------------------------------------------------------------
B4i injects NSAppTransportSecurity { NSAllowsArbitraryLoads = true } into the
generated Info.plist by default (there is no #ATSEnabled in my project, yet it
is present). To restrict cleartext to a few specific hosts I had to add
NSExceptionDomains via #PlistExtra - which risks producing a duplicate
NSAppTransportSecurity key if the framework also emits its own.
Ask: consider defaulting ATS on, and/or adding a supported directive for
NSExceptionDomains, so apps can scope cleartext without fighting the default
or risking a duplicate key.
------------------------------------------------------------
I'm happy to send the decompiled snippets or any more detail if useful.
Thanks for B4i.
------------------------------------------------------------------------------------
Thanks....