Skip to content

Security: overwrite00/MetaLens

SECURITY.md

πŸ”’ Security Policy

Security Model

MetaLens is designed with security-first principles:

  • Offline by default β€” all metadata reading and writing happens on your machine. The only network access is the update check (see below), which runs only when you click Check for updates or have enabled the opt-in startup check
  • Localhost-only sidecar β€” the Python (FastAPI) backend binds to 127.0.0.1 only, on a dynamically chosen port, never 0.0.0.0
  • Electron hardening β€” nodeIntegration: false, contextIsolation: true, sandbox: true; IPC accepts only the application's main frame. Navigation and popups are blocked and a Content Security Policy limits renderer resources
  • Authenticated sidecar β€” a fresh random token is generated for each session, passed to Python through the environment and sent in an Authorization header. Requests without valid credentials are rejected; localhost binding alone is not treated as authentication
  • Atomic, verified writes β€” every save (edits and deletions together) is prepared on a copy in a private temporary directory beside the target, read back and checked against the request, and checked for concurrent modification before the copy replaces the original (ReplaceFileW on Windows, preserving the security descriptor, alternate data streams and file attributes such as hidden; os.replace elsewhere). Any failure leaves the original content intact. The replacement is a new file, so hard links to the original are detached. A read-only file is refused (HTTP 403), not modified
  • Path validation β€” a dedicated core.path_security module normalizes every path (resolves ~, .. and symbolic links) and checks that it is an existing, readable regular file or directory before any filesystem access, across all API routes. This is normalization, not a sandbox: an authenticated caller may name any file the user account can access, which is why every request must carry the session token
  • Hardened update check β€” requests are made by the Electron main process, never by the renderer (whose CSP still only allows the local sidecar). It queries the GitHub Releases API of overwrite00/MetaLens only, and the renderer cannot supply URLs. Release and asset URLs must point to that repository, and the installer is downloaded only when you click Download & install (Windows installed builds), checked against its size and the SHA-256 digest published by GitHub, and discarded on any mismatch. Release notes are shown as plain text
  • No internal details in errors β€” API error bodies carry fixed, structured messages only; the text of internal exceptions stays in the local log
  • Clean shutdown β€” the Exit button (and closing the app) stops the sidecar's whole process tree, cancels any update download and releases the port and memory
  • Transparent code β€” all handler and analysis logic is open-source and auditable

πŸ›‘οΈ Privacy Principles

What We Don't Do

  • ❌ No user accounts or authentication
  • ❌ No telemetry or usage tracking
  • ❌ No data collection or analytics
  • ❌ No cloud processing or storage
  • ❌ No automatic phone-home: the update check is manual, or opt-in (off by default) at startup

Data Control

  • βœ… Your files and their metadata never leave your machine
  • βœ… Nothing is written anywhere except the file you explicitly edit (and its short-lived private temporary copy beside it, removed after the save)
  • βœ… The undo stack and the sidecar's Undo journal (original values of the last 50 saves, at most 64 MiB) live in memory only β€” they are cleared when you close the app, never written to disk
  • βœ… Full source code transparency

πŸ” Technical Security

Metadata Handlers

  • Uses established libraries per format: Pillow (image properties), piexif tag tables plus MetaLens's own structure-preserving EXIF/XMP/IPTC codecs and JPEG segment writer (images), mutagen (audio/MP4), pypdf (PDF), Python's zipfile/xml.etree (Office Open XML packages), olefile (legacy Office), hachoir (read-only fallback for other formats). XMP packets (JPEG, PDF) containing DOCTYPE or entity declarations are refused
  • Field capabilities are enforced by the API; client-provided editability flags cannot override them. Writable: EXIF/XMP/IPTC of JPEG, PNG, WebP, TIFF, TIFF-based RAW and HEIC/AVIF (what a format cannot hold is refused), audio tags (except AAC), MP4/MOV and MKV/WebM metadata, PDF document info and XMP, Office and OpenDocument/EPUB properties, fs:mtime and Linux user. extended attributes; legacy Office (DOC/XLS/PPT) allows removing properties only. Read-only: GIF/BMP, Canon CR3 and Fujifilm RAF, AAC, AVI and other video read through hachoir, encrypted or digitally signed PDFs, digitally signed Office packages (so a signature is never silently invalidated), everything read through hachoir. Every write is checked so that the picture, audio or video data comes out identical
  • Every value is validated before the file is touched; library errors caused by a value are reported as validation errors (HTTP 422), never as crashes
  • Filesystem access always goes through validate_file_path/validate_directory_path before touching disk

IPC Boundary

  • The Electron renderer talks to the OS only through the preload.js contextBridge surface (dialogs, path helpers, drive listing) β€” no direct filesystem or process access
  • The renderer talks to the Python sidecar only over HTTP to 127.0.0.1:{dynamic_port} (never a hardcoded port), with the port and session token obtained from the main process through the get-sidecar-connection IPC channel; the Content Security Policy only allows connections to 127.0.0.1
  • The sidecar rejects foreign browser origins and requires its session token, including for /health. The normal development path is Vite plus Electron; opening the frontend in a standalone browser does not grant sidecar access

⚠️ Known Limitations

What MetaLens Does NOT Do

  • Code-signed installers β€” releases are currently unsigned (no purchased certificate). Windows SmartScreen will warn on first run; this is expected, not a compromise indicator. See Installation Guide for how to proceed safely
  • Malware/content scanning β€” MetaLens edits metadata; it does not scan file contents for malicious payloads
  • Encryption β€” files and their metadata are stored and edited in plain form on disk, as with any local file manager
  • Guarantee against all data loss β€” while writes are atomic, always keep backups of files you can't afford to lose

Defense-in-Depth Recommended

For files handled outside MetaLens, also rely on your OS's built-in protections (Windows Defender / your Linux distro's package signing) and keep regular backups.


πŸ“’ Responsible Disclosure

If you discover a security vulnerability in MetaLens:

Reporting Process

  1. Do not open a public GitHub issue β€” this exposes the vulnerability before a fix ships
  2. Use GitHub Security Advisory:

Timeline

  • 48 hours: acknowledgment of your report
  • 2 weeks (critical): target fix timeline for critical vulnerabilities
  • 30 days (high): target fix timeline for high-severity vulnerabilities
  • Coordinated disclosure: we'll work with you on a disclosure timeline

Recognition

We appreciate responsible disclosure and will credit you in the security advisory (unless you prefer anonymity).


πŸ”„ Security Updates


πŸ“š Additional Resources


Last updated: 2026-11-04 ← Contributing | Back to README β†’

There aren't any published security advisories