# Data Model Relationships in MobileAudit: Applications, Scans, Findings, and Metadata Explained

> Understand the MobileAudit data model relationships between Applications, Scans, Findings, and metadata. Learn how Django ORM structures this hierarchy for clear data organization.

- Repository: [Mónica Pastor/mobileaudit](https://github.com/mpast/mobileaudit)
- Tags: internals
- Published: 2026-03-07

---

**MobileAudit implements a hierarchical Django ORM structure where Applications own multiple Scans, which generate Findings linked to Patterns, CWEs, and Risks, while auxiliary metadata like Permissions and Components hang off Scans via ForeignKey relationships.**

The open-source MobileAudit project (`mpast/mobileaudit`) provides a Django-based framework for static analysis of Android APK files. Understanding the **data model relationship between Applications, Scans, Findings, and their associated metadata** is essential for developers integrating with the API or extending the platform's security reporting capabilities. The schema defined in [`app/models.py`](https://github.com/mpast/mobileaudit/blob/main/app/models.py) creates a strict parent-child hierarchy that mirrors real-world mobile security audit workflows.

## Core Entity Hierarchy

The system models mobile app security analysis as a three-tier hierarchy. At the root, an **Application** represents the mobile app being analyzed. Each **Scan** captures a specific analysis run against an APK binary. Every **Finding** represents an individual security issue discovered during that scan. This cascade ensures complete traceability from a vulnerability back to the specific application version that introduced it.

### Application to Scan Relationship

Each **Scan** belongs to exactly one **Application** via a ForeignKey, while an Application can host multiple Scans over time. In [`app/models.py`](https://github.com/mpast/mobileaudit/blob/main/app/models.py) (lines 59-87), the `Scan` model declares:

```python
class Scan(models.Model):
    app = models.ForeignKey(Application, on_delete=models.CASCADE)

```

This **one-to-many** relationship enables version tracking and regression testing. When an Application is deleted, Django’s cascade configuration automatically purges all associated Scans and their downstream data. The `Scan` model stores the APK file, version info, package name, hash digests, and auto-extracted manifest data.

### Scan to Finding Relationship

**Findings** represent individual security issues discovered during static analysis. Each Finding belongs to exactly one Scan, establishing a clear audit trail. The `Finding` model (lines 17-44 in [`app/models.py`](https://github.com/mpast/mobileaudit/blob/main/app/models.py)) implements:

```python
class Finding(models.Model):
    scan = models.ForeignKey(Scan, on_delete=models.CASCADE)

```

This ensures that deleting a Scan removes all associated Findings. The model captures precise location data (`path`, `line_number`), severity, status, and descriptive evidence (`snippet`, `description`, `mitigation`).

### Finding Classification Metadata

Findings link to three critical classification models that provide vulnerability context. The `Finding` model contains ForeignKey fields pointing to taxonomy definitions (also in [`app/models.py`](https://github.com/mpast/mobileaudit/blob/main/app/models.py)):

```python
class Finding(models.Model):
    type = models.ForeignKey(Pattern, on_delete=models.CASCADE, blank=True, null=True)
    cwe = models.ForeignKey(Cwe, on_delete=models.CASCADE)
    risk = models.ForeignKey(Risk, on_delete=models.CASCADE, null=True)

```

- **Pattern**: The detection rule (`type`) that triggered the match. Nullable to support manual findings.
- **Cwe**: The Common Weakness Enumeration identifier (e.g., CWE-79 for XSS).
- **Risk**: The severity rating normalized to MobileAudit’s risk framework.

## Auxiliary Metadata Models

Beyond the core triad, MobileAudit captures extensive APK metadata through specialized models. These maintain **ForeignKey** relationships to either **Scan** (for application-wide data) or **Finding** (for vulnerability-specific evidence).

### Scan-Level Attack Surface Data

Static analysis extracts application-wide metadata during the Scan process. The `Permission`, `Component`, `IntentFilter`, and `Certificate` models link to the parent Scan. For example, the `Permission` model (lines 64-72) declares:

```python
class Permission(models.Model):
    scan = models.ForeignKey(Scan, on_delete=models.CASCADE)
    permission = models.ForeignKey(PermissionType, on_delete=models.CASCADE)

```

These entities describe the attack surface: declared Android permissions, exported components, intent filters, and cryptographic certificates. Similar patterns exist for `Malware`, `Domain`, `VirusTotalScan`, and `Antivirus` models, all cascading from **Scan**.

### Finding-Level Evidence

Specific evidence supporting a Finding attaches directly to the Finding record. The `String`, `DatabaseInfo`, and `File` models capture extracted hardcoded strings, database references, and file paths relevant to specific vulnerabilities. These maintain ForeignKey relations to **Finding** rather than **Scan**, providing precise localization of security issues within the codebase.

## Enumerations and State Tracking

MobileAudit uses Django’s `TextChoices` to standardize vocabulary across the relationship graph. Defined in [`app/models.py`](https://github.com/mpast/mobileaudit/blob/main/app/models.py) (lines 30-47), these ensure data integrity:

```python
class Severity(models.TextChoices):
    CR = ('CR', 'Critical')
    HI = ('HI', 'High')
    ME = ('ME', 'Medium')
    LO = ('LO', 'Low')
    IN = ('IN', 'Informational')

class Status(models.TextChoices):
    VF = ('VF', 'Verified')
    FP = ('FP', 'False Positive')
    NV = ('NV', 'Not Verified')
    NA = ('NA', 'Not Applicable')
    UR = ('UR', 'Under Review')

```

The `Finding` model references these via `severity` and `status` fields, allowing workflow management across the vulnerability lifecycle.

## Practical Implementation Examples

### Creating the Parent-Child Chain

To programmatically populate the hierarchy according to the `mpast/mobileaudit` source code:

```python
from app.models import Application, Scan, Finding, Pattern, Cwe, Risk, Severity, Status

# Create Application

app = Application.objects.create(
    name="BankingApp",
    description="Mobile banking client v2.1.0",
    user=request.user
)

# Create Scan

scan = Scan.objects.create(
    app=app,
    name="v2.1.0 Production Analysis",
    apk=uploaded_apk_file,
    user=request.user
)

# Create Finding with full metadata

finding = Finding.objects.create(
    scan=scan,
    type=Pattern.objects.get(id=1),      # Detection rule

    cwe=Cwe.objects.get(cwe=89),         # SQL Injection

    risk=Risk.objects.get(id=2),          # High Risk classification

    severity=Severity.HI,
    status=Status.VF,
    name="SQL Injection in LoginActivity",
    path="com/bank/LoginActivity.java",
    line_number=142,
    line="rawQuery(sql, null);",
    snippet="... rawQuery(sql, null); ...",
    description="User input concatenated into SQL query without parameterization.",
    mitigation="Use parameterized queries or PreparedStatement.",
    user=request.user
)

```

### Traversing Relationships

Query across the hierarchy using Django’s double-underscore notation:

```python

# All findings for a specific application

findings = Finding.objects.filter(scan__app__name="BankingApp")

# All permissions declared in a specific scan

perms = Permission.objects.filter(scan__id=42).select_related('permission')

# Findings by CWE category across all scans of an app

xss_findings = Finding.objects.filter(
    cwe__cwe=79, 
    scan__app=app
).select_related('scan', 'cwe')

```

## API Serialization and Integrity

The [`app/serializers.py`](https://github.com/mpast/mobileaudit/blob/main/app/serializers.py) file exposes these relationships through Django REST Framework. **ModelSerializer** definitions enforce read-only constraints on immutable fields (`id`, timestamps, `user`) while allowing nested serialization of related objects. This protects the referential integrity of the Application → Scan → Finding chain during API operations, ensuring that clients cannot accidentally reparent findings to different scans or alter audit timestamps.

## Summary

- **Application** sits at the root, identified by name and user ownership, containing multiple **Scans** over time.
- **Scan** stores the APK binary, version metadata, and analysis status, cascading to **Findings** and scan-level metadata (Permissions, Components, Certificates, Malware scans).
- **Finding** captures individual vulnerabilities with precise file locations, linking to **Pattern** (detection rule), **Cwe** (taxonomy), and **Risk** (severity classification).
- **Auxiliary models** attach to either Scans (attack surface) or Findings (evidence) via ForeignKey relationships, creating a complete audit trail from uploaded APK to individual security issues.
- **Enumerations** (Severity, Status) provide standardized vocabulary across the entire relationship graph, supporting workflow states from "Not Verified" to "False Positive".

## Frequently Asked Questions

### How does MobileAudit handle deletion of an Application?

When an **Application** is deleted, Django’s `on_delete=models.CASCADE` configuration in the `Scan` model automatically removes all related **Scans**, which in turn delete their associated **Findings** and all metadata (Permissions, Components, Certificates). This ensures referential integrity but requires caution when removing production data, as the deletion is irreversible and removes the complete audit history.

### Can a Finding exist without being linked to a Pattern?

Yes. While the `type` field (ForeignKey to **Pattern**) is recommended for traceability, the model definition in [`app/models.py`](https://github.com/mpast/mobileaudit/blob/main/app/models.py) explicitly allows `blank=True, null=True`. This supports manual findings creation or imports from external scanners that lack corresponding MobileAudit detection rules, though such findings will not display the rule description or remediation guidance stored in the Pattern model.

### What is the difference between Severity and Risk in the data model?

**Severity** is a `TextChoices` enumeration (CR, HI, ME, LO, IN) used by the `Finding` model to indicate immediate technical impact based on the vulnerability’s inherent danger. **Risk** is a separate model (ForeignKey from Finding) that typically represents organizational or contextual risk ratings, allowing security teams to apply custom risk frameworks that factor in business context, asset exposure, and exploitability beyond the raw technical severity.

### How are extracted APK strings associated with Findings versus Scans?

The **String** model maintains a ForeignKey to **Finding** (not Scan), linking specific hardcoded strings, API keys, or secrets directly to the vulnerability that references them. This differs from **Permission** or **Component** models, which attach to **Scan** because they describe application-wide attack surface discovered during manifest analysis rather than specific vulnerability evidence found in code review.