iOS Question #ATSEnabled: True vs #PlistExtra:<key>NSAppTransportSecurity</key>...

JackKirk

Well-Known Member
Licensed User
Longtime User
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:eek: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....
 

JackKirk

Well-Known Member
Licensed User
Longtime User
Erel:
========================
Thanks!

1. Removed for the next update.
2. I don't think that it is significant.
3. For many years now the project template includes:
B4X:

#ATSEnabled: True

So ATS is enabled.
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Me:
========================
Hi Erel, this stuff is at the fringes of my competence.

Claude got me to include the following in my B4i project:
B4X:

'claude was here
'Scope App Transport Security - allow insecure http ONLY to 3 AWS S3 static-website
'hosts (http-only by design); deny cleartext to every other host
'Replaces B4i default blanket NSAllowsArbitraryLoads=true
'IMPORTANT: if ever add another environment, add its website host here too
'Must be a single line
#PlistExtra:<key>NSAppTransportSecurity</key><dict><key>NSExceptionDomains</key><dict><key>xxx1.com.s3-website-ap-southeast-2.amazonaws.com</key><dict><key>NSExceptionAllowsInsecureHTTPLoads</key><true/></dict><key>xxx2.com.s3-website-ap-southeast-2.amazonaws.com</key><dict><key>NSExceptionAllowsInsecureHTTPLoads</key><true/></dict><key>xxx3.com.s3-website.eu-west-2.amazonaws.com</key><dict><key>NSExceptionAllowsInsecureHTTPLoads</key><true/></dict></dict></dict>
I understand this is so that it only allows insecure http to 3 AWS S3 static-websites

If ATS is enabled by default would this desired effect happen? - i,e, nothing else can gain access by http - if this sentence is non-sensical then I revert to my opening sentence. :)
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Me:
========================
Erel, sorry for gnawing on the bone, do I take this to mean my #PlistExtra:<key>NSAppTransportSecurity,,,, overrides the default #ATSEnabled: True?
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Erel:
========================
@JackKirk this is a good question which I need to investigate. Please start a new thread for this in the forum.
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
1. Best way to check it is by opening Objects\src\B4iProject\B4iProject-Info.plist after compilation. This is the generated plist file.
OK I did that - see attached file (added .txt to allow it to upload to B4X).

There appear to be 2 relevant entries:

<key>NSAppTransportSecurity</key><dict><key>NSExceptionDomains</key><dict><key>ftr-sps-ta-web.com.s3-website-ap-southeast-2.amazonaws.com</key><dict><key>NSExceptionAllowsInsecureHTTPLoads</key><true/></dict><key>ftr-sps-wildnets-web.com.s3-website-ap-southeast-2.amazonaws.com</key><dict><key>NSExceptionAllowsInsecureHTTPLoads</key><true/></dict><key>ftr-sps-goape-web.com.s3-website.eu-west-2.amazonaws.com</key><dict><key>NSExceptionAllowsInsecureHTTPLoads</key><true/></dict></dict></dict>

which has obviously come from my #PlistExtra - but there is another, higher up:

<key>NSAppTransportSecurity</key><dict><key>NSAllowsArbitraryLoads</key><true/></dict>

which looks worrying?
 

Attachments

  • B4iProject-Info.plist.txt
    2.7 KB · Views: 36
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Something else. I ran the entire plist by Copilot (exhausted Claude until 4pm) and it indicated that it thought the second one (mine) would overrule the first but:

4. This is NOT valid ATS structure

Apple expects one ATS dictionary.

Your plist currently violates deterministic structure rules — and may cause:

  • unpredictable behaviour
  • App Store review rejection
  • ATS silently enforcing stricter rules than intended
  • B4i build system warnings (depending on version)
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Make sure to set #ATSEnabled: True in your project.
Erel, I did that and it removed the worrying:

<key>NSAppTransportSecurity</key><dict><key>NSAllowsArbitraryLoads</key><true/></dict>

but it has left me confused, here you said:

3. For many years now the project template includes:
B4X:

#ATSEnabled: True

So ATS is enabled.

Sorry for being a pain but I would like to understand what is going on.
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
I guess that your project was created with a template that didn't include #ATSEnabled.
This sent me on a dig - my B4i app has been evolving since 2017 - did #ATSEnabled: True get added to the default template later than this?
 
Upvote 0

JackKirk

Well-Known Member
Licensed User
Longtime User
Why does it matter?
Sorry for being a PITA but I like to understand why things happen.

I managed to wire Claude Code to analyse the old B4i install packages I have (back to 2.31) - without installing them - it found ATSEnabled = True in the default template at 3.6 - dated 17/4/17 - so it looks like I just missed out when I started this app development.

VersionDate#ATSEnabled recognisedIn default template
2.31Jan 2016
2.50Feb 2016
2.80Aug 2016
3.60Apr 2017✓ #ATSEnabled: True

I am seriously in love with Claude Code...
 
Last edited:
Upvote 0
Top