Skip to content

Security Issue: Unvalidated URL in SatYAML telemetry_servers permits SSRF via loaded YAML (F104) #827

Description

@Marnick39

Affected: gr-satellites >= 3.6.0, <= 5.9.0 (SIDS support added in commit 6e242066, 2020-11-18, first released in v3.6.0)
Severity: Medium (CVSS 3.1: 4.3, AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:N/A:N)

Summary

The telemetry_servers: field in a SatYAML file accepts a
SIDS <url> entry. When present, every received frame for that
satellite is POSTed to the operator-specified URL via
urllib.request.urlopen at python/submit.py:124. The URL is not
validated beyond server.startswith('SIDS ') — no scheme allow-list,
no host allow-list, no timeout.

An operator who loads a malicious .yml from a mailing list, community
wiki, or "support for satellite X" pull request silently POSTs their
telemetry data (callsign, GPS, RF hex bytes) to whatever URL the YAML
author chose.

CPython's urllib handler set includes file://, http://,
https://, ftp://, and data:, so the attacker can read local
files (response body is discarded but the read happens), poke at
internal RFC1918 addresses, and probe localhost services.

Why this isn't an operator-misconfiguration bug

gr-satellites' own documentation doesn't warn operators to load only
trusted YAML. A grep of docs/source/ for trust, untrust,
malicious, attacker, and verify in any SatYAML context returns
zero matches. The command_line.rst:77-78 paragraph actively
encourages user-created or user-modified YAML loading without any
caveat:

"Specifying the path of a SatYAML file is useful if the user has
modified some of the files bundled with gr-satellites or has created
their own ones."

Operators reasonably treat shared YAML as benign.

What this is not

Read-only SSRF; not escalatable to RCE in v5.9.0. file:// + data=
is silently ignored by CPython's FileHandler.file_open(); gopher://,
dict://, ldap://, jar://, sftp://, tftp:// aren't in CPython's
default handler set; HTTP redirect to file:// is blocked since
CVE-2019-9948 (Python ≥ 3.7.6).

Reproduction

disclosure/bundle-2026-05-24/v2/pocs/F104-satyaml-ssrf/:

  • poc_F104_satyaml_ssrf.py — standalone, no GR; reimplements the
    loader + urlopen path and drives it against an in-process mock
    exfil listener
  • malicious_satellite.yml + mock_listener.py — for verifying
    against a real gr_satellites install

Fix

  1. Add a scheme allow-list (http/https only) in satyaml.py at YAML
    load time
  2. Add the same allow-list as defence-in-depth in submit.py before
    urlopen()
  3. Add a security warning to docs/source/satyaml.rst telling
    operators to load YAML only from trusted sources

Long-form advisory

https://github.com/Marnick39/gr-satellites/blob/audit-advisories/disclosure/bundle-2026-05-24/v2/ADVISORY-08-F104-satyaml-ssrf.md

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions