
FaintMark
io.github.matchalatteguy由 GitHub 帳號 matchalatteguy 發布v0.1.0更新於 Oct 24, 2026
Invisible per-recipient image watermarks. Mark one copy per recipient, then identify a leaked copy.
概覽
本機 MCP 伺服器,為圖片嵌入每位收件人專屬的隱形浮水印,之後可辨識外流圖片來自哪一份副本。
- 可以做什麼
- 標記圖片:為每位收件人產生一份帶隨機 id 的浮水印副本(每次 1 至 100 人),支援 JPEG、PNG、WebP,HEIC 會轉為 JPEG
- 檢查圖片:解碼轉傳或外流圖片中的浮水印,回傳 matched、unregistered 或 not_detected,深度模式還會嘗試翻轉與小角度旋轉
- 列出副本:依時間新到舊列出已登記的副本及其 id、收件人與時間
- 比對圖片:回報符合副本的感知雜湊是否仍與送出的檔案一致
- 適用情境
- 適合把同一張照片寄給多人、之後想判斷是哪位收件人的副本被轉傳或外流的情況,包括經過通訊軟體壓縮與縮放之後。也方便在本機記錄誰收到哪份帶標記的檔案。
- 執行需求
- 以 stdio 本機程序執行,透過 uvx(或 pipx、uv tool install)啟動;需要 Python 3.11 以上版本,且用戶端 PATH 中能找到 uvx。首次 mark 或 check 會把 Adobe TrustMark Q 模型(65 MB)下載到 ~/.faintmark。處理 HEIC 需安裝 heic 附加元件。不需帳號、API 金鑰或上傳;可用 FAINTMARK_HOME 指定其他登記目錄。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 FaintMark,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
FaintMark
Invisible per-recipient image watermarks. Create one marked copy per recipient, then identify which copy a shared or leaked image is. Designed to tolerate the recompression and resizing chat apps apply; see the app tests and limits below. Runs locally, no account, no upload. Python CLI and MCP server.
Send each person only their own file; file names carry the id, not the name. A match identifies the label the copy was issued under, not who shared it. The mark is intended to be visually unobtrusive on photographs. JPEG, PNG and WebP keep their format; HEIC becomes JPEG.
Install
Python 3.11 or newer on macOS, Linux or Windows (Intel Macs: 3.11 to 3.13).
uv can install Python and run FaintMark. The
first mark or check downloads Adobe's TrustMark Q models (65 MB, SHA-256
verified) into ~/.faintmark. For HEIC input install faintmark[heic]:
uv tool install 'faintmark[heic]', or without a persistent install
uvx --from 'faintmark[heic]' faintmark mark photo.heic alice.
uv tool uninstall faintmark removes the command and leaves ~/.faintmark in
place.
Copies go into marked/ beside the image unless -o says otherwise. Quote
labels with spaces: faintmark mark photo.jpg 'Alice Smith'. One run marks 1
to 100 recipients. --json prints the result the matching MCP tool returns;
mark includes the source file name and output paths, check and list omit
file names and paths unless --files is set. check --deep also tries a flip
and small rotations, and when nothing is detected lists up to three
registered ids within 26 of 96 codeword bits of the raw decoder output as
candidates, with their bit distance. Those are uncalibrated and can be
coincidental or forged; they are never a match. With --json, errors print
{"error": "..."}. check exits 0 for matched, 1 for unregistered or
not_detected, 2 for an error.
mark accepts non-animated JPEG, PNG, WebP and HEIC up to 25 megapixels
without transparency (16-bit RGB is read at 8 bits; 16-bit grayscale and CMYK
are rejected) and needs about 1.5 GB of memory at that size. check reads the
first frame of anything Pillow opens, up to 100 megapixels.
Agents
Any other client that reads an mcpServers config (Claude Desktop, Cursor,
Windsurf): add this entry to the client's MCP configuration. The client must
find uvx on its PATH; set FAINTMARK_HOME in the server's environment to
use another registry.
Choose one route per client; plugins and extensions bundle the skill too. For
HEIC input start the server as uvx --from 'faintmark[heic]' faintmark mcp;
the bundled launchers use the base package.
- Add to Cursor
- Add to VS Code
- Claude Code plugin:
claude plugin marketplace add matchalatteguy/FaintMarkthenclaude plugin install faintmark@faintmark - Codex plugin:
codex plugin marketplace add matchalatteguy/FaintMarkthencodex plugin add faintmark@faintmark - Gemini extension:
gemini extensions install https://github.com/matchalatteguy/FaintMark - Skill for any agent with a shell:
npx skills add matchalatteguy/FaintMark
Give tools absolute paths. unregistered means an id was decoded but it is
not in this machine's registry; not_detected means no readable mark, which
says nothing about where the image came from. same_image compares
perceptual hashes with the issued copy: false means they differ beyond the
threshold, which cropping or an id copied into another picture can cause; the
comparison can also miss differences.
check_image and faintmark check --json return one of these: the three
plain statuses (a match with same_image: false means the picture differs
from the issued copy); with deep, a result recovered by a transform, or a
miss with candidates (suspects is empty when no registered id is within the
cutoff). The CLI prints errors as the last line; MCP tools raise them as tool
errors (isError): messages from the service match, argument validation
messages differ.
mark_image and faintmark mark --json return the first line; list_copies
and faintmark list --json return the second, newest first:
Tested on real apps
7 October 2026, FaintMark 0.1.0, three source photos (an iPhone scene, a CC0 portrait, a CC0 sunset). Each row reports the samples actually sent on that route at default photo quality. Screenshot rows are screenshots of the receiving phone, cropped to the photo before checking. These are individual round-trip observations, not recovery rates or guarantees for an app.
Every match also reported same_image: true. The originals, every received
file, the screenshots, the crops and a manifest of expected ids and results
(docs/evidence-2026-10-07.json) are in the
evidence release.
On a machine without this registry, the received files return unregistered
with the id from the manifest; the originals and the Tinder crop return
not_detected. X, Signal, iMessage and Instagram stories were not tested.
How it works
TrustMark Q (Adobe, MIT) embeds a 40-bit
id as an image-wide pattern designed to tolerate JPEG recompression, WebP
conversion and moderate resizing. This is forensic watermarking, not
steganography: anyone with TrustMark can read the id; only your registry maps
it to a name. FaintMark draws a random id per recipient, writes the copy in
the source format (JPEG at the source's own quantization tables, PNG, WebP;
HEIC becomes JPEG), decodes the saved copy to verify its id is recoverable,
and records id, recipient, file and a perceptual hash of the copy in a local
SQLite registry. On a registered match, check compares perceptual hashes
and reports same_image: false when their distance exceeds the threshold. A
JPEG whose source settings lose the mark is saved at quality 95 instead, and
says so in its warnings. Marking an image that already carries a mark
replaces it and says so. A preflight re-encodes each copy at JPEG quality 70,
at full size (skipped with a warning when a side exceeds 65,500 px, JPEG's
limit) and resized to 1280 px (half size when the image is smaller), and
warns when the id does not survive; send those copies as a file rather than a
photo.
ICC profiles are kept so Display P3 photos stay the same colour. EXIF and other metadata are not copied.
Compatibility with Adobe's implementation is checked in: tests/fixtures
holds BCH vectors and two images marked by upstream TrustMark 0.9.2; FaintMark
decodes their ids and reproduces their marked pixels within one value per RGB
channel. A chat-app style ladder in the real-model tests (resize to 1600, 1280
and 1024 px with JPEG 70 to 80, WebP 75, and a chained resize-plus-JPEG pass,
on delivered JPEG bytes) recovers the id on two 12-megapixel synthetic covers
and the 320 px fixture, except WebP 75 on the fixture.
Attacks we measured
Someone who has this repository and a copy can do the following; measured on three photos at 2000 px, two ids each, full tables in the attack report attached to the evidence release.
- Erase the mark invisibly. Re-running the public encoder with a random
payload removes it at 42 to 47 dB PSNR (6/6).
checkthen saysnot_detected, exactly as for an unmarked photo. - Overwrite it. Re-marking with another id wins every time (last writer wins, 41 to 44 dB). In these trials the decoder read the replacement and never the previous id.
- Combine copies. Averaging two or three recipients' copies defeats the
plain decoder every time. Against a registry of 100 ids, the closest
registered codeword belonged to a colluder in 264 of 264 trials (12 to 30
bits away; the closest innocent was 28 to 41 away), and with the 26-bit
cutoff
check --deeplists at least one colluder in 253 of 264 and never an innocent. For random decoder output each registered id has about a 4 in a million chance of falling within the cutoff, so coincidences grow with the registry. - Forge the picture check. A plain transplant of an id into another photo
fails
same_image(28 to 32 bits away). A tuned forgery that also nudges the luminance to flip the cheapest hash bits passes both checks at 27 dB PSNR, with a visible but ordinary-looking tone shift. - Ordinary edits. Blur, noise, JPEG down to quality 40, downscale to 100 px
and back, flips, brightness and contrast changes, a print-and-photograph
simulation: the mark survived all of them (6/6). Crops of 15% or more per
side and rotations above 4 degrees destroy it for the plain decoder;
--deeprecovers rotations up to about 10 degrees.
Limits
matchedmeans the decoded id is registered to that recipient. It does not prove who shared the image: copies can be forwarded.matchedis a registry lookup, not a signature. Anyone who knows an id can embed it in another image. The perceptual-hash comparison may flag a different picture, but cannot authenticate a copy or detect re-marking of the same picture. TrustMark also publishes a watermark remover; an informed recipient can strip the mark, and so can heavy editing.- Recipients who combine their copies defeat a plain
check;--deeplists candidates by codeword distance, which can be coincidental or forged and is never proof. - Images with an aspect ratio above 2:1 are marked only in their centre square; edits that move an image across that boundary can prevent decoding. Heavy downscaling and cropping destroy the mark.
- Results trust this machine's registry. Keep it private: anyone who can edit it can change attribution.
Registry
~/.faintmark/registry.sqlite3 maps ids to recipient names. Keep it private
and back it up; without it, a recoverable id is reported as unregistered.
FAINTMARK_HOME selects another directory.
MIT licensed. TrustMark and its models are Adobe's, also MIT. See CONTRIBUTING, SECURITY and releases.
來源:README.md,提交 26fb091
工具
0版本歷史
1- v0.1.0最新Oct 11, 2026
評分
已滿足適用檢查項的 40%
該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。
- 近 30 天內可連通25 分
請保持端點能夠回應 MCP 握手;SourceWeft 每 30 天探測一次。
- 已宣告認證方式10 分
請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。
- 已列出工具15 分
請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。
- 描述必需15 分
- 圖示10 分
- 文件15 分
- 授權條款10 分
請在儲存庫或註冊中心條目中宣告授權條款。