Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 34 additions & 2 deletions .github/scripts/validate-workers.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,40 @@ for worker in $WORKERS; do
continue
fi

# Check required files
REQUIRED_FILES=("Dockerfile" "requirements.txt" "worker.py")
# Check Dockerfile (single file or multi-platform pattern)
if [ -f "$WORKER_DIR/Dockerfile" ]; then
# Single Dockerfile
if ! git ls-files --error-unmatch "$WORKER_DIR/Dockerfile" &> /dev/null; then
echo -e "${RED} ❌ File not tracked by git: $WORKER_DIR/Dockerfile${NC}"
echo -e "${YELLOW} Check .gitignore patterns!${NC}"
ERRORS=$((ERRORS + 1))
else
echo -e "${GREEN} βœ“ Dockerfile (tracked)${NC}"
fi
elif compgen -G "$WORKER_DIR/Dockerfile.*" > /dev/null; then
# Multi-platform Dockerfiles (e.g., Dockerfile.amd64, Dockerfile.arm64)
PLATFORM_DOCKERFILES=$(ls "$WORKER_DIR"/Dockerfile.* 2>/dev/null)
DOCKERFILE_FOUND=false
for dockerfile in $PLATFORM_DOCKERFILES; do
if git ls-files --error-unmatch "$dockerfile" &> /dev/null; then
echo -e "${GREEN} βœ“ $(basename "$dockerfile") (tracked)${NC}"
DOCKERFILE_FOUND=true
else
echo -e "${RED} ❌ File not tracked by git: $dockerfile${NC}"
ERRORS=$((ERRORS + 1))
fi
done
if [ "$DOCKERFILE_FOUND" = false ]; then
echo -e "${RED} ❌ No platform-specific Dockerfiles found${NC}"
ERRORS=$((ERRORS + 1))
fi
else
echo -e "${RED} ❌ Missing Dockerfile or Dockerfile.* files${NC}"
ERRORS=$((ERRORS + 1))
fi

# Check other required files
REQUIRED_FILES=("requirements.txt" "worker.py")
for file in "${REQUIRED_FILES[@]}"; do
FILE_PATH="$WORKER_DIR/$file"

Expand Down
88 changes: 87 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,93 @@ All notable changes to FuzzForge will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.7.0] - 2025-01-16
## [Unreleased]

### 🎯 Major Features

#### Android Static Analysis Workflow
- **Added comprehensive Android security testing workflow** (`android_static_analysis`):
- Jadx decompiler for APK β†’ Java source code decompilation
- OpenGrep/Semgrep static analysis with custom Android security rules
- MobSF integration for comprehensive mobile security scanning
- SARIF report generation with unified findings format
- Test results: Successfully decompiled 4,145 Java files, found 8 security vulnerabilities
- Full workflow completes in ~1.5 minutes

#### Platform-Aware Worker Architecture
- **ARM64 (Apple Silicon) support**:
- Automatic platform detection (ARM64 vs x86_64) in CLI using `platform.machine()`
- Worker metadata convention (`metadata.yaml`) for platform-specific capabilities
- Multi-Dockerfile support: `Dockerfile.amd64` (full toolchain) and `Dockerfile.arm64` (optimized)
- Conditional module imports for graceful degradation (MobSF skips on ARM64)
- Backend path resolution via `FUZZFORGE_HOST_ROOT` for CLI worker management
- **Worker selection logic**:
- CLI automatically selects appropriate Dockerfile based on detected platform
- Multi-strategy path resolution (API β†’ .fuzzforge marker β†’ environment variable)
- Platform-specific tool availability documented in metadata

#### Python SAST Workflow
- **Added Python Static Application Security Testing workflow** (`python_sast`):
- Bandit for Python security linting (SAST)
- MyPy for static type checking
- Safety for dependency vulnerability scanning
- Integrated SARIF reporter for unified findings format
- Auto-start Python worker on-demand

### ✨ Enhancements

#### CI/CD Improvements
- Added automated worker validation in CI pipeline
- Docker build checks for all workers before merge
- Worker file change detection for selective builds
- Optimized Docker layer caching for faster builds
- Dev branch testing workflow triggers

#### CLI Improvements
- Fixed live monitoring bug in `ff monitor live` command
- Enhanced `ff findings` command with better table formatting
- Improved `ff monitor` with clearer status displays
- Auto-start workers on-demand when workflows require them
- Better error messages with actionable manual start commands

#### Worker Management
- Standardized worker service names (`worker-python`, `worker-android`, etc.)
- Added missing `worker-secrets` to repository
- Improved worker naming consistency across codebase

#### LiteLLM Integration
- Centralized LLM provider management with proxy
- Governance and request/response routing
- OTEL collector integration for observability
- Environment-based configurable timeouts
- Optional `.env.litellm` configuration

### πŸ› Bug Fixes

- Fixed MobSF API key generation from secret file (SHA256 hash)
- Corrected Temporal activity names (decompile_with_jadx, scan_with_opengrep, scan_with_mobsf)
- Resolved linter errors across codebase
- Fixed unused import issues to pass CI checks
- Removed deprecated workflow parameters
- Docker Compose version compatibility fixes

### πŸ”§ Technical Changes

- Conditional import pattern for optional dependencies (MobSF on ARM64)
- Multi-platform Dockerfile architecture
- Worker metadata convention for capability declaration
- Improved CI worker build optimization
- Enhanced storage activity error handling

### πŸ“ Test Projects

- Added `test_projects/android_test/` with BeetleBug.apk and shopnest.apk
- Android workflow validation with real APK samples
- ARM64 platform testing and validation

---

## [0.7.0] - 2025-10-16

### 🎯 Major Features

Expand Down
47 changes: 47 additions & 0 deletions backend/src/api/system.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copyright (c) 2025 FuzzingLabs
#
# Licensed under the Business Source License 1.1 (BSL). See the LICENSE file
# at the root of this repository for details.
#
# After the Change Date (four years from publication), this version of the
# Licensed Work will be made available under the Apache License, Version 2.0.
# See the LICENSE-APACHE file or http://www.apache.org/licenses/LICENSE-2.0
#
# Additional attribution and requirements are provided in the NOTICE file.

"""
System information endpoints for FuzzForge API.

Provides system configuration and filesystem paths to CLI for worker management.
"""

import os
from typing import Dict

from fastapi import APIRouter

router = APIRouter(prefix="/system", tags=["system"])


@router.get("/info")
async def get_system_info() -> Dict[str, str]:
"""
Get system information including host filesystem paths.

This endpoint exposes paths needed by the CLI to manage workers via docker-compose.
The FUZZFORGE_HOST_ROOT environment variable is set by docker-compose and points
to the FuzzForge installation directory on the host machine.

Returns:
Dictionary containing:
- host_root: Absolute path to FuzzForge root on host
- docker_compose_path: Path to docker-compose.yml on host
- workers_dir: Path to workers directory on host
"""
host_root = os.getenv("FUZZFORGE_HOST_ROOT", "")

return {
"host_root": host_root,
"docker_compose_path": f"{host_root}/docker-compose.yml" if host_root else "",
"workers_dir": f"{host_root}/workers" if host_root else "",
}
3 changes: 2 additions & 1 deletion backend/src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

from src.temporal.manager import TemporalManager
from src.core.setup import setup_result_storage, validate_infrastructure
from src.api import workflows, runs, fuzzing
from src.api import workflows, runs, fuzzing, system

from fastmcp import FastMCP

Expand Down Expand Up @@ -76,6 +76,7 @@ def as_dict(self) -> Dict[str, Any]:
app.include_router(workflows.router)
app.include_router(runs.router)
app.include_router(fuzzing.router)
app.include_router(system.router)


def get_temporal_status() -> Dict[str, Any]:
Expand Down
31 changes: 31 additions & 0 deletions backend/toolbox/modules/android/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
Android Security Analysis Modules

Modules for Android application security testing:
- JadxDecompiler: APK decompilation using Jadx
- MobSFScanner: Mobile security analysis using MobSF
- OpenGrepAndroid: Static analysis using OpenGrep/Semgrep with Android-specific rules
"""

# Copyright (c) 2025 FuzzingLabs
#
# Licensed under the Business Source License 1.1 (BSL). See the LICENSE file
# at the root of this repository for details.
#
# After the Change Date (four years from publication), this version of the
# Licensed Work will be made available under the Apache License, Version 2.0.
# See the LICENSE-APACHE file or http://www.apache.org/licenses/LICENSE-2.0
#
# Additional attribution and requirements are provided in the NOTICE file.

from .jadx_decompiler import JadxDecompiler
from .opengrep_android import OpenGrepAndroid

# MobSF is optional (not available on ARM64 platform)
try:
from .mobsf_scanner import MobSFScanner
__all__ = ["JadxDecompiler", "MobSFScanner", "OpenGrepAndroid"]
except ImportError:
# MobSF dependencies not available (e.g., ARM64 platform)
MobSFScanner = None
__all__ = ["JadxDecompiler", "OpenGrepAndroid"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
rules:
- id: clipboard-sensitive-data
severity: WARNING
languages: [java]
message: "Sensitive data may be copied to the clipboard."
metadata:
authors:
- Guerric ELOI (FuzzingLabs)
category: security
area: clipboard
verification-level: [L1]
paths:
include:
- "**/*.java"
pattern: "$CLIPBOARD.setPrimaryClip($CLIP)"
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
rules:
- id: hardcoded-secrets
severity: WARNING
languages: [java]
message: "Possible hardcoded secret found in variable '$NAME'."
metadata:
authors:
- Guerric ELOI (FuzzingLabs)
owasp-mobile: M2
category: secrets
verification-level: [L1]
paths:
include:
- "**/*.java"
patterns:
- pattern-either:
- pattern: 'String $NAME = "$VAL";'
- pattern: 'final String $NAME = "$VAL";'
- pattern: 'private String $NAME = "$VAL";'
- pattern: 'public static String $NAME = "$VAL";'
- pattern: 'static final String $NAME = "$VAL";'
- pattern-regex: "$NAME =~ /(?i).*(api|key|token|secret|pass|auth|session|bearer|access|private).*/"

Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
rules:
- id: insecure-data-storage
severity: WARNING
languages: [java]
message: "Potential insecure data storage (external storage)."
metadata:
authors:
- Guerric ELOI (FuzzingLabs)
owasp-mobile: M2
category: security
area: storage
verification-level: [L1]
paths:
include:
- "**/*.java"
pattern-either:
- pattern: "$CTX.openFileOutput($NAME, $MODE)"
- pattern: "Environment.getExternalStorageDirectory()"
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
rules:
- id: insecure-deeplink
severity: WARNING
languages: [xml]
message: "Potential insecure deeplink found in intent-filter."
metadata:
authors:
- Guerric ELOI (FuzzingLabs)
category: component
area: manifest
verification-level: [L1]
paths:
include:
- "**/AndroidManifest.xml"
pattern: |
<intent-filter>
21 changes: 21 additions & 0 deletions backend/toolbox/modules/android/custom_rules/insecure-logging.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
rules:
- id: insecure-logging
severity: WARNING
languages: [java]
message: "Sensitive data logged via Android Log API."
metadata:
authors:
- Guerric ELOI (FuzzingLabs)
owasp-mobile: M2
category: logging
verification-level: [L1]
paths:
include:
- "**/*.java"
patterns:
- pattern-either:
- pattern: "Log.d($TAG, $MSG)"
- pattern: "Log.e($TAG, $MSG)"
- pattern: "System.out.println($MSG)"
- pattern-regex: "$MSG =~ /(?i).*(password|token|secret|api|auth|session).*/"

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
rules:
- id: intent-redirection
severity: WARNING
languages: [java]
message: "Potential intent redirection: using getIntent().getExtras() without validation."
metadata:
authors:
- Guerric ELOI (FuzzingLabs)
category: intent
area: intercomponent
verification-level: [L1]
paths:
include:
- "**/*.java"
pattern: "$ACT.getIntent().getExtras()"
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
rules:
- id: sensitive-data-in-shared-preferences
severity: WARNING
languages: [java]
message: "Sensitive data may be stored in SharedPreferences. Please review the key '$KEY'."
metadata:
authors:
- Guerric ELOI (FuzzingLabs)
owasp-mobile: M2
category: security
area: storage
verification-level: [L1]
paths:
include:
- "**/*.java"
patterns:
- pattern: "$EDITOR.putString($KEY, $VAL);"
- pattern-regex: "$KEY =~ /(?i).*(username|password|pass|token|auth_token|api_key|secret|sessionid|email).*/"
21 changes: 21 additions & 0 deletions backend/toolbox/modules/android/custom_rules/sqlite-injection.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
rules:
- id: sqlite-injection
severity: ERROR
languages: [java]
message: "Possible SQL injection: concatenated input in rawQuery or execSQL."
metadata:
authors:
- Guerric ELOI (FuzzingLabs)
owasp-mobile: M7
category: injection
area: database
verification-level: [L1]
paths:
include:
- "**/*.java"
patterns:
- pattern-either:
- pattern: "$DB.rawQuery($QUERY, ...)"
- pattern: "$DB.execSQL($QUERY)"
- pattern-regex: "$QUERY =~ /.*\".*\".*\\+.*/"

Loading