M08: Security Misconfiguration - Examples
Table of Contents
- Vulnerable Examples
- Secure Examples
- Configuration Comparisons
- Platform-Specific Examples
- Real-World Scenarios
Vulnerable Examples
❌ Example 1: Debuggable Production App
Vulnerable Code (Android - AndroidManifest.xml):``xml
android:allowBackup="true"
android:label="@string/app_name">
android:exported="true">
Why It's Vulnerable:
- Allows runtime debugging with tools like
jdb
Enables memory inspection and manipulation
Allows attachment of debugging tools without rooting
Exposes internal app state and data
Can bypass security checks through debugging
Attack Vector:
`bash
Attacker can attach debugger to running app
adb jdwp # List debuggable processes
adb forward tcp:8700 jdwp:
jdb -attach localhost:8700
Then execute arbitrary code or inspect memory
`
❌ Example 2: Excessive Permissions
Vulnerable Code (Android - AndroidManifest.xml):
`xml
package="com.example.overprivileged">
`
Why It's Vulnerable:
- Violates principle of least privilege
- Increases attack surface
- Privacy concerns for users
- Potential for data exfiltration
- May be rejected by app stores
- Users may refuse installation
❌ Example 3: Cleartext Traffic Allowed
Vulnerable Code (Android - AndroidManifest.xml):
`xml
package="com.example.insecurenetwork">
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config">
`
Why It's Vulnerable:
- Allows unencrypted HTTP connections
- Susceptible to man-in-the-middle attacks
- Credentials and data sent in plaintext
- Network traffic can be intercepted
- User-installed certificates trusted (allows SSL interception)
Attack Vector:
`bash
Attacker on same network can intercept traffic
mitmproxy -p 8080
All HTTP traffic visible and modifiable
`
❌ Example 4: Exported Components Without Protection
Vulnerable Code (Android - AndroidManifest.xml):
`xml
package="com.example.exposedcomponents">
android:name=".AdminActivity"
android:exported="true">
android:name=".UserDataProvider"
android:authorities="com.example.provider.userdata"
android:exported="true"
android:grantUriPermissions="true" />
android:name=".PaymentReceiver"
android:exported="true">
android:name=".DatabaseService"
android:exported="true" />
`
Why It's Vulnerable:
- Any app can invoke exported components
- No authentication or authorization
- Potential for unauthorized data access
- Possible privilege escalation
- Can trigger sensitive operations
Attack Vector:
`bash
Attacker app can invoke admin activity
adb shell am start -n com.example.exposedcomponents/.AdminActivity
Access content provider data
adb shell content query --uri content://com.example.provider.userdata/users
Send malicious broadcast
adb shell am broadcast -a com.example.PAYMENT_COMPLETE
`
❌ Example 5: Backup Including Sensitive Data
Vulnerable Code (Android - AndroidManifest.xml):
`xml
package="com.example.unsecurebackup">
android:allowBackup="true">
`
Vulnerable Storage Code:
`java
public class LoginManager {
public void saveCredentials(String username, String password) {
// VULNERABLE: Stored in shared preferences (included in backups)
SharedPreferences prefs = context.getSharedPreferences("user_prefs", MODE_PRIVATE);
prefs.edit()
.putString("username", username)
.putString("password", password) // Plaintext password in backup!
.putString("api_token", apiToken)
.apply();
}
}
`
Why It's Vulnerable:
- Sensitive data included in Android backups
- Accessible via
adb backup
Restored to different devices
No encryption for backup data
Accessible on compromised Google accounts
Attack Vector:
`bash
Extract backup with sensitive data
adb backup -f backup.ab -noapk com.example.unsecurebackup
Convert and extract
dd if=backup.ab bs=24 skip=1 | openssl zlib -d > backup.tar
tar -xvf backup.tar
Access shared_prefs/user_prefs.xml with passwords
`
❌ Example 6: Weak WebView Configuration
Vulnerable Code (Android - Java):
`java
public class VulnerableWebViewActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView webView = new WebView(this);
WebSettings settings = webView.getSettings();
// VULNERABLE: Dangerous WebView configuration
settings.setJavaScriptEnabled(true);
settings.setAllowFileAccess(true);
settings.setAllowContentAccess(true);
settings.setAllowFileAccessFromFileURLs(true);
settings.setAllowUniversalAccessFromFileURLs(true);
settings.setDomStorageEnabled(true);
settings.setDatabaseEnabled(true);
// VULNERABLE: JavaScript interface exposed
webView.addJavascriptInterface(new JavaScriptInterface(), "Android");
// VULNERABLE: Loading untrusted content
String userUrl = getIntent().getStringExtra("url");
webView.loadUrl(userUrl); // No URL validation!
// VULNERABLE: Debugging enabled
WebView.setWebContentsDebuggingEnabled(true);
setContentView(webView);
}
// VULNERABLE: Exposed interface
public class JavaScriptInterface {
@JavascriptInterface
public String getSensitiveData() {
return readSensitiveData(); // Accessible from JavaScript!
}
}
}
`
Why It's Vulnerable:
- JavaScript can access local files
- Cross-site scripting (XSS) attacks possible
- Arbitrary file read/write
- JavaScript interface exposes native functions
- No URL validation
- Chrome DevTools can inspect WebView
Attack Vector:
`javascript
// Malicious website loaded in WebView
`
❌ Example 7: iOS Insecure App Transport Security
Vulnerable Code (iOS - Info.plist):
`xml
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
NSAppTransportSecurity
NSAllowsArbitraryLoads
NSAllowsArbitraryLoadsInWebContent
NSAllowsLocalNetworking
NSPhotoLibraryUsageDescription
We need access
NSCameraUsageDescription
We need access
NSMicrophoneUsageDescription
We need access
NSLocationWhenInUseUsageDescription
We need access
NSLocationAlwaysUsageDescription
We need access
NSContactsUsageDescription
We need access
`
Why It's Vulnerable:
- Allows HTTP connections (no encryption)
- Man-in-the-middle attacks possible
- Weak TLS versions accepted
- No certificate validation
- Vague permission descriptions (may be rejected)
❌ Example 8: Missing ProGuard Configuration
Vulnerable Code (Android - build.gradle):
`gradle
android {
buildTypes {
release {
// VULNERABLE: ProGuard disabled
minifyEnabled false
shrinkResources false
// No obfuscation
// debuggable false // Commented out!
}
}
}
`
Why It's Vulnerable:
- Easy to reverse engineer
- Class and method names readable
- String literals visible
- Debug information present
- Larger APK size
- Security through obscurity reduced
Secure Examples
✅ Example 1: Secure Android Manifest
Secure Code (Android - AndroidManifest.xml):
`xml
package="com.example.secureapp">
android:name=".SecureApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:debuggable="false"
android:allowBackup="true"
android:fullBackupContent="@xml/backup_rules"
android:dataExtractionRules="@xml/data_extraction_rules"
android:usesCleartextTraffic="false"
android:networkSecurityConfig="@xml/network_security_config"
android:requestLegacyExternalStorage="false">
android:name=".MainActivity"
android:exported="true">
android:name=".ProfileActivity"
android:exported="false" />
android:name=".SecureDataProvider"
android:authorities="com.example.secureapp.provider"
android:exported="false"
android:grantUriPermissions="false" />
`
Secure Backup Configuration (res/xml/backup_rules.xml):
`xml
`
Secure Network Configuration (res/xml/network_security_config.xml):
`xml
api.example.com
primaryCertificateHash==
backupCertificateHash==
`
✅ Example 2: Secure Build Configuration
Secure Code (Android - build.gradle):
`gradle
android {
compileSdkVersion 34
defaultConfig {
applicationId "com.example.secureapp"
minSdkVersion 26
targetSdkVersion 34
versionCode 1
versionName "1.0"
// ✅ GOOD: Specify supported architectures
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
signingConfigs {
release {
// ✅ GOOD: Use secure signing (keys from environment)
// Validate signing configuration before using
def keystoreFile = System.getenv("KEYSTORE_FILE")
def keystorePass = System.getenv("KEYSTORE_PASSWORD")
def keyAlias = System.getenv("KEY_ALIAS")
def keyPass = System.getenv("KEY_PASSWORD")
if (keystoreFile && keystorePass && keyAlias && keyPass) {
storeFile file(keystoreFile)
storePassword keystorePass
keyAlias keyAlias
keyPassword keyPass
} else {
logger.warn("Release signing configuration not complete. Using debug signing.")
}
}
}
buildTypes {
debug {
debuggable true
minifyEnabled false
applicationIdSuffix '.debug'
versionNameSuffix '-DEBUG'
}
release {
// ✅ GOOD: Production hardening
debuggable false
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
signingConfig signingConfigs.release
// ✅ GOOD: Enable additional optimizations
crunchPngs true
// ✅ GOOD: Remove unused resources
resValue "string", "build_type", "release"
}
}
// ✅ GOOD: Disable development features in release
buildFeatures {
viewBinding true
buildConfig true
}
packagingOptions {
// ✅ GOOD: Exclude unnecessary files
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
}
}
dependencies {
// ✅ GOOD: Use latest security libraries
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
// ✅ GOOD: Debug tools only in debug builds
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
debugImplementation 'com.facebook.stetho:stetho:1.6.0'
}
`
Secure ProGuard Rules (proguard-rules.pro):
`proguard
✅ GOOD: Comprehensive ProGuard configuration
Optimization passes
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
Preserve stack traces for crash reporting
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile
Remove all logging
-assumenosideeffects class android.util.Log {
public static * d(...);
public static * v(...);
public static * i(...);
public static * w(...);
public static * e(...);
public static * wtf(...);
}
Remove debug classes completely
-assumenosideeffects class com.example.app.debug.** {
*;
}
Obfuscate but keep crash reporting functional
-keepattributes Annotation
-keepattributes Signature
-keepattributes Exception
Keep models for serialization
-keep class com.example.app.models.* { ; }
-keepclassmembers class com.example.app.models.* { ; }
Aggressive string encryption
-adaptclassstrings
-adaptresourcefilenames
-adaptresourcefilecontents
Remove unused code
-dontwarn **
-ignorewarnings
`
✅ Example 3: Secure iOS Configuration
Secure Code (iOS - Info.plist):
`xml
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
NSAppTransportSecurity
NSAllowsArbitraryLoads
NSExceptionDomains
api.example.com
NSExceptionRequiresForwardSecrecy
NSExceptionMinimumTLSVersion
TLSv1.3
NSIncludesSubdomains
NSRequiresCertificateTransparency
NSCameraUsageDescription
This app requires camera access to scan QR codes for secure authentication
NSPhotoLibraryUsageDescription
This app needs access to your photo library to allow you to select profile pictures
NSFileProtectionComplete
UIFileSharingEnabled
LSSupportsOpeningDocumentsInPlace
UIApplicationExitsOnSuspend
`
Secure iOS Build Settings (Build Configuration):
`swift
// ✅ GOOD: Conditional compilation for debug features
#if DEBUG
import os.log
class Logger {
static let enabled = true
static func log(_ message: String) {
os_log("%{public}@", log: .default, type: .debug, message)
}
}
#else
class Logger {
static let enabled = false
static func log(_ message: String) {
// No logging in production
}
}
#endif
// ✅ GOOD: Anti-debugging protection
class SecurityManager {
static func checkDebugger() {
#if !DEBUG
var info = kinfo_proc()
var size = MemoryLayout.stride
var mib: [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
let result = sysctl(&mib, UInt32(mib.count), &info, &size, nil, 0)
if result == 0 && (info.kp_proc.p_flag & P_TRACED) != 0 {
// Debugger detected in production - exit
exit(0)
}
#endif
}
}
`
✅ Example 4: Secure WebView Configuration
Secure Code (Android - Java):
`java
public class SecureWebViewActivity extends AppCompatActivity {
private static final List ALLOWED_DOMAINS = Arrays.asList(
"https://www.example.com",
"https://trusted.example.com"
);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView webView = new WebView(this);
WebSettings settings = webView.getSettings();
// ✅ GOOD: Minimal permissions
settings.setJavaScriptEnabled(true); // Only if necessary
settings.setAllowFileAccess(false);
settings.setAllowContentAccess(false);
settings.setAllowFileAccessFromFileURLs(false);
settings.setAllowUniversalAccessFromFileURLs(false);
// ✅ GOOD: Disable storage
settings.setDomStorageEnabled(false);
settings.setDatabaseEnabled(false);
settings.setSavePassword(false);
settings.setSaveFormData(false);
// ✅ GOOD: Security features
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_NEVER_ALLOW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
settings.setSafeBrowsingEnabled(true);
}
// ✅ GOOD: Disable debugging in production
if (!BuildConfig.DEBUG) {
WebView.setWebContentsDebuggingEnabled(false);
}
// ✅ GOOD: Set secure WebViewClient
webView.setWebViewClient(new SecureWebViewClient());
// ✅ GOOD: Validate URL before loading
String url = getIntent().getStringExtra("url");
if (isUrlAllowed(url)) {
webView.loadUrl(url);
} else {
showError("Invalid URL");
finish();
}
setContentView(webView);
}
// ✅ GOOD: URL validation
private boolean isUrlAllowed(String url) {
if (url == null || url.isEmpty()) {
return false;
}
try {
URL urlObj = new URL(url);
String protocol = urlObj.getProtocol();
// Only allow HTTPS
if (!"https".equals(protocol)) {
return false;
}
// Check against whitelist
for (String allowed : ALLOWED_DOMAINS) {
if (url.startsWith(allowed)) {
return true;
}
}
} catch (MalformedURLException e) {
return false;
}
return false;
}
// ✅ GOOD: Secure WebViewClient
private class SecureWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url = request.getUrl().toString();
if (isUrlAllowed(url)) {
return false; // Allow loading
}
// Block unauthorized URLs
return true;
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
// ✅ GOOD: Don't ignore SSL errors
handler.cancel();
showError("SSL Error: Connection not secure");
}
}
}
`
Secure Code (iOS - Swift):
`swift
import WebKit
class SecureWebViewController: UIViewController, WKNavigationDelegate {
private let allowedDomains = ["https://www.example.com", "https://trusted.example.com"]
private var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
// ✅ GOOD: Secure WebView configuration
let config = WKWebViewConfiguration()
let prefs = WKWebpagePreferences()
// Disable JavaScript if not needed
prefs.allowsContentJavaScript = true // Only if required
config.defaultWebpagePreferences = prefs
// ✅ GOOD: Disable inline media
config.allowsInlineMediaPlayback = false
config.mediaTypesRequiringUserActionForPlayback = .all
// ✅ GOOD: Minimize data detectors
config.dataDetectorTypes = []
// ✅ GOOD: Disable AirPlay
config.allowsAirPlayForMediaPlayback = false
webView = WKWebView(frame: .zero, configuration: config)
webView.navigationDelegate = self
// ✅ GOOD: Disable features
webView.allowsBackForwardNavigationGestures = false
webView.allowsLinkPreview = false
view.addSubview(webView)
// Load validated URL
if let urlString = validatedURL,
let url = URL(string: urlString) {
webView.load(URLRequest(url: url))
}
}
// ✅ GOOD: Validate navigation
func webView(_ webView: WKWebView,
decidePolicyFor navigationAction: WKNavigationAction,
decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else {
decisionHandler(.cancel)
return
}
if isURLAllowed(url) {
decisionHandler(.allow)
} else {
decisionHandler(.cancel)
showError("Unauthorized URL")
}
}
// ✅ GOOD: URL whitelist validation
private func isURLAllowed(_ url: URL) -> Bool {
guard let scheme = url.scheme, scheme == "https" else {
return false
}
let urlString = url.absoluteString
return allowedDomains.contains { urlString.hasPrefix($0) }
}
// ✅ GOOD: Handle SSL errors
func webView(_ webView: WKWebView,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// Don't ignore certificate errors
completionHandler(.performDefaultHandling, nil)
}
}
`
✅ Example 5: Secure Permission Handling
Secure Code (Android - Kotlin):
`kotlin
class SecurePermissionManager(private val activity: AppCompatActivity) {
// ✅ GOOD: Request permission with context
fun requestCameraPermission(onGranted: () -> Unit, onDenied: () -> Unit) {
when {
ContextCompat.checkSelfPermission(
activity,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
onGranted()
}
ActivityCompat.shouldShowRequestPermissionRationale(
activity,
Manifest.permission.CAMERA
) -> {
// ✅ GOOD: Show detailed rationale
showPermissionRationale(
title = "Camera Permission Required",
message = "This app needs camera access to scan QR codes for authentication. " +
"Your privacy is protected - images are processed locally and never stored.",
onContinue = {
requestPermission(Manifest.permission.CAMERA, onGranted, onDenied)
},
onCancel = onDenied
)
}
else -> {
requestPermission(Manifest.permission.CAMERA, onGranted, onDenied)
}
}
}
private fun requestPermission(
permission: String,
onGranted: () -> Unit,
onDenied: () -> Unit
) {
val launcher = activity.registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
onGranted()
} else {
onDenied()
}
}
launcher.launch(permission)
}
// ✅ GOOD: Guide to settings if permanently denied
private fun showPermissionRationale(
title: String,
message: String,
onContinue: () -> Unit,
onCancel: () -> Unit
) {
MaterialAlertDialogBuilder(activity)
.setTitle(title)
.setMessage(message)
.setPositiveButton("Continue") { _, _ -> onContinue() }
.setNegativeButton("Cancel") { _, _ -> onCancel() }
.show()
}
}
`
Configuration Comparisons
Android Manifest: Vulnerable vs Secure
| Configuration | ❌ Vulnerable | ✅ Secure |
|--------------|--------------|----------|
| debuggable |
true | false |
| allowBackup |
true (no rules) | true with exclusion rules |
| usesCleartextTraffic |
true | false |
| exported (activities) |
true (unnecessary) | false (unless needed) |
| permissions | All requested upfront | Minimal, runtime requests |
| networkSecurityConfig | Not set | Configured with pinning |
| WebView debugging | Enabled | Disabled in production |
| dataExtractionRules | Not set | Configured (Android 12+) |
iOS Info.plist: Vulnerable vs Secure
| Configuration | ❌ Vulnerable | ✅ Secure |
|--------------|--------------|----------|
| NSAllowsArbitraryLoads |
true | false |
| TLS Version | TLSv1.0 | TLSv1.3 |
| Permission Descriptions | Vague | Specific and clear |
| UIFileSharingEnabled |
true | false |
| Data Protection | Not set | Complete protection |
| Certificate Transparency | Not required | Required |
Build Configuration: Vulnerable vs Secure
| Aspect | ❌ Vulnerable | ✅ Secure |
|--------|--------------|----------|
| ProGuard/R8 | Disabled | Enabled with rules |
| Debugging | Enabled | Disabled in release |
| Logging | Verbose | Removed in production |
| Code Optimization | None | Maximum |
| Resource Shrinking | Disabled | Enabled |
| Signing | Debug key | Release key (secure) |
| Obfuscation | None | Aggressive |
Platform-Specific Examples
Android: Content Provider Security
❌ Vulnerable:
`xml
android:name=".DataProvider"
android:authorities="com.example.provider"
android:exported="true"
android:grantUriPermissions="true" />
`
✅ Secure:
`xml
android:name=".DataProvider"
android:authorities="com.example.provider"
android:exported="false"
android:grantUriPermissions="false"
android:readPermission="com.example.permission.READ_DATA"
android:writePermission="com.example.permission.WRITE_DATA">
android:name="com.example.permission.READ_DATA"
android:protectionLevel="signature" />
android:name="com.example.permission.WRITE_DATA"
android:protectionLevel="signature" />
`
iOS: Keychain Data Protection
❌ Vulnerable:
`swift
// No data protection
UserDefaults.standard.set(sensitiveToken, forKey: "token")
`
✅ Secure:
`swift
// ✅ GOOD: Use Keychain with appropriate protection
func storeToken(_ token: String) -> Bool {
guard let data = token.data(using: .utf8) else { return false }
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "auth_token",
kSecValueData as String: data,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
SecItemDelete(query as CFDictionary)
let status = SecItemAdd(query as CFDictionary, nil)
return status == errSecSuccess
}
`
Real-World Scenarios
Scenario 1: Banking App Configuration
Requirements:
- Maximum security
- No screenshots allowed
- Certificate pinning
- Biometric authentication
- No backups
Implementation (Android):
`xml
android:allowBackup="false"
android:usesCleartextTraffic="false"
android:networkSecurityConfig="@xml/network_security_config">
android:name=".BankingActivity"
android:exported="false"
android:windowSoftInputMode="stateAlwaysHidden">
android:name="android.app.secure_window"
android:value="true" />
`
`java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Prevent screenshots
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE
);
// Require biometric
showBiometricPrompt();
}
`
Scenario 2: Healthcare App (HIPAA Compliance)
Requirements:
- Encrypted storage
- Audit logging
- Data protection
- Minimal permissions
Implementation (iOS):
`swift
// ✅ GOOD: HIPAA-compliant storage
class SecureHealthDataManager {
func storePatientData(_ data: PatientData) throws {
let jsonData = try JSONEncoder().encode(data)
// Store with complete protection
let fileURL = getSecureURL()
try jsonData.write(to: fileURL, options: .completeFileProtection)
// Exclude from backup
var resourceValues = URLResourceValues()
resourceValues.isExcludedFromBackup = true
try fileURL.setResourceValues(resourceValues)
// Audit log
auditLog("Patient data stored securely")
}
}
``
---
Key Takeaway: Security configurations must be environment-specific and regularly audited. What's acceptable in development is often dangerous in production. Part of OWASP Mobile Top 10 - Educational Repository