Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6b1d5c8
feat: bump Android SDK to 18.3.0
martinzigrai May 7, 2026
1058b9e
feat!: rename reason to reasons in SuspiciousAppInfo
martinzigrai May 7, 2026
bd7894b
feat!: deprecate old malware config fields
martinzigrai May 7, 2026
56487c3
feat: add SuspiciousAppDetectionConfig to API
martinzigrai May 7, 2026
ba56ae0
refactor: extract SuspiciousAppDetectionConfig parsing to utils
martinzigrai May 7, 2026
6909054
chore: update changelog for 7.6.0
martinzigrai May 7, 2026
be0649a
style: format suspicious_app_detection_config.g.dart
martinzigrai May 11, 2026
e4258fc
fix: resolve lint issues - deprecated_consistency and prefer_const_co…
martinzigrai May 11, 2026
ba45995
style: format android_config.dart
martinzigrai May 11, 2026
cccbd74
fix: use positional args and correct types for MalwareScanScope and S…
martinzigrai May 12, 2026
a545b78
Merge branch 'master' into rc/7.6.0
tompsota May 13, 2026
393fa70
feat!: remove deprecated MalwareConfig API
martinzigrai May 13, 2026
8cf8248
refactor: tighten SuspiciousAppDetectionConfig parsing
martinzigrai May 13, 2026
aafe0d2
test: cover SuspiciousAppDetectionConfig and related models
martinzigrai May 13, 2026
e065364
chore: bump to 8.0.0
martinzigrai May 13, 2026
6d9947b
style: format suspicious_app_detection_config_test.dart
martinzigrai May 13, 2026
44e000a
docs: drop stale TalsecConfig.Builder deprecation note
martinzigrai May 13, 2026
74f7cce
chore: changelog + comments update
martinzigrai May 15, 2026
bd99a7f
Revert "chore: changelog + comments update"
martinzigrai May 15, 2026
e3dcac7
docs: CHANGELOG update
martinzigrai May 15, 2026
11f8e45
refactor: rename MalwareScanScope to ScanScope and malwareScanScope f…
martinzigrai May 18, 2026
3958139
fix: unify API with other platforms
martinzigrai May 27, 2026
b22631f
refactor: rename ScanScope.scanScope field to scopeType
tompsota May 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,50 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [7.6.0] - 2026-05-07

- Android SDK version: 18.3.0
- iOS SDK version: 6.14.4

### Breaking
Comment thread
tompsota marked this conversation as resolved.
Outdated

- `SuspiciousAppInfo.reason` (String) renamed to `reasons` (List\<String\>)
- Value `"blacklist"` in `reasons` renamed to `"blocklist"`

### Flutter

#### Deprecated

- `blacklistedPackageNames`, `blacklistedHashes`, `suspiciousPermissions`, `whitelistedInstallationSources` are deprecated but remain functional — use `SuspiciousAppDetectionConfig` instead

### Android

#### Added

- Added a new sub-check for `HMA` detection to the root detector
- Added a new sub-check for `KernelSU` detection to the root detector
- Added a new sub-check for `Frida Server` detection to the hook detector
- Added Huawei App Market provider to HMA detection queries
- New API class `SuspiciousAppDetectionConfig` that can be used to configure malware detection
- New API for malware detection configuration in `TalsecConfig`, see `TalsecConfig.Builder#suspiciousAppDetection`

#### Fixed

- Fixed `VerifyError` caused by `JaCoCo` bytecode instrumentation
- Fixed a potential cause of crash in the multi-instance detector
- Fixed crash caused by unhandled `SecurityException` thrown by `UsageStatsManager` in root detection
- Fixed manifest merge conflicts in HMA detection providers
- Fixed Java interoperability of `ScreenProtector` methods
- Fixed Kotlin classpath conflicts in SDK dependency resolution (Kotlin 2.0.0)

#### Changed

- Fine-tuned `KernelSU` detection
- Fine-tuned hook detection
- Fine-tuned location spoofing detection
- Modified malware incident log structure for better aggregation
- Old malware configuration API methods in `TalsecConfig.Builder` tagged as deprecated (but remain functional): `blacklistedPackageNames`, `blacklistedHashes`, `suspiciousPermissions`, `whitelistedInstallationSources`

## [7.5.1] - 2026-03-24

- Android SDK version: 18.0.4
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ version '1.0-SNAPSHOT'

buildscript {
ext.kotlin_version = '2.1.0'
ext.talsec_version = '18.0.4'
ext.talsec_version = '18.3.0'
repositories {
google()
mavenCentral()
Expand Down
52 changes: 51 additions & 1 deletion android/src/main/kotlin/com/aheaditec/freerasp/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ import android.content.Context
import android.content.pm.PackageInfo
import android.os.Build
import com.aheaditec.talsec_security.security.api.ExternalIdResult
import com.aheaditec.talsec_security.security.api.MalwareScanScope
import com.aheaditec.talsec_security.security.api.ReasonMode
import com.aheaditec.talsec_security.security.api.ScopeType
import com.aheaditec.talsec_security.security.api.SuspiciousAppDetectionConfig
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
import io.flutter.plugin.common.MethodChannel
import org.json.JSONObject
import com.aheaditec.freerasp.generated.PackageInfo as FlutterPackageInfo
import com.aheaditec.freerasp.generated.SuspiciousAppInfo as FlutterSuspiciousAppInfo

Expand Down Expand Up @@ -33,7 +38,7 @@ internal inline fun runResultCatching(result: MethodChannel.Result, block: () ->
* this [SuspiciousAppInfo].
*/
internal fun SuspiciousAppInfo.toPigeon(context: Context): FlutterSuspiciousAppInfo {
return FlutterSuspiciousAppInfo(this.packageInfo.toPigeon(context), this.reason)
return FlutterSuspiciousAppInfo(this.packageInfo.toPigeon(context), this.reasons.toList())
}

/**
Expand Down Expand Up @@ -83,3 +88,48 @@ internal fun ExternalIdResult.resolve(result: MethodChannel.Result) {
is ExternalIdResult.Error -> result.error("external-id-failure", this.errorMsg, null)
}
}

internal fun JSONObject.toMalwareScanScope(): MalwareScanScope {
val scopeTypeStr = optString("scanScope", "SIDELOADED_ONLY")
val scanScope = runCatching { ScopeType.valueOf(scopeTypeStr) }.getOrDefault(ScopeType.SIDELOADED_ONLY)
val trustedInstallSources = optJSONArray("trustedInstallSources")?.let { arr ->
(0 until arr.length()).map { arr.getString(it) }.toSet()
}
return MalwareScanScope(scanScope = scanScope, trustedInstallSources = trustedInstallSources)
}

internal fun JSONObject.toSuspiciousAppDetectionConfig(): SuspiciousAppDetectionConfig {
val packageNames = optJSONArray("packageNames")?.let { arr ->
(0 until arr.length()).map { arr.getString(it) }.toSet()
}
val hashes = optJSONArray("hashes")?.let { arr ->
(0 until arr.length()).map { arr.getString(it) }.toSet()
}
val requestedPermissions = optJSONArray("requestedPermissions")?.let { outer ->
(0 until outer.length()).map { i ->
val inner = outer.getJSONArray(i)
(0 until inner.length()).map { j -> inner.getString(j) }.toSet()
}.toSet()
}
val grantedPermissions = optJSONArray("grantedPermissions")?.let { outer ->
(0 until outer.length()).map { i ->
val inner = outer.getJSONArray(i)
(0 until inner.length()).map { j -> inner.getString(j) }.toSet()
}.toSet()
}
val malwareScanScope = optJSONObject("malwareScanScope")?.toMalwareScanScope()
val reasonModeStr = optString("reasonMode")
Comment thread
tompsota marked this conversation as resolved.
Outdated
val reasonMode = if (reasonModeStr.isNullOrEmpty()) {
Comment thread
tompsota marked this conversation as resolved.
Outdated
ReasonMode.HIGHEST_CONFIDENCE
} else {
runCatching { ReasonMode.valueOf(reasonModeStr) }.getOrDefault(ReasonMode.HIGHEST_CONFIDENCE)
}
return SuspiciousAppDetectionConfig(
packageNames = packageNames,
hashes = hashes,
requestedPermissions = requestedPermissions,
grantedPermissions = grantedPermissions,
malwareScanScope = malwareScanScope,
reasonMode = reasonMode,
)
}
11 changes: 8 additions & 3 deletions android/src/main/kotlin/com/aheaditec/freerasp/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal object Utils {
val alternativeStores = androidConfig.extractArray<String>("supportedStores")
val malwareConfig = parseMalwareConfig(androidConfig)

return TalsecConfig.Builder(packageName, certificateHashes)
val builder = TalsecConfig.Builder(packageName, certificateHashes)
.watcherMail(watcherMail)
.supportedAlternativeStores(alternativeStores)
.prod(isProd)
Expand All @@ -47,7 +47,12 @@ internal object Utils {
.blacklistedHashes(malwareConfig.blacklistedHashes)
.suspiciousPermissions(malwareConfig.suspiciousPermissions)
.whitelistedInstallationSources(malwareConfig.whitelistedInstallationSources)
.build()

androidConfig.optJSONObject("suspiciousAppDetectionConfig")?.let {
builder.suspiciousAppDetection(it.toSuspiciousAppDetectionConfig())
}

return builder.build()
}

private fun parseMalwareConfig(androidConfig: JSONObject): MalwareConfig {
Expand Down Expand Up @@ -175,4 +180,4 @@ private inline fun <reified T> processArray(jsonArray: JSONArray): Array<T> {
}

return list.toTypedArray()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,20 @@ data class PackageInfo (
/** Generated class from Pigeon that represents data sent in messages. */
data class SuspiciousAppInfo (
val packageInfo: PackageInfo,
val reason: String
val reasons: List<String>
)
{
companion object {
fun fromList(pigeonVar_list: List<Any?>): SuspiciousAppInfo {
val packageInfo = pigeonVar_list[0] as PackageInfo
val reason = pigeonVar_list[1] as String
return SuspiciousAppInfo(packageInfo, reason)
val reasons = pigeonVar_list[1] as List<String>
return SuspiciousAppInfo(packageInfo, reasons)
}
}
fun toList(): List<Any?> {
return listOf(
packageInfo,
reason,
reasons,
)
}
}
Expand Down
10 changes: 7 additions & 3 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@ Future<void> _initializeTalsec() async {
packageName: 'com.aheaditec.freeraspExample',
signingCertHashes: ['AKoRuyLMM91E7lX/Zqp3u4jMmd0A7hH/Iqozu0TMVd0='],
supportedStores: ['com.sec.android.app.samsungapps'],
malwareConfig: MalwareConfig(
blacklistedPackageNames: ['com.aheaditec.freeraspExample'],
suspiciousPermissions: [
suspiciousAppDetectionConfig: SuspiciousAppDetectionConfig(
Comment thread
tompsota marked this conversation as resolved.
Outdated
packageNames: ['com.aheaditec.freeraspExample'],
requestedPermissions: [
['android.permission.CAMERA'],
['android.permission.READ_SMS', 'android.permission.READ_CONTACTS'],
],
malwareScanScope: MalwareScanScope(
Comment thread
tompsota marked this conversation as resolved.
Outdated
scanScope: ScopeType.sideloadedOnly,
),
reasonMode: ReasonMode.highestConfidence,
),
),
iosConfig: IOSConfig(
Expand Down
2 changes: 1 addition & 1 deletion example/lib/widgets/malware_bottom_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class MalwareListTile extends StatelessWidget {

return ListTile(
title: Text(malware.packageInfo.packageName),
subtitle: Text('Reason: ${malware.reason}'),
subtitle: Text('Reasons: ${malware.reasons.join(', ')}'),
leading: appIcon,
);
},
Expand Down
8 changes: 4 additions & 4 deletions lib/src/generated/talsec_pigeon_api.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,25 @@ class PackageInfo {
class SuspiciousAppInfo {
SuspiciousAppInfo({
required this.packageInfo,
required this.reason,
required this.reasons,
});

PackageInfo packageInfo;

String reason;
List<String> reasons;

Object encode() {
return <Object?>[
packageInfo,
reason,
reasons,
];
}

static SuspiciousAppInfo decode(Object result) {
result as List<Object?>;
return SuspiciousAppInfo(
packageInfo: result[0]! as PackageInfo,
reason: result[1]! as String,
reasons: (result[1] as List<Object?>?)!.cast<String>(),
);
}
}
Expand Down
5 changes: 5 additions & 0 deletions lib/src/models/android_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class AndroidConfig {
required this.signingCertHashes,
this.supportedStores = const [],
this.malwareConfig,
this.suspiciousAppDetectionConfig,
}) {
ConfigVerifier.verifyAndroid(this);
}
Expand All @@ -34,5 +35,9 @@ class AndroidConfig {
final List<String> supportedStores;

/// Malware configuration for Android.
@Deprecated('Use suspiciousAppDetectionConfig instead')
final MalwareConfig? malwareConfig;

/// Suspicious app detection configuration for Android.
final SuspiciousAppDetectionConfig? suspiciousAppDetectionConfig;
}
10 changes: 9 additions & 1 deletion lib/src/models/android_config.g.dart
Comment thread
tompsota marked this conversation as resolved.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions lib/src/models/malware_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ part 'malware_config.g.dart';
class MalwareConfig {
/// Creates a new instance of [MalwareConfig].
MalwareConfig({
@Deprecated('Use SuspiciousAppDetectionConfig instead')
this.blacklistedPackageNames = const [],
@Deprecated('Use SuspiciousAppDetectionConfig instead')
this.blacklistedHashes = const [],
@Deprecated('Use SuspiciousAppDetectionConfig instead')
this.suspiciousPermissions = const [],
@Deprecated('Use SuspiciousAppDetectionConfig instead')
this.whitelistedInstallationSources = const [],
});

Expand All @@ -21,14 +25,18 @@ class MalwareConfig {
Map<String, dynamic> toJson() => _$MalwareConfigToJson(this);

/// List of blocklisted applications with given package name.
@Deprecated('Use SuspiciousAppDetectionConfig instead')
final List<String> blacklistedPackageNames;

/// List of blocklisted applications with given hash.
@Deprecated('Use SuspiciousAppDetectionConfig instead')
final List<String> blacklistedHashes;

/// List of blocklisted applications with given permissions.
@Deprecated('Use SuspiciousAppDetectionConfig instead')
final List<List<String>> suspiciousPermissions;

/// List of whitelisted installation sources.
@Deprecated('Use SuspiciousAppDetectionConfig instead')
final List<String> whitelistedInstallationSources;
}
1 change: 1 addition & 0 deletions lib/src/models/models.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export 'android_config.dart';
export 'ios_config.dart';
export 'malware_config.dart';
export 'suspicious_app_detection_config.dart';
export 'talsec_config.dart';
Loading
Loading