Skip to content

samb4secure/mavlink-security-gateway

Repository files navigation

MAVLink Security Gateway for GCS Protection

Built as a hobby project to proof-of-concept defensive cyber capabilities for drone ground control stations. Mavlink security gateway is a configurable message filter for defending drones against malicious, spoofed, or unauthorised MAVLink traffic. Includes a little vibe coded, web-based schema builder UI for creating security policies without coding. The idea is to expose only the commands or telemetry required for a mission and policy enforce this at the network layer, abstracting mission/strategic policy from the operator. See the blogpost at samblack.co.

Overview

This filter acts as a security gateway between MAVLink sources (radio links, network bridges, companion computers) and your GCS or autopilot. It inspects every MAVLink message and applies configurable allow/block rules based on:

  • Message type and ID
  • Source and target system/component IDs
  • Command codes (for COMMAND_LONG, COMMAND_INT, MISSION_ITEM)
  • Parameter names (for PARAM_SET, PARAM_VALUE)
  • Arbitrary payload field values with comparison operators
  • Sequence numbers for replay/reorder detection

Threat Model

Threats Addressed

Threat Description Mitigation
Command Injection Attacker sends unauthorised commands (arm, disarm, mode change, RTL override) Block unauthorised command IDs and sources
Parameter Tampering Malicious PARAM_SET to disable failsafes, geofences, or alter flight characteristics Allowlist specific safe parameters
Data Exfiltration Non-mavlink traffic using the uplink as a bearer of opportunity Application layer attacks against the GCS/from the GCS to the battlespace management system Comprehensive security filtering on trusted network
Replay Attacks Re-transmitting captured legitimate commands Sequence tracking with replay detection
Privilege Escalation GCS operator exceeding authorised actions Role-based schema selection

Trust Boundaries

Deployment pattern one, defend the GCS from remote attack.

deployment1

Deployment pattern two, defend the battlespace management program from remote attack, release of sensitive information.

deployment2

Installation

pip install pymavlink

For YAML schema support (optional):

pip install pyyaml

Copy the filter module to your project:

cp mavlink-filter.py /your/project/

Quick Start

Using the Schema Builder UI

  1. Start a web server:

    python3 -m http.server 8000
  2. Open http://localhost:8000/schema-ui.html in your browser

  3. Select a template or build a custom schema

  4. Configure rules using the guided interface

  5. Download your schema as JSON or YAML

  6. Use with the gateway or in your code

Using the Command-Line Gateway

# Filter UDP traffic
python3 mavlink-gateway.py \
  --schema my-schema.json \
  --input udp:127.0.0.1:14550 \
  --output udp:127.0.0.1:14551

# Filter serial traffic
python3 mavlink-gateway.py \
  --schema my-schema.json \
  --input serial:/dev/ttyUSB0:57600 \
  --output udp:127.0.0.1:14550

Using in Python Code

from mavlink_filter import MavlinkFilter

# Load from file
filter = MavlinkFilter("my-schema.json")

# Or use dict directly
schema = {"mode": "blocklist", "allow": [...], "block": [...]}
filter = MavlinkFilter(schema)

# Check if message is allowed
if filter.allowed(message):
    # Process message
    pass

Schema Builder UI

A user-friendly web interface for creating MAVLink security filter schemas without writing code.

Features

  • Visual Interface - No coding required
  • 295 MAVLink Message Types - Complete catalog with search
  • Templates - Pre-configured security policies
  • Guided Configuration - Step-by-step rule creation with explanations
  • Command Catalog - Browse commands with descriptions and risk levels
  • Context-Aware Options - Only shows relevant configuration options
  • Real-time Preview - See schema as you build
  • Export - Download JSON or YAML schemas
  • Import - Load existing schemas for editing

Creating a Schema

  1. Select a Template (optional)

    • Permissive: Blocklist mode, blocks only dangerous commands
    • Secure Gateway: Allowlist mode with sequence tracking
    • Read-Only Observer: Telemetry only, no commands or writes
    • Emergency Override: Always allows safety-critical commands
    • Custom: Start from scratch
  2. Configure Settings

    • Filter Mode:
      • Blocklist (allow by default) - More permissive, easier to configure
      • Allowlist (block by default) - More secure, requires explicit allow rules
    • Default Behaviour: What happens to messages that don't match any rules
    • Sequence Tracking: Enable replay attack detection
  3. Add Rules

    • Click "+ Add Allow Rule" or "+ Add Block Rule"
    • The editor opens immediately
    • Step 1: Select message types from the searchable list
    • Step 2: Use quick presets (optional) for common patterns
    • Advanced Options: Toggle to show commands, parameters, filtering, etc.
  4. Configure Advanced Options (when needed)

    • Commands: Select from catalog or enter command IDs
    • Parameter Names: Filter by parameter with wildcard support
    • Source/Target Filtering: Restrict by system/component IDs
    • Field Conditions: Match based on message field values
    • Sequence Tracking: Detect replays and out-of-order messages
  5. Export Schema

    • Click "Download JSON" or "Download YAML"
    • Use with mavlink-gateway.py or in your code

Understanding Commands vs Messages

Message Types (like HEARTBEAT, COMMAND_LONG, PARAM_SET) are the structure/format of messages. They are defined in the MAVLink message definitions.

Command Enum Values (like 400, 512, 176) are MAV_CMD constants that specify what action a command performs. These appear inside certain message types like COMMAND_LONG.

For example:

  • COMMAND_LONG is a message type
  • 400 (ARM_DISARM) is a command value that can appear in a COMMAND_LONG message

When you configure a rule with {"names": ["COMMAND_LONG"], "commands": [400]}, you're saying: "Match COMMAND_LONG messages where the command field equals 400 (ARM_DISARM)".

Common Command IDs

ID Name Risk Description
400 ARM_DISARM Critical Arm or disarm the vehicle (motors on/off)
176 DO_SET_MODE High Change flight mode
20 NAV_RETURN_TO_LAUNCH Medium Return to launch position
21 NAV_LAND Medium Land at current location
22 NAV_TAKEOFF High Take off to specified altitude
92 NAV_GUIDED_ENABLE High Enable external control
183 DO_SET_SERVO High Direct actuator control
184 DO_REPEAT_SERVO High Direct actuator control (repeat)
185 DO_FLIGHTTERMINATION Critical Kill switch - immediately stop vehicle
252 PREFLIGHT_REBOOT Critical Reboot autopilot
511 SET_MESSAGE_INTERVAL Low Set message stream rate
512 REQUEST_MESSAGE Low Request a specific message stream
520 REQUEST_AUTOPILOT_CAPABILITIES Low Request autopilot capabilities

Command-Line Gateway

The mavlink-gateway.py tool provides a standalone command-line interface for filtering MAVLink traffic using schema files.

Usage

python3 mavlink-gateway.py \
  --schema <schema-file> \
  --input <input-spec> \
  --output <output-spec> \
  [--audit] \
  [--stats]

Arguments

  • --schema: Path to schema file (JSON or YAML)
  • --input: Input specification in format type:address:port or type:device:baud
    • udp: udp:127.0.0.1:14550
    • serial: serial:/dev/ttyUSB0:57600
  • --output: Output specification (same format as input)
  • --audit: Enable audit logging (prints all decisions)
  • --stats: Print statistics periodically

Examples

# UDP proxy with filtering
python3 mavlink-gateway.py \
  --schema schemas/01-secure-command-gateway.json \
  --input udp:127.0.0.1:14550 \
  --output udp:127.0.0.1:14551

# Serial to UDP gateway
python3 mavlink-gateway.py \
  --schema schemas/02-parameter-protection.json \
  --input serial:/dev/ttyUSB0:57600 \
  --output udp:127.0.0.1:14550 \
  --audit

# Bidirectional filtering (requires two instances)
# Terminal 1: Vehicle → GCS
python3 mavlink-gateway.py \
  --schema telemetry-schema.json \
  --input serial:/dev/ttyUSB0:57600 \
  --output udp:127.0.0.1:14550

# Terminal 2: GCS → Vehicle
python3 mavlink-gateway.py \
  --schema command-schema.json \
  --input udp:127.0.0.1:14551 \
  --output serial:/dev/ttyUSB0:57600

Schema Reference

Top-Level Structure

{
    "mode": "allowlist" | "blocklist",
    "default": "allow" | "block",
    "allow": [rule, ...],
    "block": [rule, ...],
    "seq_tracking": {
        "enabled": true,
        "max_reorder": 10,
        "update_on": "allowed"
    }
}

Filter Modes

Allowlist Mode (deny by default):

  • Messages that don't match any rules: BLOCKED
  • If both allow and block rules match: BLOCK wins
  • Security model: Deny everything except what's explicitly allowed
  • More secure but requires explicit allow rules for all needed messages

Blocklist Mode (allow by default):

  • Messages that don't match any rules: Use default (usually ALLOW)
  • If both allow and block rules match: ALLOW wins (allow overrides block)
  • Security model: Allow everything except what's explicitly blocked
  • More permissive but easier to configure

Rule Structure

{
    "names": ["HEARTBEAT", {"glob": "GPS_*"}, {"regex": "^COMMAND_"}],
    "msgids": [0, 76, 77],
    
    "src_sysids": [255],
    "src_compids": [190],
    
    "target_sysids": [1],
    "target_compids": [1],
    
    "commands": [400, 176, 21],
    
    "param_ids": ["SYSID_THISMAV", {"glob": "FENCE_*"}],
    
    "fields": {
        "param1": {"gt": 0, "lt": 100},
        "confirmation": {"ne": 21}
    },
    
    "seq": {
        "replay": true,
        "out_of_order": true,
        "max_gap": 50
    }
}

Field Predicates

Predicate Example Description
eq {"eq": 5} Equals
ne {"ne": 0} Not equals
gt, gte {"gt": 100} Greater than (or equal)
lt, lte {"lt": 50} Less than (or equal)
in {"in": [1,2,3]} Value in set
nin {"nin": [0]} Value not in set
between {"between": [-10, 10]} Inclusive range
abs_gt {"abs_gt": 1000} Absolute value greater than

Boolean Logic for Fields

{
    "fields": {
        "any": [
            {"field": "param1", "pred": {"gt": 100}},
            {"field": "param2", "pred": {"gt": 100}}
        ]
    }
}
{
    "fields": {
        "all": [
            {"field": "param1", "pred": {"gt": 100}},
            {"field": "confirmation", "pred": {"ne": 21}}
        ]
    }
}
{
    "fields": {
        "not": {"field": "confirmation", "pred": {"eq": 21}}
    }
}

Sequence Tracking

Sequence tracking detects replay attacks by monitoring message sequence numbers:

  • replay: Block messages with the same sequence number we've seen before
  • out_of_order: Block messages that arrive out of order (beyond reorder window)
  • max_gap: Block if sequence number jumps more than N steps

The update_on setting controls when sequence state is updated:

  • "seen": Update on all messages (less secure)
  • "allowed": Update only on allowed messages (recommended for security)
  • "matched": Update only on messages that match rules

Example Schemas

The schemas/ directory contains seven pre-configured example schemas:

  1. 01-secure-command-gateway.json - High-security allowlist with comprehensive telemetry
  2. 02-parameter-protection.json - Parameter tampering protection
  3. 03-mission-protection.json - Mission upload protection
  4. 04-anti-replay.json - Replay attack mitigation
  5. 05-emergency-override.json - Emergency safety commands
  6. 06-read-only-observer.json - Monitoring station configuration
  7. 07-permissive-blocklist.json - Permissive policy for development

See the schemas/ directory for detailed descriptions of each schema.


Files

  • mavlink-filter.py - Core filtering library
  • mavlink-gateway.py - Command-line gateway tool
  • schema-ui.html - Web-based schema builder
  • mavlink_message_catalog.json - Complete message type catalog
  • schemas/ - Example schema files
  • example-schema.json - Basic example schema
  • example-schema.yaml - Basic example schema (YAML)

Testing

The project includes some test suites to validate filter functionality, more need to be built to encompas all of the current catalogue for now we have:

test_security_configs.py - Unit tests using mock MAVLink messages

  • Tests all 7 security configurations
  • 42+ tests covering command blocking, parameter protection, sequence tracking, etc.
  • Run: python3 test_security_configs.py

test_pymavlink_integration.py - Integration tests using real pymavlink messages

  • Uses actual MAVLink message objects from pymavlink
  • Validates filter works with real MAVLink protocol structures
  • Tests byte stream filtering with MavlinkStreamFilter
  • Run: python3 test_pymavlink_integration.py

test_schema_files.py - Tests schema file loading and gateway functionality

  • Validates JSON and YAML schema loading
  • Tests command-line gateway with various configurations
  • Run: python3 test_schema_files.py

Test Coverage

  • Message types: HEARTBEAT, COMMAND_LONG, PARAM_SET, MISSION_ITEM, GPS_RAW_INT, and more
  • Security scenarios: Command blocking, parameter protection, source/target filtering, sequence tracking, field predicates
  • Modes: Allowlist and blocklist modes
  • Edge cases: First messages, replay detection, out-of-order handling
  • No significant load, throughput or ramp up testing performed

License

MIT, see LICENSE. Use at your own risk. This software is designed as a security tool but does not guarantee any protection against any attack vectors. Always implement defence in depth.


About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published