thiagowfx's avatar

Β¬ just serendipity πŸ€ (not just serendipity)

anki: auto-sync

β€’ 676 words β€’ 4 min

Previously.

Problem statement: enable auto-sync to AnkiWeb.

First layer: enable sync on open/close: Preferences > Syncing > Automatically sync on profile open/close

Second layer: for manual syncs, press y (source).

Third layer: install and enable an auto sync add-on such as this one:

This addon will automatically synchronize your collection with AnkiWeb at time intervals you can choose. It will never interrupt you while you are using Anki.

By default, the first sync will start 1 minute after your last activity. While Anki is sitting idle in the background, it will sync every 10 minutes. You can change those settings in the options dialog.

Someone forked that add-on to improve upon it, enabling background auto sync.

Should I trust a random add-on though? Even if the Anki community is generally decent and well-intentioned, these days we can’t trust anyone.

I asked Opus 4.6 (Claude) to analyze it for potential malware:

⏺ I've now read every single source file in the addon. Here's my analysis:

  ---
  Malware Analysis: Background Auto Sync (226796325)

  Addon: Background Auto Sync for Anki
  Author: athulkrishna2015
  Source: GitHub
  Fork of: Auto-Sync-Anki-Addon by Robin-Haupt-1
  License: GPL-3.0
  Files reviewed: All 8 Python source files + manifest.json

  Verdict: No malware detected. Appears safe.

  What the code actually does

  1. sync_routine.py (core logic) β€” Sets up timers to periodically call Anki's built-in
  mw.col.sync_collection(). Saves/restores window state so sync doesn't steal focus. All sync goes
  through Anki's native sync infrastructure (AnkiWeb auth, mw.pm.sync_auth()).
  2. utils.py β€” Single function: has_internet_connection() which opens a TCP socket to 8.8.8.8:53
  (Google DNS) to check connectivity. This is a standard, benign connectivity check. No data is
  sent.
  3. config.py β€” Reads/writes config to Anki's own config storage (mw.col.set_config/get_config). No
   external communication.
  4. main.py β€” Wires up hooks (profile_did_open, profile_will_close, sync_will_start,
  sync_did_finish) and adds a menu item. Standard Anki addon boilerplate.
  5. log_window.py β€” Simple in-memory log viewer (QDialog + QTextEdit). No file I/O, no network.
  6. options_dialog.py β€” Qt settings dialog with spinboxes/checkboxes. The support tab loads a Ko-fi
   widget (https://storage.ko-fi.com/cdn/widget/Widget_2.js) via an embedded AnkiWebView. Also
  displays crypto donation QR codes (BTC, ETH, UPI). These are static images bundled in the addon.
  7. constants.py β€” Config key names and defaults. Pure data.
  8. bump.py / make_ankiaddon.py β€” Developer build tooling only; not shipped in the .ankiaddon
  package.

  Specific things I checked for

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚    Concern     β”‚                                  Finding                                   β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚                β”‚ Only socket.create_connection("8.8.8.8", 53) for connectivity check +      β”‚
  β”‚ Network calls  β”‚ Anki's own sync API. No external HTTP requests, no telemetry, no phoning   β”‚
  β”‚                β”‚ home.                                                                      β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ File system    β”‚ Only os.path.dirname(__file__) and os.path.join to load bundled QR code    β”‚
  β”‚ access         β”‚ images. No reading/writing arbitrary files.                                β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ Code execution β”‚ None. No exec(), eval(), subprocess, os.system, importlib, or dynamic code β”‚
  β”‚  / eval        β”‚  loading.                                                                  β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ Data           β”‚ No access to deck content, card data, or personal information beyond what  β”‚
  β”‚ exfiltration   β”‚ Anki's sync already handles.                                               β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ Obfuscation    β”‚ None. Code is clean, readable, well-structured Python.                     β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚ Suspicious     β”‚ Only standard library (socket, datetime, os, json) and Anki's own APIs     β”‚
  β”‚ imports        β”‚ (aqt, aqt.qt).                                                             β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
  β”‚                β”‚ Loads JavaScript from storage.ko-fi.com in the support tab β€” this is a     β”‚
  β”‚ Ko-fi widget   β”‚ standard donation button, not a concern, and only loads when you open the  β”‚
  β”‚                β”‚ options dialog's "Support" tab.                                            β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

  Minor notes (not security concerns)

  - The author has 18 other shared items on AnkiWeb, suggesting an active community member rather
  than a throwaway account.
  - The addon is relatively new (updated 2026-03-27) with 0 ratings so far, so there's limited
  community vetting.
  - The code is a clean, well-documented fork of the established Robin-Haupt Auto-Sync addon.

  Bottom line: The code does exactly what it claims β€” periodic background sync using Anki's native
  sync mechanism. No signs of malicious intent, data exfiltration, backdoors, or obfuscated code.

✻ Cooked for 2m 36s

I am not installing it though, I am happy with the second layer for now.