Complete folder anatomy for all 649 cybersecurity skills + update LICENSE to Mahipal

- Add scripts/agent.py and references/api-reference.md to all remaining skills
- Update all 648 LICENSE files: copyright now reads 'Mahipal'
- Add implementing-security-monitoring-with-datadog (new skill with full anatomy)
- All 649 skills now have: SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
This commit is contained in:
mukul975
2026-03-11 00:22:12 +01:00
parent 27c6414ca5
commit c21af3347e
1244 changed files with 61622 additions and 723 deletions
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2025 Anthropic Agent Skills Contributors
Copyright (c) 2025 Mahipal
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -0,0 +1,106 @@
# API Reference: Insecure Mobile Data Storage Detection
## OWASP Mobile Top 10 — M9: Insecure Data Storage
### Risk Areas
| Storage Type | Platform | Risk |
|-------------|----------|------|
| SharedPreferences | Android | HIGH (plaintext XML) |
| SQLite databases | Both | CRITICAL if unencrypted |
| Keychain (improper) | iOS | MEDIUM |
| External storage | Android | HIGH (world-readable) |
| Plist files | iOS | HIGH (plaintext) |
## Android Data Locations
### App Private Storage
```
/data/data/<package>/shared_prefs/ # SharedPreferences XML
/data/data/<package>/databases/ # SQLite databases
/data/data/<package>/files/ # App files
/data/data/<package>/cache/ # Cache data
```
### External Storage (World-Readable)
```
/sdcard/Android/data/<package>/
```
## ADB Commands
### Pull App Data
```bash
adb pull /data/data/com.target.app/ ./extracted/
```
### List SharedPreferences
```bash
adb shell run-as com.target.app ls /data/data/com.target.app/shared_prefs/
```
### Read SharedPreferences
```bash
adb shell run-as com.target.app cat shared_prefs/credentials.xml
```
## SQLite Analysis
### Python sqlite3
```python
import sqlite3
conn = sqlite3.connect("app.db")
cursor = conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
for table in cursor.fetchall():
cursor.execute(f"PRAGMA table_info({table[0]})")
print(cursor.fetchall())
```
## iOS Data Locations
### App Sandbox
```
/var/mobile/Containers/Data/Application/<UUID>/
Documents/
Library/Preferences/ # NSUserDefaults (plist)
Library/Caches/
tmp/
```
### Keychain
```bash
# Using keychain-dumper
./keychain-dumper -a
```
## Frida Scripts for Data Storage Audit
### Hook SharedPreferences (Android)
```javascript
Java.perform(function() {
var sp = Java.use("android.app.SharedPreferencesImpl$EditorImpl");
sp.putString.implementation = function(key, value) {
console.log("SharedPrefs PUT: " + key + " = " + value);
return this.putString(key, value);
};
});
```
### Hook NSUserDefaults (iOS)
```javascript
var NSUserDefaults = ObjC.classes.NSUserDefaults;
var orig = NSUserDefaults["- setObject:forKey:"];
Interceptor.attach(orig.implementation, {
onEnter: function(args) {
console.log("NSUserDefaults: " + ObjC.Object(args[3]) + " = " + ObjC.Object(args[2]));
}
});
```
## Secure Storage Alternatives
| Platform | Secure Method |
|----------|---------------|
| Android | EncryptedSharedPreferences, Android Keystore |
| iOS | Keychain Services with kSecAttrAccessible |
| Both | SQLCipher for encrypted databases |
@@ -0,0 +1,173 @@
#!/usr/bin/env python3
"""Agent for detecting insecure data storage in mobile applications."""
import argparse
import json
import os
import re
import subprocess
import sys
import sqlite3
from datetime import datetime, timezone
ANDROID_SENSITIVE_PATHS = [
"/data/data/{package}/shared_prefs/",
"/data/data/{package}/databases/",
"/data/data/{package}/files/",
"/data/data/{package}/cache/",
"/sdcard/Android/data/{package}/",
]
SENSITIVE_PATTERNS = {
"api_key": re.compile(r'["\']?api[_-]?key["\']?\s*[:=]\s*["\']([^"\']+)', re.I),
"token": re.compile(r'["\']?(?:access|auth|bearer)[_-]?token["\']?\s*[:=]\s*["\']([^"\']+)', re.I),
"password": re.compile(r'["\']?password["\']?\s*[:=]\s*["\']([^"\']+)', re.I),
"private_key": re.compile(r'-----BEGIN (?:RSA )?PRIVATE KEY-----'),
"base64_cred": re.compile(r'["\']?(?:auth|credential)["\']?\s*[:=]\s*["\']([A-Za-z0-9+/=]{20,})', re.I),
}
def scan_shared_prefs(prefs_dir):
"""Scan Android SharedPreferences XML files for sensitive data."""
findings = []
if not os.path.isdir(prefs_dir):
return findings
for fname in os.listdir(prefs_dir):
if not fname.endswith(".xml"):
continue
fpath = os.path.join(prefs_dir, fname)
try:
with open(fpath, "r", errors="replace") as f:
content = f.read()
for pattern_name, pattern in SENSITIVE_PATTERNS.items():
matches = pattern.findall(content)
if matches:
findings.append({
"file": fpath,
"type": "shared_prefs",
"pattern": pattern_name,
"match_count": len(matches),
"severity": "HIGH",
})
except PermissionError:
pass
return findings
def scan_sqlite_databases(db_dir):
"""Scan SQLite databases for unencrypted sensitive data."""
findings = []
if not os.path.isdir(db_dir):
return findings
for fname in os.listdir(db_dir):
if not fname.endswith((".db", ".sqlite", ".sqlite3")):
continue
fpath = os.path.join(db_dir, fname)
try:
conn = sqlite3.connect(fpath)
cursor = conn.cursor()
cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
tables = cursor.fetchall()
for (table_name,) in tables:
cursor.execute(f"PRAGMA table_info({table_name})")
columns = cursor.fetchall()
sensitive_cols = []
for col in columns:
col_name = col[1].lower()
for sf in ["password", "token", "secret", "key", "ssn", "credit"]:
if sf in col_name:
sensitive_cols.append(col[1])
if sensitive_cols:
cursor.execute(f"SELECT COUNT(*) FROM {table_name}")
row_count = cursor.fetchone()[0]
findings.append({
"file": fpath,
"table": table_name,
"sensitive_columns": sensitive_cols,
"row_count": row_count,
"encrypted": False,
"severity": "CRITICAL",
})
conn.close()
except (sqlite3.Error, PermissionError):
pass
return findings
def scan_file_storage(files_dir):
"""Scan app file storage for sensitive data."""
findings = []
if not os.path.isdir(files_dir):
return findings
for root, _, files in os.walk(files_dir):
for fname in files:
fpath = os.path.join(root, fname)
try:
with open(fpath, "r", errors="replace") as f:
content = f.read(4096)
for pattern_name, pattern in SENSITIVE_PATTERNS.items():
if pattern.search(content):
findings.append({
"file": fpath,
"pattern": pattern_name,
"severity": "HIGH",
})
except (PermissionError, UnicodeDecodeError):
pass
return findings
def adb_pull_app_data(package_name, output_dir):
"""Pull application data via ADB for analysis."""
os.makedirs(output_dir, exist_ok=True)
paths = [p.format(package=package_name) for p in ANDROID_SENSITIVE_PATHS]
results = []
for path in paths:
try:
subprocess.check_output(
["adb", "pull", path, output_dir],
text=True, errors="replace", timeout=15
)
results.append({"path": path, "status": "pulled"})
except subprocess.SubprocessError:
results.append({"path": path, "status": "failed"})
return results
def main():
parser = argparse.ArgumentParser(
description="Detect insecure data storage in mobile apps (authorized testing only)"
)
parser.add_argument("--scan-dir", help="Directory containing app data to scan")
parser.add_argument("--package", help="Android package name for ADB pull")
parser.add_argument("--pull-dir", default="/tmp/mobile_audit")
parser.add_argument("--output", "-o", help="Output JSON report")
args = parser.parse_args()
print("[*] Insecure Mobile Data Storage Detection Agent")
report = {"timestamp": datetime.now(timezone.utc).isoformat(), "findings": []}
scan_dir = args.scan_dir or args.pull_dir
if args.package:
adb_pull_app_data(args.package, args.pull_dir)
if os.path.isdir(scan_dir):
report["findings"].extend(scan_shared_prefs(scan_dir))
report["findings"].extend(scan_sqlite_databases(scan_dir))
report["findings"].extend(scan_file_storage(scan_dir))
critical = sum(1 for f in report["findings"] if f.get("severity") == "CRITICAL")
report["risk_level"] = "CRITICAL" if critical else "HIGH" if report["findings"] else "LOW"
print(f"[*] Findings: {len(report['findings'])} (CRITICAL: {critical})")
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(f"[*] Report saved to {args.output}")
else:
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()