Security false positives
- Introduction
- Common concerns
- Shared objects should use fortified functions
- Shared objects should use RELRO
- Shared objects should use stack canary values
- Code should avoid using the _sscanf, _strlen, and _fopen APIs
- Code should use calloc (instead of _malloc) for memory allocations
- The iOS binary has a Runpath Search Path (@rpath) set
- CBC with PKCS5/PKCS7 padding vulnerability
- Apps can read and write to external storage
- Apps delete data using file.delete()
- Obsolete concerns
- Reporting real concerns
Introduction
We occasionally receive false reports of security vulnerabilities in Dart and Flutter applications, generated by tools that were built for other kinds of applications (for example, those written with Java or C++). This document provides information on reports that we believe are incorrect and explains why the concerns are misplaced.
Common concerns
Shared objects should use fortified functions
The shared object does not have any fortified functions. Fortified functions provides buffer overflow checks against glibc’s commons insecure functions like
strcpy
,gets
etc. Use the compiler option-D_FORTIFY_SOURCE=2
to fortify functions.
When this refers to compiled Dart code
(such as the libapp.so
file in Flutter applications),
this advice is misguided because Dart code doesn’t
directly invoke libc functions;
all Dart code goes through the Dart standard library.
(In general, MobSF gets false positives here because
it checks for any use of functions with a _chk
suffix,
but since Dart doesn’t use these functions at all,
it doesn’t have calls with or without the suffix,
and therefore MobSF treats the code as containing
non-fortified calls.)
Shared objects should use RELRO
no RELRO found for
libapp.so
binaries
Dart doesn’t use the normal Procedure Linkage Table (PLT) or Global Offsets Table (GOT) mechanisms at all, so the Relocation Read-Only (RELRO) technique doesn’t really make much sense for Dart.
Dart’s equivalent of GOT is the pool pointer, which unlike GOT, is located in a randomized location and is therefore much harder to exploit.
In principle, you can create vulnerable code when using Dart FFI, but normal use of Dart FFI wouldn’t be prone to these issues either, assuming it’s used with C code that itself uses RELRO appropriately.
Shared objects should use stack canary values
no canary are found for
libapp.so
binaries
This shared object does not have a stack canary value added to the stack. Stack canaries are used to detect and prevent exploits from overwriting return address. Use the option -fstack-protector-all to enable stack canaries.
Dart doesn’t generate stack canaries because, unlike C++, Dart doesn’t have stack-allocated arrays (the primary source of stack smashing in C/C++).
When writing pure Dart (without using dart:ffi
),
you already have much stronger isolation guarantees
than any C++ mitigation can provide,
simply because pure Dart code is a managed language
where things like buffer overruns don’t exist.
In principle, you can create vulnerable code when using Dart FFI, but normal use of Dart FFI would not be prone to these issues either, assuming it’s used with C code that itself uses stack canary values appropriately.
_sscanf
, _strlen
, and _fopen
APIs
Code should avoid using the The binary may contain the following insecure API(s)
_sscanf
,_strlen
,_fopen
.
The tools that report these issues tend to be overly-simplistic in their scans; for example, finding custom functions with these names and assuming they refer to the standard library functions. Many of Flutter’s third-party dependencies have functions with similar names that trip these checks. It’s possible that some occurrences are valid concerns, but it’s impossible to tell from the output of these tools due to the sheer number of false positives.
calloc
(instead of _malloc
) for memory allocations
Code should use The binary may use
_malloc
function instead ofcalloc
.
Memory allocation is a nuanced topic,
where trade-offs have to be made between performance
and resilience to vulnerabilities.
Merely using malloc
is not automatically indicative
of a security vulnerability.
While we welcome concrete reports (see below)
for cases where using calloc
would be preferable,
in practice it would be inappropriate to uniformly
replace all malloc
calls with calloc
.
@rpath
) set
The iOS binary has a Runpath Search Path (The binary has Runpath Search Path (
@rpath
) set. In certain cases an attacker can abuse this feature to run arbitrary executable for code execution and privilege escalation. Remove the compiler option-rpath
to remove@rpath
.
When the app is being built, Runpath Search Path refers
to the paths the linker searches to find dynamic libraries
(dylibs) used by the app.
By default, iOS apps have this set to
@executable_path/Frameworks
,
which means the linker should search for dylibs
in the Frameworks
directory relative to the app
binary inside the app bundle.
The Flutter.framework
engine,
like most embedded frameworks or dylibs,
is correctly copied into this directory.
When the app runs, it loads the library binary.
Flutter apps use the default iOS build setting
(LD_RUNPATH_SEARCH_PATHS=@executable_path/Frameworks
).
Vulnerabilities involving @rpath
don’t apply
in mobile settings, as attackers don’t have
access to the file system and can’t arbitrarily
swap out these frameworks.
Even if an attacker somehow could swap out the
framework with a malicious one,
the app would crash on launch due to codesigning violations.
CBC with PKCS5/PKCS7 padding vulnerability
We have received vague reports that there is a “CBC with PKCS5/PKCS7 padding vulnerability” in some Flutter packages.
As far as we can tell, this is triggered by the HLS
implementation in ExoPlayer
(the com.google.android.exoplayer2.source.hls.Aes128DataSource
class).
HLS is Apple’s streaming format,
which defines the type of encryption that must be used for DRM;
this isn’t a vulnerability,
as DRM doesn’t protect the user’s machine or data
but instead merely provides obfuscation
to limit the user’s ability to fully use their software and hardware.
Apps can read and write to external storage
App can read/write to External Storage. Any App can read data written to External Storage.
As with data from any untrusted source, you should perform input validation when handling data from external storage. We strongly recommend that you not store executables or class files on external storage prior to dynamic loading. If your app does retrieve executable files from external storage, the files should be signed and cryptographically verified prior to dynamic loading.
We have received reports that some vulnerability scanning tools interpret the ability for image picker plugins to read and write to external storage as a threat.
Reading images from local storage is the purpose of these plugins; this is not a vulnerability.
Apps delete data using file.delete()
When you delete a file using file. delete, only the reference to the file is removed from the file system table. The file still exists on disk until other data overwrites it, leaving it vulnerable to recovery.
Some vulnerability scanning tools interpret the deletion of temporary files after a camera plugin records data from the device’s camera as a security vulnerability. Because the video is recorded by the user and is stored on the user’s hardware, there is no actual risk.
Obsolete concerns
This section contains valid messages that might be seen with older versions of Dart and Flutter, but should no longer be seen with more recent versions. If you see these messages with old versions of Dart or Flutter, upgrade to the latest stable version. If you see these with the current stable version, please report them (see the section at the end of this document).
The stack should have its NX bit set
The shared object does not have NX bit set. NX bit offer protection against exploitation of memory corruption vulnerabilities by marking memory page as non-executable. Use option
--noexecstack
or-z noexecstack
to mark stack as non executable.
(The message from MobSF is misleading; it’s looking for whether the stack is marked as non-executable, not the shared object.)
In older versions of Dart and Flutter there was a bug
where the ELF generator didn’t emit the gnustack
segment with the ~X
permission, but this is now fixed.
Reporting real concerns
While automated vulnerability scanning tools report false positives such as the examples above, we can’t rule out that there are real issues that deserve closer attention. Should you find an issue that you believe is a legitimate security vulnerability, we would greatly appreciate if you would report it: