# Firehound Firebase Security Scanner
**Firebase security scanner for iOS apps - Now available on PyPI!**
[](https://badge.fury.io/py/firehound-scanner)
Firehound automatically downloads iOS applications from the App Store, extracts their Firebase configurations, and systematically tests for security misconfigurations.
**Command transformation: 151 → 29 characters (80% reduction!)**
- Before: `VERBOSE=1 python3 firehound.py --search rizz --limit 1 --keychain-passphrase 1 --apple-id-password 'pass' --email user@example.com --timeout 60`
- After: `firehound --search rizz -l 1`
## 🚀 Quick Start
### Installation
```bash
# Install from PyPI
pip install firehound-scanner
# Or with pipx (recommended)
pipx install firehound-scanner
```
### Prerequisites
Install ipatool (required for App Store downloads):
```bash
# macOS
brew install majd/repo/ipatool
# Linux - download from GitHub releases
# https://github.com/majd/ipatool/releases
```
### First-time Setup
```bash
# Interactive login with 2FA
ipatool auth login --email your@email.com
# Set environment variables (one-time)
export FIREHOUND_EMAIL='your@email.com'
export FIREHOUND_KEYCHAIN_PASSPHRASE='your_passphrase'
export FIREHOUND_APPLE_ID_PASSWORD='your_password'
```
### Usage Examples
```bash
# Search and scan apps
firehound --search "banking apps" -l 3
# Scan specific app
firehound --bundle-id com.example.app
# Batch scan from file
firehound --ids-file app-list.txt
# Scan extracted app directory
firehound --directory /path/to/extracted/app
```
## Executive Summary
Firehound is a sophisticated Firebase security scanner that:
1. **Downloads iOS applications** from the App Store using `ipatool`
2. **Extracts Firebase configuration** from iOS app bundles
3. **Systematically tests Firebase services** for misconfigurations
4. **Performs authenticated testing** when possible
5. **Generates detailed vulnerability reports** with evidence
## Core Architecture Overview
```mermaid
graph TD
A["App Store Search"] --> B["IPA Download"]
B --> C["Configuration Extraction"]
C --> D["Firebase Service Discovery"]
D --> E["Unauthenticated Testing"]
E --> F["Authentication Attempt"]
F --> G["Authenticated Testing"]
G --> H["Vulnerability Classification"]
H --> I["Report Generation"]
subgraph Services["Firebase Services Tested"]
J["Realtime Database"]
K["Firestore"]
L["Storage Buckets"]
M["Cloud Functions"]
N["Firebase Hosting"]
end
E --> J
E --> K
E --> L
E --> M
E --> N
G --> J
G --> K
G --> L
```
## Phase 1: iOS Application Acquisition
### App Store Search Process
When using `--search`, Firehound performs intelligent App Store discovery:
```python
# Search execution flow
ipatool_search(term="banking", limit=10) ->
1. Execute: ipatool search --format json "banking" --limit 10
2. Parse JSON response for bundle IDs
3. Fallback to text parsing if JSON fails
4. Return deduplicated bundle ID list
```
**Key Implementation Details:**
- **Multiple command formats**: Tries different argument orders for compatibility
- **Robust parsing**: Handles both JSON and text responses
- **Deduplication**: Ensures unique bundle IDs
- **Error handling**: Graceful fallback mechanisms
### IPA Download & Extraction
For each discovered bundle ID, Firehound performs a complex download process:
#### 1. Authentication Management
```python
# Auto-authentication flow
run_ipatool_download(bundle_id) ->
1. Check existing auth: ipatool auth info
2. Auto-login if needed: ipatool auth login
3. Acquire license: ipatool purchase --bundle-identifier
4. Download by bundle: ipatool download --bundle-identifier
5. Fallback to app ID if bundle fails
```
#### 2. IPA Processing
```python
# Extraction workflow
process_bundle_id() ->
1. Create output directory: /path/bundle_id/
2. Download IPA to: bundle_id.ipa
3. Extract critical files:
- Info.plist (app metadata)
- GoogleService-Info.plist (Firebase config)
4. Convert binary plists to XML
5. Delete IPA file (save space)
6. Proceed to security analysis
```
**Critical Files Extracted:**
- **`Info.plist`**: Contains app metadata, display name, version
- **`GoogleService-Info.plist`**: Firebase project configuration
## Phase 2: Firebase Configuration Analysis
### Configuration Parsing
The heart of Firehound's analysis begins with parsing `GoogleService-Info.plist`:
```python
# Configuration extraction
with open("GoogleService-Info.plist", "rb") as f:
cfg = plistlib.load(f)
# Key configuration values extracted:
{
"PROJECT_ID": "quitvaping-8cfeb", # Firebase project identifier
"DATABASE_URL": "https://quitvaping-8cfeb.firebaseio.com", # Realtime DB URL
"STORAGE_BUCKET": "quitvaping-8cfeb.appspot.com", # Storage bucket
"API_KEY": "AIzaSyC-qKpFx1mL_I--rpzWjdWScPItg-OjhEw", # Client API key
"CLIENT_ID": ["123456789-abc.apps.googleusercontent.com"], # OAuth client
}
```
### Service URL Construction
From this configuration, Firehound constructs service endpoints:
```python
# Service endpoint mapping
realtime_db = f"{DATABASE_URL}/path/.json"
firestore = f"https://firestore.googleapis.com/v1/projects/{PROJECT_ID}/databases/(default)/documents"
storage = f"https://firebasestorage.googleapis.com/v0/b/{STORAGE_BUCKET}/o"
functions = f"https://{region}-{PROJECT_ID}.cloudfunctions.net/{function_name}"
hosting = [f"https://{PROJECT_ID}.web.app/", f"https://{PROJECT_ID}.firebaseapp.com/"]
```
## Phase 3: Systematic Security Testing
### 3.1 Realtime Database Testing (`fuzz_rtdb`)
Firehound performs comprehensive Realtime Database security assessment:
#### Security Rules Exposure Test
```python
# Check if security rules are publicly readable
rules_url = f"{DATABASE_URL}/.rules.json"
response = http_request(rules_url)
if response.status == 200:
return "CRITICAL: Security rules are publicly readable"
```
#### Data Access Pattern Testing
```python
# Test common database paths
rtdb_roots = ["users", "public", "profiles", "data", "messages", "config",
"settings", "dev", "prod", "staging", "test", "logs", "info",
"private", "admin"]
for root in rtdb_roots:
url = f"{DATABASE_URL}/{root}/.json?shallow=true&limitToFirst=1"
response = http_request(url)
if response.status == 200:
discovered_paths.append(root)
```
#### Write Access Testing
```python
# Test for public write access
write_data = {"f3tcher_probe": {"timestamp": time.time(), "probe": True}}
write_url = f"{DATABASE_URL}/probes/.json"
response = http_request(write_url, method="PATCH", body=json.dumps(write_data))
if response.status == 200:
# Clean up test data
http_request(write_url, method="DELETE")
return "CRITICAL: Database is publicly writable"
```
**Vulnerability Classification:**
- **CRITICAL**: Public read AND write access
- **OPEN**: Public read access only
- **CLOSED**: Requires authentication
### 3.2 Firestore Testing (`fuzz_firestore`)
Firestore testing uses the REST API with structured queries:
#### Datastore Mode Detection
```python
# Check if project uses Firestore in Datastore mode
response = http_request(f"{base_url}:runQuery?key={API_KEY}",
method="POST",
body='{"structuredQuery":{"limit":1}}')
if "datastore mode" in response.snippet.lower():
return "NOT_APPLICABLE: Firestore is in Datastore mode"
```
#### Collection Discovery
```python
# Test common collection names
collections = ["users", "profiles", "posts", "messages", "items", "orders",
"products", "carts", "config", "settings", "notifications",
"chats", "groups", "events", "feedback", "logs", "private",
"public", "admin"]
for collection in collections:
query = {"structuredQuery": {"from": [{"collectionId": collection}], "limit": 1}}
response = http_request(f"{base_url}:runQuery?key={API_KEY}",
method="POST",
body=json.dumps(query))
if response.status == 200:
accessible_collections.append(collection)
```
#### Write Access Testing
```python
# Test document creation without authentication
write_collection = "f3tcher_probes"
write_doc_id = f"probe-{int(time.time())}"
write_url = f"{base_url}/{write_collection}/{write_doc_id}?key={API_KEY}"
write_body = {
"fields": {
"probe": {"stringValue": "true"},
"timestamp": {"integerValue": str(int(time.time()))}
}
}
response = http_request(write_url, method="PATCH", body=json.dumps(write_body))
if response.status == 200:
# Clean up
http_request(write_url, method="DELETE")
return "CRITICAL: Public write access allowed"
```
### 3.3 Storage Bucket Testing (`fuzz_storage`)
Storage testing focuses on object listing and upload capabilities:
#### Directory Enumeration
```python
# Test common storage prefixes
prefixes = ["", "users/", "images/", "uploads/", "public/", "private/"]
for prefix in prefixes:
encoded_prefix = urllib.parse.quote(prefix)
url = f"https://firebasestorage.googleapis.com/v0/b/{STORAGE_BUCKET}/o"
url += f"?maxResults=10&delimiter=/&prefix={encoded_prefix}"
response = http_request(url)
if response.status == 200:
accessible_prefixes.append(prefix or "root")
```
#### Upload Testing
```python
# Test file upload without authentication
if accessible_prefixes:
test_filename = f"probes/test-{int(time.time())}.txt"
encoded_name = urllib.parse.quote(test_filename, safe="")
upload_url = f"https://firebasestorage.googleapis.com/v0/b/{STORAGE_BUCKET}/o"
upload_url += f"?uploadType=media&name={encoded_name}"
response = http_request(upload_url,
method="POST",
body="f3tcher test file - safe to delete",
headers={"Content-Type": "text/plain"})
if response.status == 200:
# Parse response to get object name for cleanup
data = json.loads(response.snippet)
object_name = data.get("name", "")
if object_name:
delete_url = f"https://firebasestorage.googleapis.com/v0/b/{STORAGE_BUCKET}/o/{urllib.parse.quote(object_name, safe='')}"
http_request(delete_url, method="DELETE")
return "CRITICAL: Public upload access detected"
```
### 3.4 Cloud Functions Testing (`fuzz_functions`)
Functions testing performs systematic endpoint discovery:
#### Regional Endpoint Testing
```python
# Test all Google Cloud regions
regions = ["us-central1", "us-east1", "us-east4", "us-west1", "us-west2",
"us-west3", "us-west4", "europe-west1", "europe-west2",
"europe-west3", "europe-central2", "asia-northeast1",
"asia-northeast2", "asia-east2", "asia-southeast1",
"asia-southeast2", "australia-southeast1", "southamerica-east1"]
functions = ["api", "status", "v1"] # Common function names
for region in regions:
for function_name in functions:
url = f"https://{region}-{PROJECT_ID}.cloudfunctions.net/{function_name}"
# Test GET request
response = http_request(url)
if response.status == 200:
discovered.append(f"{region}->{function_name}")
elif response.status == 405: # Method not allowed
# Try POST request
post_response = http_request(url, method="POST",
body="{}",
headers={"Content-Type": "application/json"})
if post_response.status == 200:
discovered.append(f"{region}->{function_name} (POST)")
```
### 3.5 Firebase Hosting Testing (`fuzz_hosting`)
Hosting tests check for accessible web applications:
```python
# Test both hosting domains
hosting_urls = [
f"https://{PROJECT_ID}.web.app/",
f"https://{PROJECT_ID}.firebaseapp.com/"
]
for url in hosting_urls:
response = http_request(url)
if response.status == 200:
# Also check for Firebase initialization config
init_response = http_request(url + "__/firebase/init.json")
# This can reveal additional configuration
```
## Phase 4: Authentication & Escalation Testing
### 4.1 Token Acquisition Strategy
Firehound attempts to obtain authentication tokens using two methods:
#### Anonymous Authentication
```python
def get_anonymous_token(api_key):
url = f"https://identitytoolkit.googleapis.com/v1/accounts:signUp?key={api_key}"
payload = {"returnSecureToken": True}
response = http_request(url, method="POST",
body=json.dumps(payload),
headers={"Content-Type": "application/json"})
if response.status == 200:
data = json.loads(response.snippet)
return data.get("idToken") # JWT token for authenticated requests
```
#### Email/Password Authentication
```python
def get_email_token(api_key):
url = f"https://identitytoolkit.googleapis.com/v1/accounts:signUp?key={api_key}"
email = f"probe+{int(time.time())}@example.com" # Unique test email
payload = {
"returnSecureToken": True,
"email": email,
"password": "testpassword123"
}
response = http_request(url, method="POST",
body=json.dumps(payload),
headers={"Content-Type": "application/json"})
if response.status == 200:
data = json.loads(response.snippet)
return data.get("idToken")
```
### 4.2 Authenticated Testing Phase
If authentication succeeds, Firehound re-tests all services with the token:
#### Authenticated Realtime Database Testing
```python
def fuzz_rtdb_auth(cfg, token, wl):
# Test the same paths but with authentication
for root in rtdb_roots:
url = f"{DATABASE_URL}/{root}/.json?shallow=true&limitToFirst=1&auth={token}"
response = http_request(url)
# Determines if "auth != null" rules are too permissive
```
#### Authenticated Firestore Testing
```python
def fuzz_firestore_auth(cfg, token, wl):
headers = {"Authorization": f"Bearer {token}"}
# Re-test collections with Bearer token
# Identifies overly broad "auth != null" rules
```
#### Authenticated Storage Testing
```python
def fuzz_storage_auth(cfg, token):
headers = {"Authorization": f"Bearer {token}"}
# Test storage access with authentication
# Reveals if any authenticated user can access all data
```
## Phase 5: Vulnerability Classification System
### Classification Logic
Firehound uses a sophisticated classification system in the `classify()` function:
```python
def classify(url, status, method):
# Service identification by URL patterns
if "firebasedatabase.app" in url or "firebaseio.com" in url:
if status in (200, 201):
if "_probes" in url:
return "Realtime DB", "CRITICAL: Public write access detected"
else:
return "Realtime DB", "OPEN: Public read access detected"
return "Realtime DB", f"Status: {status}"
if "firestore.googleapis" in url:
if status in (200, 201):
return "Firestore", "OPEN: Collection accessible without auth"
return "Firestore", f"Status: {status}"
if "firebasestorage" in url:
if status in (200, 201):
if "uploadType=media" in url:
return "Storage", "CRITICAL: Public write access detected"
else:
return "Storage", "OPEN: Public list access detected"
return "Storage", f"Status: {status}"
```
### Severity Levels
**CRITICAL Vulnerabilities:**
- Public write access to any service
- Security rules publicly readable
- Admin endpoints accessible
**OPEN Vulnerabilities:**
- Public read access to data
- Directory listing enabled
- Unauthenticated function access
**CLOSED (Secure):**
- Proper authentication required
- Access denied responses (401, 403)
## Phase 6: Evidence Collection & Logging
### Multi-Layer Logging System
Firehound implements comprehensive logging at multiple levels:
#### 1. Terminal Output (User-Friendly)
```python
# Condensed, colorized status messages
vprint("200 | GET | realtime-db | quitvaping-8cfeb | shallow=true", GREY)
vprint("Download complete | OK | app.ipa", GREEN)
vprint("CRITICAL: Public write access detected", RED)
```
#### 2. Detailed File Logging
```python
# Complete operation logging
log_detailed("HTTP_REQUEST: GET https://firestore.googleapis.com/v1/...", "DEBUG")
log_detailed("HTTP_HEADERS: {'User-Agent': 'f3tcher/1.1', ...}", "DEBUG")
log_detailed("HTTP_RESPONSE: 200 in 0.43s, 1024 bytes", "DEBUG")
log_detailed("HTTP_SNIPPET: {\"error\": \"Permission denied\"}", "DEBUG")
```
#### 3. Evidence Collection
```python
# Each HTTP request generates evidence
evidence_entry = {
"url": "https://firestore.googleapis.com/v1/projects/...",
"method": "POST",
"status": 200,
"snippet": "{\"readTime\": \"2025-08-22T15:05:04.036867Z\"}",
"evidence": "Successful access",
"service": "Firestore",
"vuln": "OPEN: Collection accessible without auth"
}
```
## Phase 7: Vulnerability Report Generation
### Report Structure
Firehound generates structured JSON reports with complete vulnerability details:
```json
{
"appName": "Quit Vaping",
"bundleId": "com.jonathankopp.quitvaping",
"vulnerabilities": [
{
"service": "Firestore",
"method": "PATCH",
"url": "https://firestore.googleapis.com/v1/projects/quitvaping-8cfeb/databases/(default)/documents/f3tcher_probes/probe-1755875104?key=AIzaSyC-qKpFx1mL_I--rpzWjdWScPItg-OjhEw",
"details": "OPEN: Collection accessible without auth",
"preview": "{\n \"name\": \"projects/quitvaping-8cfeb/databases/(default)/documents/f3tcher_probes/probe-1755875104\",\n \"fields\": {\n \"timestamp\": {\n \"integerValue\": \"1755875104\"\n },\n \"probe\": {\n \"stringValue\": \"true\"\n }\n },\n \"createTime\": \"2025-08-22T15:05:05.330819Z\",\n \"updateTime\": \"2025-08-22T15:05:05.330819Z\"\n}\n",
"status": 200
}
]
}
```
### Vulnerability Deduplication
```python
def build_vulnerabilities(all_evidence):
vulnerabilities = []
seen = set()
for entry in all_evidence:
# Only include successful access attempts
if entry.status in (200, 201, 204):
key = (entry.service, entry.method, entry.url)
if key not in seen:
seen.add(key)
vulnerabilities.append(entry)
return sorted(vulnerabilities)
```
## Real-World Example: Quit Vaping App Analysis
### Configuration Discovered
From the log analysis, the Quit Vaping app revealed:
```python
{
"PROJECT_ID": "quitvaping-8cfeb",
"DATABASE_URL": "https://quitvaping-8cfeb.firebaseio.com",
"STORAGE_BUCKET": "quitvaping-8cfeb.appspot.com",
"API_KEY": "AIzaSyC-qKpFx1mL_I--rpzWjdWScPItg-OjhEw"
}
```
### Vulnerabilities Found
#### 1. Realtime Database Exposure
- **Public read access** to `/users/` path
- **Public read access** to `/admin/` path containing `{"superusers": true}`
- **No write access** (properly secured)
#### 2. Firestore Misconfigurations
- **Public document creation** in any collection
- **Public query access** via REST API
- **Successful authentication** with email/password signup
#### 3. Storage Bucket Issues
- **Public listing** of all storage prefixes
- **Public file upload** capability
- **9 exposed files** including logos and assets
### Security Impact Assessment
**Critical Issues (Immediate Risk):**
- Storage bucket allows public file uploads → Data pollution, malware hosting
- Firestore allows document creation → Data manipulation, spam injection
**High Issues (Data Exposure):**
- Realtime Database `/admin/` path exposed → Admin user identification
- Realtime Database `/users/` path exposed → User enumeration
- Storage bucket listing enabled → Asset enumeration
**Medium Issues (Information Disclosure):**
- Email/password authentication enabled → Account creation possible
- Multiple service endpoints discoverable → Attack surface mapping
## Advanced Technical Details
### HTTP Request Flow
Every HTTP request follows this pattern:
```python
# Request lifecycle
1. Log request details (URL, method, headers, body)
2. Execute request with timeout and retries
3. Log response (status, duration, size, snippet)
4. Classify service and vulnerability
5. Store evidence for reporting
6. Display condensed terminal output
```
### Error Handling Strategy
```python
# Retry logic for network requests
for attempt in range(MAX_RETRIES + 1):
try:
response = urllib.request.urlopen(request, timeout=HTTP_TIMEOUT)
# Success path
except urllib.error.HTTPError as e:
# HTTP error (400, 401, 403, 404, etc.) - still valuable data
return process_http_error(e)
except Exception as e:
# Network/timeout error - retry with exponential backoff
if attempt < MAX_RETRIES:
time.sleep(2 ** attempt) # 1s, 2s, 4s delays
continue
return failure_response(e)
```
### Security Considerations
#### Responsible Testing
- **Read-only probes** when possible
- **Immediate cleanup** of test data
- **Non-destructive testing** methods
- **Minimal data footprint**
#### Authentication Safety
- **Temporary accounts** for testing (`probe+timestamp@example.com`)
- **No persistent authentication**
- **Token cleanup** after testing
- **Masked logging** of sensitive data
## Performance Characteristics
### Network Efficiency
- **Concurrent testing** of different services
- **Intelligent retry logic** with exponential backoff
- **Request deduplication** to avoid redundant tests
- **Timeout management** to prevent hanging
### Resource Management
- **IPA cleanup** after extraction (saves disk space)
- **Optional plist retention** via `KEEP_PLISTS` environment variable
- **Automatic directory cleanup** for apps with no findings
- **Memory-efficient** streaming of large responses
## Integration Points
### Command Line Interface
```bash
# Multiple input methods supported
python3 test.py --search "banking" # Search App Store
python3 test.py --ids-file bundles.txt # Batch processing
python3 test.py --bundle-id com.example.app # Single app
python3 test.py --directory /path/to/extracted/app # Pre-extracted app
```
### Environment Configuration
```bash
# Performance tuning
export VERBOSE=1 # Enable detailed terminal output
export RESCAN=1 # Force re-analysis of existing reports
export KEEP_PLISTS=1 # Retain configuration files
export NO_COLOR=1 # Disable colored output
```
### Output Structure
```
/output/directory/
├── logs/
│ └── firehound_scan_20250822_150448.log # Detailed execution log
├── com.example.app/
│ ├── Info.plist # App metadata
│ ├── GoogleService-Info.plist # Firebase config
│ └── App Name__com.example.app_audit.json # Vulnerability report
└── scan_index.json # Scan summary
```
## Conclusion
Firehound represents a sophisticated approach to automated Firebase security testing. Its strength lies in:
1. **Comprehensive Coverage**: Tests all major Firebase services systematically
2. **Intelligent Discovery**: Uses real iOS app configurations for realistic testing
3. **Evidence-Based Reporting**: Provides complete proof of vulnerabilities
4. **Responsible Testing**: Minimizes impact while maximizing coverage
5. **Detailed Logging**: Enables deep analysis and debugging
The tool's architecture allows security researchers to quickly identify Firebase misconfigurations at scale while maintaining detailed audit trails for compliance and further analysis.
Understanding this architecture enables users to:
- **Customize testing strategies** for specific environments
- **Interpret results accurately** with full context
- **Extend functionality** for additional security checks
- **Integrate with other tools** in security workflows
This deep understanding transforms Firehound from a black box tool into a transparent, extensible security testing platform.
Raw data
{
"_id": null,
"home_page": null,
"name": "firehound-scanner",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "firebase, security, scanner, ios, mobile, pentesting",
"author": null,
"author_email": "Harry Johnston <harry@harryjohnston.com.au>",
"download_url": "https://files.pythonhosted.org/packages/5f/a0/a2f6558817570b55a4f22284fb9237de5740790c92c5486190b57a2ad2af/firehound_scanner-1.0.5.tar.gz",
"platform": null,
"description": "# Firehound Firebase Security Scanner\n\n**Firebase security scanner for iOS apps - Now available on PyPI!**\n\n[](https://badge.fury.io/py/firehound-scanner)\n\nFirehound automatically downloads iOS applications from the App Store, extracts their Firebase configurations, and systematically tests for security misconfigurations.\n\n**Command transformation: 151 \u2192 29 characters (80% reduction!)**\n- Before: `VERBOSE=1 python3 firehound.py --search rizz --limit 1 --keychain-passphrase 1 --apple-id-password 'pass' --email user@example.com --timeout 60`\n- After: `firehound --search rizz -l 1`\n\n## \ud83d\ude80 Quick Start\n\n### Installation\n```bash\n# Install from PyPI \npip install firehound-scanner\n\n# Or with pipx (recommended)\npipx install firehound-scanner\n```\n\n### Prerequisites\nInstall ipatool (required for App Store downloads):\n```bash\n# macOS\nbrew install majd/repo/ipatool\n\n# Linux - download from GitHub releases\n# https://github.com/majd/ipatool/releases\n```\n\n### First-time Setup\n```bash\n# Interactive login with 2FA\nipatool auth login --email your@email.com\n\n# Set environment variables (one-time)\nexport FIREHOUND_EMAIL='your@email.com'\nexport FIREHOUND_KEYCHAIN_PASSPHRASE='your_passphrase'\nexport FIREHOUND_APPLE_ID_PASSWORD='your_password'\n```\n\n### Usage Examples\n```bash\n# Search and scan apps\nfirehound --search \"banking apps\" -l 3\n\n# Scan specific app\nfirehound --bundle-id com.example.app\n\n# Batch scan from file \nfirehound --ids-file app-list.txt\n\n# Scan extracted app directory\nfirehound --directory /path/to/extracted/app\n```\n\n## Executive Summary\n\nFirehound is a sophisticated Firebase security scanner that:\n1. **Downloads iOS applications** from the App Store using `ipatool`\n2. **Extracts Firebase configuration** from iOS app bundles\n3. **Systematically tests Firebase services** for misconfigurations\n4. **Performs authenticated testing** when possible\n5. **Generates detailed vulnerability reports** with evidence\n\n## Core Architecture Overview\n\n```mermaid\ngraph TD\n A[\"App Store Search\"] --> B[\"IPA Download\"]\n B --> C[\"Configuration Extraction\"]\n C --> D[\"Firebase Service Discovery\"]\n D --> E[\"Unauthenticated Testing\"]\n E --> F[\"Authentication Attempt\"]\n F --> G[\"Authenticated Testing\"]\n G --> H[\"Vulnerability Classification\"]\n H --> I[\"Report Generation\"]\n \n subgraph Services[\"Firebase Services Tested\"]\n J[\"Realtime Database\"]\n K[\"Firestore\"]\n L[\"Storage Buckets\"]\n M[\"Cloud Functions\"]\n N[\"Firebase Hosting\"]\n end\n \n E --> J\n E --> K\n E --> L\n E --> M\n E --> N\n \n G --> J\n G --> K\n G --> L\n```\n\n## Phase 1: iOS Application Acquisition\n\n### App Store Search Process\n\nWhen using `--search`, Firehound performs intelligent App Store discovery:\n\n```python\n# Search execution flow\nipatool_search(term=\"banking\", limit=10) ->\n 1. Execute: ipatool search --format json \"banking\" --limit 10\n 2. Parse JSON response for bundle IDs\n 3. Fallback to text parsing if JSON fails\n 4. Return deduplicated bundle ID list\n```\n\n**Key Implementation Details:**\n- **Multiple command formats**: Tries different argument orders for compatibility\n- **Robust parsing**: Handles both JSON and text responses\n- **Deduplication**: Ensures unique bundle IDs\n- **Error handling**: Graceful fallback mechanisms\n\n### IPA Download & Extraction\n\nFor each discovered bundle ID, Firehound performs a complex download process:\n\n#### 1. Authentication Management\n```python\n# Auto-authentication flow\nrun_ipatool_download(bundle_id) ->\n 1. Check existing auth: ipatool auth info\n 2. Auto-login if needed: ipatool auth login\n 3. Acquire license: ipatool purchase --bundle-identifier\n 4. Download by bundle: ipatool download --bundle-identifier\n 5. Fallback to app ID if bundle fails\n```\n\n#### 2. IPA Processing\n```python\n# Extraction workflow\nprocess_bundle_id() ->\n 1. Create output directory: /path/bundle_id/\n 2. Download IPA to: bundle_id.ipa\n 3. Extract critical files:\n - Info.plist (app metadata)\n - GoogleService-Info.plist (Firebase config)\n 4. Convert binary plists to XML\n 5. Delete IPA file (save space)\n 6. Proceed to security analysis\n```\n\n**Critical Files Extracted:**\n- **`Info.plist`**: Contains app metadata, display name, version\n- **`GoogleService-Info.plist`**: Firebase project configuration\n\n## Phase 2: Firebase Configuration Analysis\n\n### Configuration Parsing\n\nThe heart of Firehound's analysis begins with parsing `GoogleService-Info.plist`:\n\n```python\n# Configuration extraction\nwith open(\"GoogleService-Info.plist\", \"rb\") as f:\n cfg = plistlib.load(f)\n\n# Key configuration values extracted:\n{\n \"PROJECT_ID\": \"quitvaping-8cfeb\", # Firebase project identifier\n \"DATABASE_URL\": \"https://quitvaping-8cfeb.firebaseio.com\", # Realtime DB URL\n \"STORAGE_BUCKET\": \"quitvaping-8cfeb.appspot.com\", # Storage bucket\n \"API_KEY\": \"AIzaSyC-qKpFx1mL_I--rpzWjdWScPItg-OjhEw\", # Client API key\n \"CLIENT_ID\": [\"123456789-abc.apps.googleusercontent.com\"], # OAuth client\n}\n```\n\n### Service URL Construction\n\nFrom this configuration, Firehound constructs service endpoints:\n\n```python\n# Service endpoint mapping\nrealtime_db = f\"{DATABASE_URL}/path/.json\"\nfirestore = f\"https://firestore.googleapis.com/v1/projects/{PROJECT_ID}/databases/(default)/documents\"\nstorage = f\"https://firebasestorage.googleapis.com/v0/b/{STORAGE_BUCKET}/o\"\nfunctions = f\"https://{region}-{PROJECT_ID}.cloudfunctions.net/{function_name}\"\nhosting = [f\"https://{PROJECT_ID}.web.app/\", f\"https://{PROJECT_ID}.firebaseapp.com/\"]\n```\n\n## Phase 3: Systematic Security Testing\n\n### 3.1 Realtime Database Testing (`fuzz_rtdb`)\n\nFirehound performs comprehensive Realtime Database security assessment:\n\n#### Security Rules Exposure Test\n```python\n# Check if security rules are publicly readable\nrules_url = f\"{DATABASE_URL}/.rules.json\"\nresponse = http_request(rules_url)\nif response.status == 200:\n return \"CRITICAL: Security rules are publicly readable\"\n```\n\n#### Data Access Pattern Testing\n```python\n# Test common database paths\nrtdb_roots = [\"users\", \"public\", \"profiles\", \"data\", \"messages\", \"config\", \n \"settings\", \"dev\", \"prod\", \"staging\", \"test\", \"logs\", \"info\", \n \"private\", \"admin\"]\n\nfor root in rtdb_roots:\n url = f\"{DATABASE_URL}/{root}/.json?shallow=true&limitToFirst=1\"\n response = http_request(url)\n if response.status == 200:\n discovered_paths.append(root)\n```\n\n#### Write Access Testing\n```python\n# Test for public write access\nwrite_data = {\"f3tcher_probe\": {\"timestamp\": time.time(), \"probe\": True}}\nwrite_url = f\"{DATABASE_URL}/probes/.json\"\nresponse = http_request(write_url, method=\"PATCH\", body=json.dumps(write_data))\n\nif response.status == 200:\n # Clean up test data\n http_request(write_url, method=\"DELETE\")\n return \"CRITICAL: Database is publicly writable\"\n```\n\n**Vulnerability Classification:**\n- **CRITICAL**: Public read AND write access\n- **OPEN**: Public read access only\n- **CLOSED**: Requires authentication\n\n### 3.2 Firestore Testing (`fuzz_firestore`)\n\nFirestore testing uses the REST API with structured queries:\n\n#### Datastore Mode Detection\n```python\n# Check if project uses Firestore in Datastore mode\nresponse = http_request(f\"{base_url}:runQuery?key={API_KEY}\", \n method=\"POST\", \n body='{\"structuredQuery\":{\"limit\":1}}')\n\nif \"datastore mode\" in response.snippet.lower():\n return \"NOT_APPLICABLE: Firestore is in Datastore mode\"\n```\n\n#### Collection Discovery\n```python\n# Test common collection names\ncollections = [\"users\", \"profiles\", \"posts\", \"messages\", \"items\", \"orders\", \n \"products\", \"carts\", \"config\", \"settings\", \"notifications\", \n \"chats\", \"groups\", \"events\", \"feedback\", \"logs\", \"private\", \n \"public\", \"admin\"]\n\nfor collection in collections:\n query = {\"structuredQuery\": {\"from\": [{\"collectionId\": collection}], \"limit\": 1}}\n response = http_request(f\"{base_url}:runQuery?key={API_KEY}\", \n method=\"POST\", \n body=json.dumps(query))\n if response.status == 200:\n accessible_collections.append(collection)\n```\n\n#### Write Access Testing\n```python\n# Test document creation without authentication\nwrite_collection = \"f3tcher_probes\"\nwrite_doc_id = f\"probe-{int(time.time())}\"\nwrite_url = f\"{base_url}/{write_collection}/{write_doc_id}?key={API_KEY}\"\nwrite_body = {\n \"fields\": {\n \"probe\": {\"stringValue\": \"true\"}, \n \"timestamp\": {\"integerValue\": str(int(time.time()))}\n }\n}\n\nresponse = http_request(write_url, method=\"PATCH\", body=json.dumps(write_body))\nif response.status == 200:\n # Clean up\n http_request(write_url, method=\"DELETE\")\n return \"CRITICAL: Public write access allowed\"\n```\n\n### 3.3 Storage Bucket Testing (`fuzz_storage`)\n\nStorage testing focuses on object listing and upload capabilities:\n\n#### Directory Enumeration\n```python\n# Test common storage prefixes\nprefixes = [\"\", \"users/\", \"images/\", \"uploads/\", \"public/\", \"private/\"]\n\nfor prefix in prefixes:\n encoded_prefix = urllib.parse.quote(prefix)\n url = f\"https://firebasestorage.googleapis.com/v0/b/{STORAGE_BUCKET}/o\"\n url += f\"?maxResults=10&delimiter=/&prefix={encoded_prefix}\"\n \n response = http_request(url)\n if response.status == 200:\n accessible_prefixes.append(prefix or \"root\")\n```\n\n#### Upload Testing\n```python\n# Test file upload without authentication\nif accessible_prefixes:\n test_filename = f\"probes/test-{int(time.time())}.txt\"\n encoded_name = urllib.parse.quote(test_filename, safe=\"\")\n upload_url = f\"https://firebasestorage.googleapis.com/v0/b/{STORAGE_BUCKET}/o\"\n upload_url += f\"?uploadType=media&name={encoded_name}\"\n \n response = http_request(upload_url, \n method=\"POST\", \n body=\"f3tcher test file - safe to delete\",\n headers={\"Content-Type\": \"text/plain\"})\n \n if response.status == 200:\n # Parse response to get object name for cleanup\n data = json.loads(response.snippet)\n object_name = data.get(\"name\", \"\")\n if object_name:\n delete_url = f\"https://firebasestorage.googleapis.com/v0/b/{STORAGE_BUCKET}/o/{urllib.parse.quote(object_name, safe='')}\"\n http_request(delete_url, method=\"DELETE\")\n \n return \"CRITICAL: Public upload access detected\"\n```\n\n### 3.4 Cloud Functions Testing (`fuzz_functions`)\n\nFunctions testing performs systematic endpoint discovery:\n\n#### Regional Endpoint Testing\n```python\n# Test all Google Cloud regions\nregions = [\"us-central1\", \"us-east1\", \"us-east4\", \"us-west1\", \"us-west2\", \n \"us-west3\", \"us-west4\", \"europe-west1\", \"europe-west2\", \n \"europe-west3\", \"europe-central2\", \"asia-northeast1\", \n \"asia-northeast2\", \"asia-east2\", \"asia-southeast1\", \n \"asia-southeast2\", \"australia-southeast1\", \"southamerica-east1\"]\n\nfunctions = [\"api\", \"status\", \"v1\"] # Common function names\n\nfor region in regions:\n for function_name in functions:\n url = f\"https://{region}-{PROJECT_ID}.cloudfunctions.net/{function_name}\"\n \n # Test GET request\n response = http_request(url)\n if response.status == 200:\n discovered.append(f\"{region}->{function_name}\")\n elif response.status == 405: # Method not allowed\n # Try POST request\n post_response = http_request(url, method=\"POST\", \n body=\"{}\", \n headers={\"Content-Type\": \"application/json\"})\n if post_response.status == 200:\n discovered.append(f\"{region}->{function_name} (POST)\")\n```\n\n### 3.5 Firebase Hosting Testing (`fuzz_hosting`)\n\nHosting tests check for accessible web applications:\n\n```python\n# Test both hosting domains\nhosting_urls = [\n f\"https://{PROJECT_ID}.web.app/\",\n f\"https://{PROJECT_ID}.firebaseapp.com/\"\n]\n\nfor url in hosting_urls:\n response = http_request(url)\n if response.status == 200:\n # Also check for Firebase initialization config\n init_response = http_request(url + \"__/firebase/init.json\")\n # This can reveal additional configuration\n```\n\n## Phase 4: Authentication & Escalation Testing\n\n### 4.1 Token Acquisition Strategy\n\nFirehound attempts to obtain authentication tokens using two methods:\n\n#### Anonymous Authentication\n```python\ndef get_anonymous_token(api_key):\n url = f\"https://identitytoolkit.googleapis.com/v1/accounts:signUp?key={api_key}\"\n payload = {\"returnSecureToken\": True}\n \n response = http_request(url, method=\"POST\", \n body=json.dumps(payload),\n headers={\"Content-Type\": \"application/json\"})\n \n if response.status == 200:\n data = json.loads(response.snippet)\n return data.get(\"idToken\") # JWT token for authenticated requests\n```\n\n#### Email/Password Authentication\n```python\ndef get_email_token(api_key):\n url = f\"https://identitytoolkit.googleapis.com/v1/accounts:signUp?key={api_key}\"\n email = f\"probe+{int(time.time())}@example.com\" # Unique test email\n payload = {\n \"returnSecureToken\": True,\n \"email\": email,\n \"password\": \"testpassword123\"\n }\n \n response = http_request(url, method=\"POST\", \n body=json.dumps(payload),\n headers={\"Content-Type\": \"application/json\"})\n \n if response.status == 200:\n data = json.loads(response.snippet)\n return data.get(\"idToken\")\n```\n\n### 4.2 Authenticated Testing Phase\n\nIf authentication succeeds, Firehound re-tests all services with the token:\n\n#### Authenticated Realtime Database Testing\n```python\ndef fuzz_rtdb_auth(cfg, token, wl):\n # Test the same paths but with authentication\n for root in rtdb_roots:\n url = f\"{DATABASE_URL}/{root}/.json?shallow=true&limitToFirst=1&auth={token}\"\n response = http_request(url)\n # Determines if \"auth != null\" rules are too permissive\n```\n\n#### Authenticated Firestore Testing\n```python\ndef fuzz_firestore_auth(cfg, token, wl):\n headers = {\"Authorization\": f\"Bearer {token}\"}\n # Re-test collections with Bearer token\n # Identifies overly broad \"auth != null\" rules\n```\n\n#### Authenticated Storage Testing\n```python\ndef fuzz_storage_auth(cfg, token):\n headers = {\"Authorization\": f\"Bearer {token}\"}\n # Test storage access with authentication\n # Reveals if any authenticated user can access all data\n```\n\n## Phase 5: Vulnerability Classification System\n\n### Classification Logic\n\nFirehound uses a sophisticated classification system in the `classify()` function:\n\n```python\ndef classify(url, status, method):\n # Service identification by URL patterns\n if \"firebasedatabase.app\" in url or \"firebaseio.com\" in url:\n if status in (200, 201):\n if \"_probes\" in url:\n return \"Realtime DB\", \"CRITICAL: Public write access detected\"\n else:\n return \"Realtime DB\", \"OPEN: Public read access detected\"\n return \"Realtime DB\", f\"Status: {status}\"\n \n if \"firestore.googleapis\" in url:\n if status in (200, 201):\n return \"Firestore\", \"OPEN: Collection accessible without auth\"\n return \"Firestore\", f\"Status: {status}\"\n \n if \"firebasestorage\" in url:\n if status in (200, 201):\n if \"uploadType=media\" in url:\n return \"Storage\", \"CRITICAL: Public write access detected\"\n else:\n return \"Storage\", \"OPEN: Public list access detected\"\n return \"Storage\", f\"Status: {status}\"\n```\n\n### Severity Levels\n\n**CRITICAL Vulnerabilities:**\n- Public write access to any service\n- Security rules publicly readable\n- Admin endpoints accessible\n\n**OPEN Vulnerabilities:**\n- Public read access to data\n- Directory listing enabled\n- Unauthenticated function access\n\n**CLOSED (Secure):**\n- Proper authentication required\n- Access denied responses (401, 403)\n\n## Phase 6: Evidence Collection & Logging\n\n### Multi-Layer Logging System\n\nFirehound implements comprehensive logging at multiple levels:\n\n#### 1. Terminal Output (User-Friendly)\n```python\n# Condensed, colorized status messages\nvprint(\"200 | GET | realtime-db | quitvaping-8cfeb | shallow=true\", GREY)\nvprint(\"Download complete | OK | app.ipa\", GREEN)\nvprint(\"CRITICAL: Public write access detected\", RED)\n```\n\n#### 2. Detailed File Logging\n```python\n# Complete operation logging\nlog_detailed(\"HTTP_REQUEST: GET https://firestore.googleapis.com/v1/...\", \"DEBUG\")\nlog_detailed(\"HTTP_HEADERS: {'User-Agent': 'f3tcher/1.1', ...}\", \"DEBUG\")\nlog_detailed(\"HTTP_RESPONSE: 200 in 0.43s, 1024 bytes\", \"DEBUG\")\nlog_detailed(\"HTTP_SNIPPET: {\\\"error\\\": \\\"Permission denied\\\"}\", \"DEBUG\")\n```\n\n#### 3. Evidence Collection\n```python\n# Each HTTP request generates evidence\nevidence_entry = {\n \"url\": \"https://firestore.googleapis.com/v1/projects/...\",\n \"method\": \"POST\",\n \"status\": 200,\n \"snippet\": \"{\\\"readTime\\\": \\\"2025-08-22T15:05:04.036867Z\\\"}\",\n \"evidence\": \"Successful access\",\n \"service\": \"Firestore\",\n \"vuln\": \"OPEN: Collection accessible without auth\"\n}\n```\n\n## Phase 7: Vulnerability Report Generation\n\n### Report Structure\n\nFirehound generates structured JSON reports with complete vulnerability details:\n\n```json\n{\n \"appName\": \"Quit Vaping\",\n \"bundleId\": \"com.jonathankopp.quitvaping\",\n \"vulnerabilities\": [\n {\n \"service\": \"Firestore\",\n \"method\": \"PATCH\",\n \"url\": \"https://firestore.googleapis.com/v1/projects/quitvaping-8cfeb/databases/(default)/documents/f3tcher_probes/probe-1755875104?key=AIzaSyC-qKpFx1mL_I--rpzWjdWScPItg-OjhEw\",\n \"details\": \"OPEN: Collection accessible without auth\",\n \"preview\": \"{\\n \\\"name\\\": \\\"projects/quitvaping-8cfeb/databases/(default)/documents/f3tcher_probes/probe-1755875104\\\",\\n \\\"fields\\\": {\\n \\\"timestamp\\\": {\\n \\\"integerValue\\\": \\\"1755875104\\\"\\n },\\n \\\"probe\\\": {\\n \\\"stringValue\\\": \\\"true\\\"\\n }\\n },\\n \\\"createTime\\\": \\\"2025-08-22T15:05:05.330819Z\\\",\\n \\\"updateTime\\\": \\\"2025-08-22T15:05:05.330819Z\\\"\\n}\\n\",\n \"status\": 200\n }\n ]\n}\n```\n\n### Vulnerability Deduplication\n\n```python\ndef build_vulnerabilities(all_evidence):\n vulnerabilities = []\n seen = set()\n \n for entry in all_evidence:\n # Only include successful access attempts\n if entry.status in (200, 201, 204):\n key = (entry.service, entry.method, entry.url)\n if key not in seen:\n seen.add(key)\n vulnerabilities.append(entry)\n \n return sorted(vulnerabilities)\n```\n\n## Real-World Example: Quit Vaping App Analysis\n\n### Configuration Discovered\nFrom the log analysis, the Quit Vaping app revealed:\n\n```python\n{\n \"PROJECT_ID\": \"quitvaping-8cfeb\",\n \"DATABASE_URL\": \"https://quitvaping-8cfeb.firebaseio.com\",\n \"STORAGE_BUCKET\": \"quitvaping-8cfeb.appspot.com\",\n \"API_KEY\": \"AIzaSyC-qKpFx1mL_I--rpzWjdWScPItg-OjhEw\"\n}\n```\n\n### Vulnerabilities Found\n\n#### 1. Realtime Database Exposure\n- **Public read access** to `/users/` path\n- **Public read access** to `/admin/` path containing `{\"superusers\": true}`\n- **No write access** (properly secured)\n\n#### 2. Firestore Misconfigurations\n- **Public document creation** in any collection\n- **Public query access** via REST API\n- **Successful authentication** with email/password signup\n\n#### 3. Storage Bucket Issues\n- **Public listing** of all storage prefixes\n- **Public file upload** capability\n- **9 exposed files** including logos and assets\n\n### Security Impact Assessment\n\n**Critical Issues (Immediate Risk):**\n- Storage bucket allows public file uploads \u2192 Data pollution, malware hosting\n- Firestore allows document creation \u2192 Data manipulation, spam injection\n\n**High Issues (Data Exposure):**\n- Realtime Database `/admin/` path exposed \u2192 Admin user identification\n- Realtime Database `/users/` path exposed \u2192 User enumeration\n- Storage bucket listing enabled \u2192 Asset enumeration\n\n**Medium Issues (Information Disclosure):**\n- Email/password authentication enabled \u2192 Account creation possible\n- Multiple service endpoints discoverable \u2192 Attack surface mapping\n\n## Advanced Technical Details\n\n### HTTP Request Flow\n\nEvery HTTP request follows this pattern:\n\n```python\n# Request lifecycle\n1. Log request details (URL, method, headers, body)\n2. Execute request with timeout and retries\n3. Log response (status, duration, size, snippet)\n4. Classify service and vulnerability\n5. Store evidence for reporting\n6. Display condensed terminal output\n```\n\n### Error Handling Strategy\n\n```python\n# Retry logic for network requests\nfor attempt in range(MAX_RETRIES + 1):\n try:\n response = urllib.request.urlopen(request, timeout=HTTP_TIMEOUT)\n # Success path\n except urllib.error.HTTPError as e:\n # HTTP error (400, 401, 403, 404, etc.) - still valuable data\n return process_http_error(e)\n except Exception as e:\n # Network/timeout error - retry with exponential backoff\n if attempt < MAX_RETRIES:\n time.sleep(2 ** attempt) # 1s, 2s, 4s delays\n continue\n return failure_response(e)\n```\n\n### Security Considerations\n\n#### Responsible Testing\n- **Read-only probes** when possible\n- **Immediate cleanup** of test data\n- **Non-destructive testing** methods\n- **Minimal data footprint**\n\n#### Authentication Safety\n- **Temporary accounts** for testing (`probe+timestamp@example.com`)\n- **No persistent authentication**\n- **Token cleanup** after testing\n- **Masked logging** of sensitive data\n\n## Performance Characteristics\n\n### Network Efficiency\n- **Concurrent testing** of different services\n- **Intelligent retry logic** with exponential backoff\n- **Request deduplication** to avoid redundant tests\n- **Timeout management** to prevent hanging\n\n### Resource Management\n- **IPA cleanup** after extraction (saves disk space)\n- **Optional plist retention** via `KEEP_PLISTS` environment variable\n- **Automatic directory cleanup** for apps with no findings\n- **Memory-efficient** streaming of large responses\n\n## Integration Points\n\n### Command Line Interface\n```bash\n# Multiple input methods supported\npython3 test.py --search \"banking\" # Search App Store\npython3 test.py --ids-file bundles.txt # Batch processing\npython3 test.py --bundle-id com.example.app # Single app\npython3 test.py --directory /path/to/extracted/app # Pre-extracted app\n```\n\n### Environment Configuration\n```bash\n# Performance tuning\nexport VERBOSE=1 # Enable detailed terminal output\nexport RESCAN=1 # Force re-analysis of existing reports\nexport KEEP_PLISTS=1 # Retain configuration files\nexport NO_COLOR=1 # Disable colored output\n```\n\n### Output Structure\n```\n/output/directory/\n\u251c\u2500\u2500 logs/\n\u2502 \u2514\u2500\u2500 firehound_scan_20250822_150448.log # Detailed execution log\n\u251c\u2500\u2500 com.example.app/\n\u2502 \u251c\u2500\u2500 Info.plist # App metadata\n\u2502 \u251c\u2500\u2500 GoogleService-Info.plist # Firebase config\n\u2502 \u2514\u2500\u2500 App Name__com.example.app_audit.json # Vulnerability report\n\u2514\u2500\u2500 scan_index.json # Scan summary\n```\n\n## Conclusion\n\nFirehound represents a sophisticated approach to automated Firebase security testing. Its strength lies in:\n\n1. **Comprehensive Coverage**: Tests all major Firebase services systematically\n2. **Intelligent Discovery**: Uses real iOS app configurations for realistic testing\n3. **Evidence-Based Reporting**: Provides complete proof of vulnerabilities\n4. **Responsible Testing**: Minimizes impact while maximizing coverage\n5. **Detailed Logging**: Enables deep analysis and debugging\n\nThe tool's architecture allows security researchers to quickly identify Firebase misconfigurations at scale while maintaining detailed audit trails for compliance and further analysis.\n\nUnderstanding this architecture enables users to:\n- **Customize testing strategies** for specific environments\n- **Interpret results accurately** with full context\n- **Extend functionality** for additional security checks\n- **Integrate with other tools** in security workflows\n\nThis deep understanding transforms Firehound from a black box tool into a transparent, extensible security testing platform.\n",
"bugtrack_url": null,
"license": null,
"summary": "Firebase security scanner for iOS apps",
"version": "1.0.5",
"project_urls": {
"Bug Reports": "https://github.com/covertlabsaus/obscurekitten/issues",
"Documentation": "https://github.com/covertlabsaus/obscurekitten/blob/main/README.md",
"Homepage": "https://github.com/covertlabsaus/obscurekitten",
"Source": "https://github.com/covertlabsaus/obscurekitten"
},
"split_keywords": [
"firebase",
" security",
" scanner",
" ios",
" mobile",
" pentesting"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "0dc64bcb902180eb1e673176e34b5cca22ebdea0574b3e23228ce3aeb6e76562",
"md5": "251254c5705b36d0dbe0d67d94c2a3c7",
"sha256": "0c58f879dfd97b7290493f5ee5bb24bd9de19be909cf3af1c873a51cd54a36c3"
},
"downloads": -1,
"filename": "firehound_scanner-1.0.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "251254c5705b36d0dbe0d67d94c2a3c7",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 31726,
"upload_time": "2025-08-22T17:51:21",
"upload_time_iso_8601": "2025-08-22T17:51:21.488662Z",
"url": "https://files.pythonhosted.org/packages/0d/c6/4bcb902180eb1e673176e34b5cca22ebdea0574b3e23228ce3aeb6e76562/firehound_scanner-1.0.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "5fa0a2f6558817570b55a4f22284fb9237de5740790c92c5486190b57a2ad2af",
"md5": "08d8bed0473fd0e24a85e03926e68f6b",
"sha256": "088b2678041e68c96e13fe0eb67cd15a5f3fa2b6d0adbfd107473de9fe614ead"
},
"downloads": -1,
"filename": "firehound_scanner-1.0.5.tar.gz",
"has_sig": false,
"md5_digest": "08d8bed0473fd0e24a85e03926e68f6b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 37364,
"upload_time": "2025-08-22T17:51:22",
"upload_time_iso_8601": "2025-08-22T17:51:22.765834Z",
"url": "https://files.pythonhosted.org/packages/5f/a0/a2f6558817570b55a4f22284fb9237de5740790c92c5486190b57a2ad2af/firehound_scanner-1.0.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-22 17:51:22",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "covertlabsaus",
"github_project": "obscurekitten",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "firehound-scanner"
}